From c30dbb1e3f85ada71eaa9b41a734b503acd8441b Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 15 Jun 2016 12:04:28 +0200
Subject: ssh: test cases for no repetition of bad passwords
---
lib/ssh/test/ssh_basic_SUITE.erl | 84 ++++++++++++++++++++++++++++++++++++++--
1 file changed, 81 insertions(+), 3 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index 094d28e879..96d424dc98 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -49,7 +49,12 @@
inet6_option/1,
inet_option/1,
internal_error/1,
- known_hosts/1,
+ known_hosts/1,
+ login_bad_pwd_no_retry1/1,
+ login_bad_pwd_no_retry2/1,
+ login_bad_pwd_no_retry3/1,
+ login_bad_pwd_no_retry4/1,
+ login_bad_pwd_no_retry5/1,
misc_ssh_options/1,
openssh_zlib_basic_test/1,
packet_size_zero/1,
@@ -99,7 +104,8 @@ all() ->
daemon_opt_fd,
multi_daemon_opt_fd,
packet_size_zero,
- ssh_info_print
+ ssh_info_print,
+ {group, login_bad_pwd_no_retry}
].
groups() ->
@@ -115,7 +121,13 @@ groups() ->
{dsa_pass_key, [], [pass_phrase]},
{rsa_pass_key, [], [pass_phrase]},
{key_cb, [], [key_callback, key_callback_options]},
- {internal_error, [], [internal_error]}
+ {internal_error, [], [internal_error]},
+ {login_bad_pwd_no_retry, [], [login_bad_pwd_no_retry1,
+ login_bad_pwd_no_retry2,
+ login_bad_pwd_no_retry3,
+ login_bad_pwd_no_retry4,
+ login_bad_pwd_no_retry5
+ ]}
].
@@ -1088,6 +1100,72 @@ ssh_info_print(Config) ->
end.
+%%--------------------------------------------------------------------
+%% Check that a basd pwd is not tried more times. Could cause lock-out
+%% on server
+
+login_bad_pwd_no_retry1(Config) ->
+ login_bad_pwd_no_retry(Config, "keyboard-interactive,password").
+
+login_bad_pwd_no_retry2(Config) ->
+ login_bad_pwd_no_retry(Config, "password,keyboard-interactive").
+
+login_bad_pwd_no_retry3(Config) ->
+ login_bad_pwd_no_retry(Config, "password,publickey,keyboard-interactive").
+
+login_bad_pwd_no_retry4(Config) ->
+ login_bad_pwd_no_retry(Config, "password,other,keyboard-interactive").
+
+login_bad_pwd_no_retry5(Config) ->
+ login_bad_pwd_no_retry(Config, "password,other,keyboard-interactive,password,password").
+
+
+
+
+
+login_bad_pwd_no_retry(Config, AuthMethods) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth
+ file:make_dir(UserDir),
+ SysDir = proplists:get_value(data_dir, Config),
+
+ Parent = self(),
+ PwdFun = fun(_, _, _, undefined) -> {false, 1};
+ (_, _, _, _) -> Parent ! retry_bad_pwd,
+ false
+ end,
+
+ {DaemonRef, _Host, Port} =
+ ssh_test_lib:daemon([{system_dir, SysDir},
+ {user_dir, UserDir},
+ {auth_methods, AuthMethods},
+ {user_passwords, [{"foo","somepwd"}]},
+ {pwdfun, PwdFun}
+ ]),
+
+ ConnRes = ssh:connect("localhost", Port,
+ [{silently_accept_hosts, true},
+ {user, "foo"},
+ {password, "badpwd"},
+ {user_dir, UserDir},
+ {user_interaction, false}]),
+
+ receive
+ retry_bad_pwd ->
+ ssh:stop_daemon(DaemonRef),
+ {fail, "Retry bad password"}
+ after 0 ->
+ case ConnRes of
+ {error,"Unable to connect using the available authentication methods"} ->
+ ssh:stop_daemon(DaemonRef),
+ ok;
+ {ok,Conn} ->
+ ssh:close(Conn),
+ ssh:stop_daemon(DaemonRef),
+ {fail, "Connect erroneosly succeded"}
+ end
+ end.
+
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
--
cgit v1.2.3
From 2e3d97a27bbfa86260dd248b793a1d358a836a1b Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 15 Jun 2016 13:03:40 +0200
Subject: ssh: Make client send a faulty pwd only once, ssh_auth part
Conflicts:
lib/ssh/src/ssh_connection_handler.erl
---
lib/ssh/src/ssh_auth.erl | 214 ++++++++++++++++++++++++++++-------------------
1 file changed, 126 insertions(+), 88 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl
index b71bed033a..86a91c6d22 100644
--- a/lib/ssh/src/ssh_auth.erl
+++ b/lib/ssh/src/ssh_auth.erl
@@ -31,12 +31,107 @@
-export([publickey_msg/1, password_msg/1, keyboard_interactive_msg/1,
service_request_msg/1, init_userauth_request_msg/1,
userauth_request_msg/1, handle_userauth_request/3,
- handle_userauth_info_request/3, handle_userauth_info_response/2
+ handle_userauth_info_request/2, handle_userauth_info_response/2
]).
%%--------------------------------------------------------------------
%%% Internal application API
%%--------------------------------------------------------------------
+%%%----------------------------------------------------------------
+userauth_request_msg(#ssh{userauth_methods = ServerMethods,
+ userauth_supported_methods = UserPrefMethods, % Note: this is not documented as supported for clients
+ userauth_preference = ClientMethods0
+ } = Ssh0) ->
+ case sort_select_mthds(ClientMethods0, UserPrefMethods, ServerMethods) of
+ [] ->
+ Msg = #ssh_msg_disconnect{code = ?SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE,
+ description = "Unable to connect using the available authentication methods",
+ language = "en"},
+ {disconnect, Msg, ssh_transport:ssh_packet(Msg, Ssh0)};
+
+ [{Pref,Module,Function,Args} | Prefs] ->
+ Ssh = case Pref of
+ "keyboard-interactive" -> Ssh0;
+ _ -> Ssh0#ssh{userauth_preference = Prefs}
+ end,
+ case Module:Function(Args ++ [Ssh]) of
+ {not_ok, Ssh1} ->
+ userauth_request_msg(Ssh1#ssh{userauth_preference = Prefs});
+ Result ->
+ {Pref,Result}
+ end
+ end.
+
+
+
+sort_select_mthds(Clients, undefined, Servers) ->
+ %% User has not expressed an opinion via option "auth_methods", use the server's prefs
+ sort_select_mthds(Clients, Servers, Servers);
+
+sort_select_mthds(Clients, Users0, Servers0) ->
+ %% The User has an opinion, use the intersection of that and the Servers whishes but
+ %% in the Users order
+ Servers = unique(Servers0),
+ Users = unique(Users0),
+ [C || Key <- Users,
+ lists:member(Key, Servers),
+ C <- Clients,
+ element(1,C) == Key].
+
+unique(L) ->
+ lists:reverse(
+ lists:foldl(fun(E,Acc) ->
+ case lists:member(E,Acc) of
+ true -> Acc;
+ false -> [E|Acc]
+ end
+ end, [], L)).
+
+
+%%%---- userauth_request_msg "callbacks"
+password_msg([#ssh{opts = Opts, io_cb = IoCb,
+ user = User, service = Service} = Ssh0]) ->
+ {Password,Ssh} =
+ case proplists:get_value(password, Opts) of
+ undefined when IoCb == ssh_no_io ->
+ {not_ok, Ssh0};
+ undefined ->
+ {IoCb:read_password("ssh password: ",Ssh0), Ssh0};
+ PW ->
+ %% If "password" option is given it should not be tried again
+ {PW, Ssh0#ssh{opts = lists:keyreplace(password,1,Opts,{password,not_ok})}}
+ end,
+ case Password of
+ not_ok ->
+ {not_ok, Ssh};
+ _ ->
+ ssh_transport:ssh_packet(
+ #ssh_msg_userauth_request{user = User,
+ service = Service,
+ method = "password",
+ data =
+ <>},
+ Ssh)
+ end.
+
+%% See RFC 4256 for info on keyboard-interactive
+keyboard_interactive_msg([#ssh{user = User,
+ opts = Opts,
+ service = Service} = Ssh]) ->
+ case proplists:get_value(password, Opts) of
+ not_ok ->
+ {not_ok,Ssh}; % No need to use a failed pwd once more
+ _ ->
+ ssh_transport:ssh_packet(
+ #ssh_msg_userauth_request{user = User,
+ service = Service,
+ method = "keyboard-interactive",
+ data = << ?STRING(<<"">>),
+ ?STRING(<<>>) >> },
+ Ssh)
+ end.
+
publickey_msg([Alg, #ssh{user = User,
session_id = SessionId,
service = Service,
@@ -48,7 +143,7 @@ publickey_msg([Alg, #ssh{user = User,
StrAlgo = atom_to_list(Alg),
case encode_public_key(StrAlgo, ssh_transport:extract_public_key(PrivKey)) of
not_ok ->
- not_ok;
+ {not_ok, Ssh};
PubKeyBlob ->
SigData = build_sig_data(SessionId,
User, Service, PubKeyBlob, StrAlgo),
@@ -65,52 +160,15 @@ publickey_msg([Alg, #ssh{user = User,
Ssh)
end;
_Error ->
- not_ok
+ {not_ok, Ssh}
end.
-password_msg([#ssh{opts = Opts, io_cb = IoCb,
- user = User, service = Service} = Ssh]) ->
- Password = case proplists:get_value(password, Opts) of
- undefined ->
- user_interaction(IoCb, Ssh);
- PW ->
- PW
- end,
- case Password of
- not_ok ->
- not_ok;
- _ ->
- ssh_transport:ssh_packet(
- #ssh_msg_userauth_request{user = User,
- service = Service,
- method = "password",
- data =
- <>},
- Ssh)
- end.
-
-user_interaction(ssh_no_io, _) ->
- not_ok;
-user_interaction(IoCb, Ssh) ->
- IoCb:read_password("ssh password: ", Ssh).
-
-
-%% See RFC 4256 for info on keyboard-interactive
-keyboard_interactive_msg([#ssh{user = User,
- service = Service} = Ssh]) ->
- ssh_transport:ssh_packet(
- #ssh_msg_userauth_request{user = User,
- service = Service,
- method = "keyboard-interactive",
- data = << ?STRING(<<"">>),
- ?STRING(<<>>) >> },
- Ssh).
-
+%%%----------------------------------------------------------------
service_request_msg(Ssh) ->
ssh_transport:ssh_packet(#ssh_msg_service_request{name = "ssh-userauth"},
Ssh#ssh{service = "ssh-userauth"}).
+%%%----------------------------------------------------------------
init_userauth_request_msg(#ssh{opts = Opts} = Ssh) ->
case user_name(Opts) of
{ok, User} ->
@@ -140,34 +198,9 @@ init_userauth_request_msg(#ssh{opts = Opts} = Ssh) ->
language = "en"})
end.
-userauth_request_msg(#ssh{userauth_preference = []} = Ssh) ->
- Msg = #ssh_msg_disconnect{code =
- ?SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE,
- description = "Unable to connect using the available"
- " authentication methods",
- language = "en"},
- {disconnect, Msg, ssh_transport:ssh_packet(Msg, Ssh)};
-
-userauth_request_msg(#ssh{userauth_methods = Methods,
- userauth_preference = [{Pref, Module,
- Function, Args} | Prefs]}
- = Ssh0) ->
- Ssh = Ssh0#ssh{userauth_preference = Prefs},
- case lists:member(Pref, Methods) of
- true ->
- case Module:Function(Args ++ [Ssh]) of
- not_ok ->
- userauth_request_msg(Ssh);
- Result ->
- {Pref,Result}
- end;
- false ->
- userauth_request_msg(Ssh)
- end.
-
-
-handle_userauth_request(#ssh_msg_service_request{name =
- Name = "ssh-userauth"},
+%%%----------------------------------------------------------------
+%%% called by server
+handle_userauth_request(#ssh_msg_service_request{name = Name = "ssh-userauth"},
_, Ssh) ->
{ok, ssh_transport:ssh_packet(#ssh_msg_service_accept{name = Name},
Ssh#ssh{service = "ssh-connection"})};
@@ -319,21 +352,28 @@ handle_userauth_request(#ssh_msg_userauth_request{user = User,
partial_success = false}, Ssh)}.
-
-handle_userauth_info_request(
- #ssh_msg_userauth_info_request{name = Name,
- instruction = Instr,
- num_prompts = NumPrompts,
- data = Data}, IoCb,
- #ssh{opts = Opts} = Ssh) ->
+%%%----------------------------------------------------------------
+%%% keyboard-interactive client
+handle_userauth_info_request(#ssh_msg_userauth_info_request{name = Name,
+ instruction = Instr,
+ num_prompts = NumPrompts,
+ data = Data},
+ #ssh{opts = Opts,
+ io_cb = IoCb
+ } = Ssh) ->
PromptInfos = decode_keyboard_interactive_prompts(NumPrompts,Data),
- Responses = keyboard_interact_get_responses(IoCb, Opts,
- Name, Instr, PromptInfos),
- {ok,
- ssh_transport:ssh_packet(
- #ssh_msg_userauth_info_response{num_responses = NumPrompts,
- data = Responses}, Ssh)}.
+ case keyboard_interact_get_responses(IoCb, Opts, Name, Instr, PromptInfos) of
+ not_ok ->
+ not_ok;
+ Responses ->
+ {ok,
+ ssh_transport:ssh_packet(
+ #ssh_msg_userauth_info_response{num_responses = NumPrompts,
+ data = Responses}, Ssh)}
+ end.
+%%%----------------------------------------------------------------
+%%% keyboard-interactive server
handle_userauth_info_response(#ssh_msg_userauth_info_response{num_responses = 1,
data = <>},
#ssh{opts = Opts,
@@ -369,11 +409,6 @@ method_preference(Algs) ->
[{"publickey", ?MODULE, publickey_msg, [A]} | Acc]
end,
[{"password", ?MODULE, password_msg, []},
- {"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []},
- {"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []},
- {"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []},
- {"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []},
- {"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []},
{"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []}
],
Algs).
@@ -473,6 +508,9 @@ keyboard_interact_get_responses(IoCb, Opts, Name, Instr, PromptInfos) ->
proplists:get_value(password, Opts, undefined), IoCb, Name,
Instr, PromptInfos, Opts, NumPrompts).
+
+keyboard_interact_get_responses(_, _, not_ok, _, _, _, _, _, _) ->
+ not_ok;
keyboard_interact_get_responses(_, undefined, Password, _, _, _, _, _,
1) when Password =/= undefined ->
[Password]; %% Password auth implemented with keyboard-interaction and passwd is known
--
cgit v1.2.3
From 3ad4e41e4653a910d592ac9912ec380b1cb1b25b Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 16 Jun 2016 18:26:50 +0200
Subject: ssh: Make client send a faulty pwd only once, ssh_connection_handler
part
---
lib/ssh/src/ssh_connection_handler.erl | 28 +++++++++++++++++++++-------
1 file changed, 21 insertions(+), 7 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index ce1931e4f4..b73f8b23d2 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -612,11 +612,14 @@ userauth(#ssh_msg_userauth_banner{message = Msg},
userauth_keyboard_interactive(#ssh_msg_userauth_info_request{} = Msg,
- #state{ssh_params = #ssh{role = client,
- io_cb = IoCb} = Ssh0} = State) ->
- {ok, {Reply, Ssh}} = ssh_auth:handle_userauth_info_request(Msg, IoCb, Ssh0),
- send_msg(Reply, State),
- {next_state, userauth_keyboard_interactive_info_response, next_packet(State#state{ssh_params = Ssh})};
+ #state{ssh_params = #ssh{role = client} = Ssh0} = State) ->
+ case ssh_auth:handle_userauth_info_request(Msg, Ssh0) of
+ {ok, {Reply, Ssh}} ->
+ send_msg(Reply, State),
+ {next_state, userauth_keyboard_interactive_info_response, next_packet(State#state{ssh_params = Ssh})};
+ not_ok ->
+ userauth(Msg, State)
+ end;
userauth_keyboard_interactive(#ssh_msg_userauth_info_response{} = Msg,
#state{ssh_params = #ssh{role = server,
@@ -646,7 +649,18 @@ userauth_keyboard_interactive(Msg = #ssh_msg_userauth_failure{},
userauth_keyboard_interactive_info_response(Msg=#ssh_msg_userauth_failure{},
- #state{ssh_params = #ssh{role = client}} = State) ->
+ #state{ssh_params = #ssh{role = client,
+ opts = Opts} = Ssh0} = State0) ->
+
+ State = case proplists:get_value(password, Opts) of
+ undefined ->
+ State0;
+ _ ->
+ State0#state{ssh_params =
+ Ssh0#ssh{opts =
+ lists:keyreplace(password,1,Opts,
+ {password,not_ok})}}
+ end,
userauth(Msg, State);
userauth_keyboard_interactive_info_response(Msg=#ssh_msg_userauth_success{},
#state{ssh_params = #ssh{role = client}} = State) ->
@@ -1247,7 +1261,7 @@ init_ssh(client = Role, Vsn, Version, Options, Socket) ->
end,
AuthMethods = proplists:get_value(auth_methods, Options,
- ?SUPPORTED_AUTH_METHODS),
+ undefined),
{ok, PeerAddr} = inet:peername(Socket),
PeerName = proplists:get_value(host, Options),
--
cgit v1.2.3
From 688a278d0050ed088df17e351d14e3f9ba193501 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 17 Jun 2016 13:34:47 +0200
Subject: ssh: Fix type error in args of ssh_auth:sort_selected_mthds
---
lib/ssh/src/ssh_auth.erl | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl
index 86a91c6d22..07585dbacd 100644
--- a/lib/ssh/src/ssh_auth.erl
+++ b/lib/ssh/src/ssh_auth.erl
@@ -66,11 +66,15 @@ userauth_request_msg(#ssh{userauth_methods = ServerMethods,
sort_select_mthds(Clients, undefined, Servers) ->
%% User has not expressed an opinion via option "auth_methods", use the server's prefs
- sort_select_mthds(Clients, Servers, Servers);
+ sort_select_mthds1(Clients, Servers, string:tokens(?SUPPORTED_AUTH_METHODS,","));
sort_select_mthds(Clients, Users0, Servers0) ->
%% The User has an opinion, use the intersection of that and the Servers whishes but
%% in the Users order
+ sort_select_mthds1(Clients, string:tokens(Users0,","), Servers0).
+
+
+sort_select_mthds1(Clients, Users0, Servers0) ->
Servers = unique(Servers0),
Users = unique(Users0),
[C || Key <- Users,
--
cgit v1.2.3
From c66f6df0678362ce09558af1981473b0b8d82baf Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 17 Jun 2016 14:41:22 +0200
Subject: ssh: Some code cuddling in ssh_io
---
lib/ssh/src/ssh_io.erl | 42 +++++++++++++++++-------------------------
1 file changed, 17 insertions(+), 25 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_io.erl b/lib/ssh/src/ssh_io.erl
index a5e627fdb3..6be5ea25bb 100644
--- a/lib/ssh/src/ssh_io.erl
+++ b/lib/ssh/src/ssh_io.erl
@@ -36,47 +36,42 @@ read_line(Prompt, Ssh) ->
end.
yes_no(Prompt, Ssh) ->
- io:format("~s [y/n]?", [Prompt]),
+ format("~s [y/n]?", [Prompt]),
proplists:get_value(user_pid, Ssh#ssh.opts) ! {self(), question},
receive
+ %% I can't see that the atoms y and n are ever received, but it must
+ %% be investigated before removing
+ y -> yes;
+ n -> no;
+
Answer ->
case trim(Answer) of
"y" -> yes;
"n" -> no;
"Y" -> yes;
"N" -> no;
- y -> yes;
- n -> no;
_ ->
- io:format("please answer y or n\n"),
+ format("please answer y or n\n",[]),
yes_no(Prompt, Ssh)
end
end.
-read_password(Prompt, Ssh) ->
+read_password(Prompt, #ssh{opts=Opts}) -> read_password(Prompt, Opts);
+read_password(Prompt, Opts) when is_list(Opts) ->
format("~s", [listify(Prompt)]),
- case is_list(Ssh) of
- false ->
- proplists:get_value(user_pid, Ssh#ssh.opts) ! {self(), user_password};
- _ ->
- proplists:get_value(user_pid, Ssh) ! {self(), user_password}
- end,
+ proplists:get_value(user_pid, Opts) ! {self(), user_password},
receive
+ "" ->
+ read_password(Prompt, Opts);
Answer ->
- case Answer of
- "" ->
- read_password(Prompt, Ssh);
- Pass -> Pass
- end
+ Answer
end.
-listify(A) when is_atom(A) ->
- atom_to_list(A);
-listify(L) when is_list(L) ->
- L;
-listify(B) when is_binary(B) ->
- binary_to_list(B).
+
+listify(A) when is_atom(A) -> atom_to_list(A);
+listify(L) when is_list(L) -> L;
+listify(B) when is_binary(B) -> binary_to_list(B).
format(Fmt, Args) ->
io:format(Fmt, Args).
@@ -93,6 +88,3 @@ trim1([$\r|Cs]) -> trim(Cs);
trim1([$\n|Cs]) -> trim(Cs);
trim1([$\t|Cs]) -> trim(Cs);
trim1(Cs) -> Cs.
-
-
-
--
cgit v1.2.3
From d68b279981496c5293746524e00ff77fd8a8b84c Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 17 Jun 2016 14:49:04 +0200
Subject: ssh: Fix a hazard bug in ssh_auth
---
lib/ssh/src/ssh_io.erl | 22 +++++++++++++---------
1 file changed, 13 insertions(+), 9 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_io.erl b/lib/ssh/src/ssh_io.erl
index 6be5ea25bb..5e335c2063 100644
--- a/lib/ssh/src/ssh_io.erl
+++ b/lib/ssh/src/ssh_io.erl
@@ -31,7 +31,7 @@ read_line(Prompt, Ssh) ->
format("~s", [listify(Prompt)]),
proplists:get_value(user_pid, Ssh) ! {self(), question},
receive
- Answer ->
+ Answer when is_list(Answer) ->
Answer
end.
@@ -44,7 +44,7 @@ yes_no(Prompt, Ssh) ->
y -> yes;
n -> no;
- Answer ->
+ Answer when is_list(Answer) ->
case trim(Answer) of
"y" -> yes;
"n" -> no;
@@ -62,20 +62,24 @@ read_password(Prompt, Opts) when is_list(Opts) ->
format("~s", [listify(Prompt)]),
proplists:get_value(user_pid, Opts) ! {self(), user_password},
receive
- "" ->
- read_password(Prompt, Opts);
- Answer ->
- Answer
+ Answer when is_list(Answer) ->
+ case trim(Answer) of
+ "" ->
+ read_password(Prompt, Opts);
+ Pwd ->
+ Pwd
+ end
end.
+format(Fmt, Args) ->
+ io:format(Fmt, Args).
+
+%%%================================================================
listify(A) when is_atom(A) -> atom_to_list(A);
listify(L) when is_list(L) -> L;
listify(B) when is_binary(B) -> binary_to_list(B).
-format(Fmt, Args) ->
- io:format(Fmt, Args).
-
trim(Line) when is_list(Line) ->
lists:reverse(trim1(lists:reverse(trim1(Line))));
--
cgit v1.2.3
From c74cb8aaec77452f7c91ea5345c1b6120fe15224 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 17 Jun 2016 16:01:38 +0200
Subject: ssh: polishing of password prompt's linefeed
---
lib/ssh/src/ssh_auth.erl | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl
index 07585dbacd..0c378d084b 100644
--- a/lib/ssh/src/ssh_auth.erl
+++ b/lib/ssh/src/ssh_auth.erl
@@ -528,17 +528,18 @@ keyboard_interact_get_responses(true, Fun, _Pwd, _IoCb, Name, Instr, PromptInfos
keyboard_interact_fun(Fun, Name, Instr, PromptInfos, NumPrompts).
keyboard_interact(IoCb, Name, Instr, Prompts, Opts) ->
- if Name /= "" -> IoCb:format("~s~n", [Name]);
- true -> ok
- end,
- if Instr /= "" -> IoCb:format("~s~n", [Instr]);
- true -> ok
- end,
+ write_if_nonempty(IoCb, Name),
+ write_if_nonempty(IoCb, Instr),
lists:map(fun({Prompt, true}) -> IoCb:read_line(Prompt, Opts);
({Prompt, false}) -> IoCb:read_password(Prompt, Opts)
end,
Prompts).
+write_if_nonempty(_, "") -> ok;
+write_if_nonempty(_, <<>>) -> ok;
+write_if_nonempty(IoCb, Text) -> IoCb:format("~s~n",[Text]).
+
+
keyboard_interact_fun(KbdInteractFun, Name, Instr, PromptInfos, NumPrompts) ->
Prompts = lists:map(fun({Prompt, _Echo}) -> Prompt end,
PromptInfos),
--
cgit v1.2.3
From 76c968d9a0f667ea3e112676861f5dc399113dae Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Tue, 21 Jun 2016 15:41:14 +0200
Subject: ssh: update vsn.mk
---
lib/ssh/vsn.mk | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index 41b42d454b..dc5e7092f8 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,5 +1,5 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 4.2.2
+SSH_VSN = 4.2.2.1
APP_VSN = "ssh-$(SSH_VSN)"
--
cgit v1.2.3
From 1122ef871c2439e07614f9d6060f1f56f460907a Mon Sep 17 00:00:00 2001
From: Erlang/OTP
Date: Wed, 22 Jun 2016 14:15:24 +0200
Subject: Update release notes
---
lib/ssh/doc/src/notes.xml | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index 5f2cd19cda..00a8bceb4a 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -30,6 +30,22 @@
notes.xml
+Ssh 4.2.2.1
+
+ Fixed Bugs and Malfunctions
+
+ -
+
+ SSH client does not any longer retry a bad password given
+ as option to ssh:connect et al.
+
+ Own Id: OTP-13674 Aux Id: TR-HU92273
+
+
+
+
+
+
Ssh 4.2.2
Fixed Bugs and Malfunctions
--
cgit v1.2.3
From 3f2ed5864b94edb6709c7942f5fdc50448744e3d Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 15 Jun 2016 12:04:28 +0200
Subject: ssh: test cases for no repetition of bad passwords
---
lib/ssh/test/ssh_basic_SUITE.erl | 84 ++++++++++++++++++++++++++++++++++++++--
1 file changed, 81 insertions(+), 3 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index 733414e23a..d52d453007 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -50,7 +50,12 @@
inet6_option/1,
inet_option/1,
internal_error/1,
- known_hosts/1,
+ known_hosts/1,
+ login_bad_pwd_no_retry1/1,
+ login_bad_pwd_no_retry2/1,
+ login_bad_pwd_no_retry3/1,
+ login_bad_pwd_no_retry4/1,
+ login_bad_pwd_no_retry5/1,
misc_ssh_options/1,
openssh_zlib_basic_test/1,
packet_size_zero/1,
@@ -100,7 +105,8 @@ all() ->
daemon_opt_fd,
multi_daemon_opt_fd,
packet_size_zero,
- ssh_info_print
+ ssh_info_print,
+ {group, login_bad_pwd_no_retry}
].
groups() ->
@@ -116,7 +122,13 @@ groups() ->
{dsa_pass_key, [], [pass_phrase]},
{rsa_pass_key, [], [pass_phrase]},
{key_cb, [], [key_callback, key_callback_options]},
- {internal_error, [], [internal_error]}
+ {internal_error, [], [internal_error]},
+ {login_bad_pwd_no_retry, [], [login_bad_pwd_no_retry1,
+ login_bad_pwd_no_retry2,
+ login_bad_pwd_no_retry3,
+ login_bad_pwd_no_retry4,
+ login_bad_pwd_no_retry5
+ ]}
].
@@ -1089,6 +1101,72 @@ ssh_info_print(Config) ->
end.
+%%--------------------------------------------------------------------
+%% Check that a basd pwd is not tried more times. Could cause lock-out
+%% on server
+
+login_bad_pwd_no_retry1(Config) ->
+ login_bad_pwd_no_retry(Config, "keyboard-interactive,password").
+
+login_bad_pwd_no_retry2(Config) ->
+ login_bad_pwd_no_retry(Config, "password,keyboard-interactive").
+
+login_bad_pwd_no_retry3(Config) ->
+ login_bad_pwd_no_retry(Config, "password,publickey,keyboard-interactive").
+
+login_bad_pwd_no_retry4(Config) ->
+ login_bad_pwd_no_retry(Config, "password,other,keyboard-interactive").
+
+login_bad_pwd_no_retry5(Config) ->
+ login_bad_pwd_no_retry(Config, "password,other,keyboard-interactive,password,password").
+
+
+
+
+
+login_bad_pwd_no_retry(Config, AuthMethods) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth
+ file:make_dir(UserDir),
+ SysDir = proplists:get_value(data_dir, Config),
+
+ Parent = self(),
+ PwdFun = fun(_, _, _, undefined) -> {false, 1};
+ (_, _, _, _) -> Parent ! retry_bad_pwd,
+ false
+ end,
+
+ {DaemonRef, _Host, Port} =
+ ssh_test_lib:daemon([{system_dir, SysDir},
+ {user_dir, UserDir},
+ {auth_methods, AuthMethods},
+ {user_passwords, [{"foo","somepwd"}]},
+ {pwdfun, PwdFun}
+ ]),
+
+ ConnRes = ssh:connect("localhost", Port,
+ [{silently_accept_hosts, true},
+ {user, "foo"},
+ {password, "badpwd"},
+ {user_dir, UserDir},
+ {user_interaction, false}]),
+
+ receive
+ retry_bad_pwd ->
+ ssh:stop_daemon(DaemonRef),
+ {fail, "Retry bad password"}
+ after 0 ->
+ case ConnRes of
+ {error,"Unable to connect using the available authentication methods"} ->
+ ssh:stop_daemon(DaemonRef),
+ ok;
+ {ok,Conn} ->
+ ssh:close(Conn),
+ ssh:stop_daemon(DaemonRef),
+ {fail, "Connect erroneosly succeded"}
+ end
+ end.
+
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
--
cgit v1.2.3
From 53b5d8cf604222c970a298e98c6937e268011b54 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 15 Jun 2016 13:03:40 +0200
Subject: ssh: Make client send a faulty pwd only once, ssh_auth part
Conflicts:
lib/ssh/src/ssh_connection_handler.erl
---
lib/ssh/src/ssh_auth.erl | 214 ++++++++++++++++++++++++++++-------------------
1 file changed, 126 insertions(+), 88 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl
index 49eec8072f..1c6f656913 100644
--- a/lib/ssh/src/ssh_auth.erl
+++ b/lib/ssh/src/ssh_auth.erl
@@ -31,12 +31,107 @@
-export([publickey_msg/1, password_msg/1, keyboard_interactive_msg/1,
service_request_msg/1, init_userauth_request_msg/1,
userauth_request_msg/1, handle_userauth_request/3,
- handle_userauth_info_request/3, handle_userauth_info_response/2
+ handle_userauth_info_request/2, handle_userauth_info_response/2
]).
%%--------------------------------------------------------------------
%%% Internal application API
%%--------------------------------------------------------------------
+%%%----------------------------------------------------------------
+userauth_request_msg(#ssh{userauth_methods = ServerMethods,
+ userauth_supported_methods = UserPrefMethods, % Note: this is not documented as supported for clients
+ userauth_preference = ClientMethods0
+ } = Ssh0) ->
+ case sort_select_mthds(ClientMethods0, UserPrefMethods, ServerMethods) of
+ [] ->
+ Msg = #ssh_msg_disconnect{code = ?SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE,
+ description = "Unable to connect using the available authentication methods",
+ language = "en"},
+ {disconnect, Msg, ssh_transport:ssh_packet(Msg, Ssh0)};
+
+ [{Pref,Module,Function,Args} | Prefs] ->
+ Ssh = case Pref of
+ "keyboard-interactive" -> Ssh0;
+ _ -> Ssh0#ssh{userauth_preference = Prefs}
+ end,
+ case Module:Function(Args ++ [Ssh]) of
+ {not_ok, Ssh1} ->
+ userauth_request_msg(Ssh1#ssh{userauth_preference = Prefs});
+ Result ->
+ {Pref,Result}
+ end
+ end.
+
+
+
+sort_select_mthds(Clients, undefined, Servers) ->
+ %% User has not expressed an opinion via option "auth_methods", use the server's prefs
+ sort_select_mthds(Clients, Servers, Servers);
+
+sort_select_mthds(Clients, Users0, Servers0) ->
+ %% The User has an opinion, use the intersection of that and the Servers whishes but
+ %% in the Users order
+ Servers = unique(Servers0),
+ Users = unique(Users0),
+ [C || Key <- Users,
+ lists:member(Key, Servers),
+ C <- Clients,
+ element(1,C) == Key].
+
+unique(L) ->
+ lists:reverse(
+ lists:foldl(fun(E,Acc) ->
+ case lists:member(E,Acc) of
+ true -> Acc;
+ false -> [E|Acc]
+ end
+ end, [], L)).
+
+
+%%%---- userauth_request_msg "callbacks"
+password_msg([#ssh{opts = Opts, io_cb = IoCb,
+ user = User, service = Service} = Ssh0]) ->
+ {Password,Ssh} =
+ case proplists:get_value(password, Opts) of
+ undefined when IoCb == ssh_no_io ->
+ {not_ok, Ssh0};
+ undefined ->
+ {IoCb:read_password("ssh password: ",Ssh0), Ssh0};
+ PW ->
+ %% If "password" option is given it should not be tried again
+ {PW, Ssh0#ssh{opts = lists:keyreplace(password,1,Opts,{password,not_ok})}}
+ end,
+ case Password of
+ not_ok ->
+ {not_ok, Ssh};
+ _ ->
+ ssh_transport:ssh_packet(
+ #ssh_msg_userauth_request{user = User,
+ service = Service,
+ method = "password",
+ data =
+ <>},
+ Ssh)
+ end.
+
+%% See RFC 4256 for info on keyboard-interactive
+keyboard_interactive_msg([#ssh{user = User,
+ opts = Opts,
+ service = Service} = Ssh]) ->
+ case proplists:get_value(password, Opts) of
+ not_ok ->
+ {not_ok,Ssh}; % No need to use a failed pwd once more
+ _ ->
+ ssh_transport:ssh_packet(
+ #ssh_msg_userauth_request{user = User,
+ service = Service,
+ method = "keyboard-interactive",
+ data = << ?STRING(<<"">>),
+ ?STRING(<<>>) >> },
+ Ssh)
+ end.
+
publickey_msg([Alg, #ssh{user = User,
session_id = SessionId,
service = Service,
@@ -48,7 +143,7 @@ publickey_msg([Alg, #ssh{user = User,
StrAlgo = atom_to_list(Alg),
case encode_public_key(StrAlgo, ssh_transport:extract_public_key(PrivKey)) of
not_ok ->
- not_ok;
+ {not_ok, Ssh};
PubKeyBlob ->
SigData = build_sig_data(SessionId,
User, Service, PubKeyBlob, StrAlgo),
@@ -65,52 +160,15 @@ publickey_msg([Alg, #ssh{user = User,
Ssh)
end;
_Error ->
- not_ok
+ {not_ok, Ssh}
end.
-password_msg([#ssh{opts = Opts, io_cb = IoCb,
- user = User, service = Service} = Ssh]) ->
- Password = case proplists:get_value(password, Opts) of
- undefined ->
- user_interaction(IoCb, Ssh);
- PW ->
- PW
- end,
- case Password of
- not_ok ->
- not_ok;
- _ ->
- ssh_transport:ssh_packet(
- #ssh_msg_userauth_request{user = User,
- service = Service,
- method = "password",
- data =
- <>},
- Ssh)
- end.
-
-user_interaction(ssh_no_io, _) ->
- not_ok;
-user_interaction(IoCb, Ssh) ->
- IoCb:read_password("ssh password: ", Ssh).
-
-
-%% See RFC 4256 for info on keyboard-interactive
-keyboard_interactive_msg([#ssh{user = User,
- service = Service} = Ssh]) ->
- ssh_transport:ssh_packet(
- #ssh_msg_userauth_request{user = User,
- service = Service,
- method = "keyboard-interactive",
- data = << ?STRING(<<"">>),
- ?STRING(<<>>) >> },
- Ssh).
-
+%%%----------------------------------------------------------------
service_request_msg(Ssh) ->
ssh_transport:ssh_packet(#ssh_msg_service_request{name = "ssh-userauth"},
Ssh#ssh{service = "ssh-userauth"}).
+%%%----------------------------------------------------------------
init_userauth_request_msg(#ssh{opts = Opts} = Ssh) ->
case user_name(Opts) of
{ok, User} ->
@@ -140,34 +198,9 @@ init_userauth_request_msg(#ssh{opts = Opts} = Ssh) ->
description = ErrStr})
end.
-userauth_request_msg(#ssh{userauth_preference = []} = Ssh) ->
- Msg = #ssh_msg_disconnect{code =
- ?SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE,
- description = "Unable to connect using the available"
- " authentication methods",
- language = "en"},
- {disconnect, Msg, ssh_transport:ssh_packet(Msg, Ssh)};
-
-userauth_request_msg(#ssh{userauth_methods = Methods,
- userauth_preference = [{Pref, Module,
- Function, Args} | Prefs]}
- = Ssh0) ->
- Ssh = Ssh0#ssh{userauth_preference = Prefs},
- case lists:member(Pref, Methods) of
- true ->
- case Module:Function(Args ++ [Ssh]) of
- not_ok ->
- userauth_request_msg(Ssh);
- Result ->
- {Pref,Result}
- end;
- false ->
- userauth_request_msg(Ssh)
- end.
-
-
-handle_userauth_request(#ssh_msg_service_request{name =
- Name = "ssh-userauth"},
+%%%----------------------------------------------------------------
+%%% called by server
+handle_userauth_request(#ssh_msg_service_request{name = Name = "ssh-userauth"},
_, Ssh) ->
{ok, ssh_transport:ssh_packet(#ssh_msg_service_accept{name = Name},
Ssh#ssh{service = "ssh-connection"})};
@@ -319,21 +352,28 @@ handle_userauth_request(#ssh_msg_userauth_request{user = User,
partial_success = false}, Ssh)}.
-
-handle_userauth_info_request(
- #ssh_msg_userauth_info_request{name = Name,
- instruction = Instr,
- num_prompts = NumPrompts,
- data = Data}, IoCb,
- #ssh{opts = Opts} = Ssh) ->
+%%%----------------------------------------------------------------
+%%% keyboard-interactive client
+handle_userauth_info_request(#ssh_msg_userauth_info_request{name = Name,
+ instruction = Instr,
+ num_prompts = NumPrompts,
+ data = Data},
+ #ssh{opts = Opts,
+ io_cb = IoCb
+ } = Ssh) ->
PromptInfos = decode_keyboard_interactive_prompts(NumPrompts,Data),
- Responses = keyboard_interact_get_responses(IoCb, Opts,
- Name, Instr, PromptInfos),
- {ok,
- ssh_transport:ssh_packet(
- #ssh_msg_userauth_info_response{num_responses = NumPrompts,
- data = Responses}, Ssh)}.
+ case keyboard_interact_get_responses(IoCb, Opts, Name, Instr, PromptInfos) of
+ not_ok ->
+ not_ok;
+ Responses ->
+ {ok,
+ ssh_transport:ssh_packet(
+ #ssh_msg_userauth_info_response{num_responses = NumPrompts,
+ data = Responses}, Ssh)}
+ end.
+%%%----------------------------------------------------------------
+%%% keyboard-interactive server
handle_userauth_info_response(#ssh_msg_userauth_info_response{num_responses = 1,
data = <>},
#ssh{opts = Opts,
@@ -369,11 +409,6 @@ method_preference(Algs) ->
[{"publickey", ?MODULE, publickey_msg, [A]} | Acc]
end,
[{"password", ?MODULE, password_msg, []},
- {"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []},
- {"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []},
- {"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []},
- {"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []},
- {"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []},
{"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []}
],
Algs).
@@ -473,6 +508,9 @@ keyboard_interact_get_responses(IoCb, Opts, Name, Instr, PromptInfos) ->
proplists:get_value(password, Opts, undefined), IoCb, Name,
Instr, PromptInfos, Opts, NumPrompts).
+
+keyboard_interact_get_responses(_, _, not_ok, _, _, _, _, _, _) ->
+ not_ok;
keyboard_interact_get_responses(_, undefined, Password, _, _, _, _, _,
1) when Password =/= undefined ->
[Password]; %% Password auth implemented with keyboard-interaction and passwd is known
--
cgit v1.2.3
From 4f24fd3f8943d8c7ebd56336d15f699dde9bcc61 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 15 Jun 2016 13:03:40 +0200
Subject: ssh: Make client send a faulty pwd only once, ssh_connection_handler
part
---
lib/ssh/src/ssh_connection_handler.erl | 30 +++++++++++++++++++++++++-----
1 file changed, 25 insertions(+), 5 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index e952a333ff..27c205a932 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -428,7 +428,12 @@ init_connection(server, C = #connection{}, Opts) ->
init_ssh_record(Role, Socket, Opts) ->
{ok, PeerAddr} = inet:peername(Socket),
KeyCb = proplists:get_value(key_cb, Opts, ssh_file),
- AuthMethods = proplists:get_value(auth_methods, Opts, ?SUPPORTED_AUTH_METHODS),
+ AuthMethods = proplists:get_value(auth_methods,
+ Opts,
+ case Role of
+ server -> ?SUPPORTED_AUTH_METHODS;
+ client -> undefined
+ end),
S0 = #ssh{role = Role,
key_cb = KeyCb,
opts = Opts,
@@ -794,9 +799,13 @@ handle_event(_, #ssh_msg_userauth_banner{message = Msg}, {userauth,client}, D) -
handle_event(_, #ssh_msg_userauth_info_request{} = Msg, {userauth_keyboard_interactive, client},
#data{ssh_params = Ssh0} = D) ->
- {ok, {Reply, Ssh}} = ssh_auth:handle_userauth_info_request(Msg, Ssh0#ssh.io_cb, Ssh0),
- send_bytes(Reply, D),
- {next_state, {userauth_keyboard_interactive_info_response,client}, D#data{ssh_params = Ssh}};
+ case ssh_auth:handle_userauth_info_request(Msg, Ssh0) of
+ {ok, {Reply, Ssh}} ->
+ send_bytes(Reply, D),
+ {next_state, {userauth_keyboard_interactive_info_response,client}, D#data{ssh_params = Ssh}};
+ not_ok ->
+ {next_state, {userauth,client}, D, [{next_event, internal, Msg}]}
+ end;
handle_event(_, #ssh_msg_userauth_info_response{} = Msg, {userauth_keyboard_interactive, server}, D) ->
case ssh_auth:handle_userauth_info_response(Msg, D#data.ssh_params) of
@@ -819,7 +828,18 @@ handle_event(_, Msg = #ssh_msg_userauth_failure{}, {userauth_keyboard_interactiv
D = D0#data{ssh_params = Ssh0#ssh{userauth_preference=Prefs}},
{next_state, {userauth,client}, D, [{next_event, internal, Msg}]};
-handle_event(_, Msg=#ssh_msg_userauth_failure{}, {userauth_keyboard_interactive_info_response, client}, D) ->
+handle_event(_, Msg=#ssh_msg_userauth_failure{}, {userauth_keyboard_interactive_info_response, client},
+ #data{ssh_params = Ssh0} = D0) ->
+ Opts = Ssh0#ssh.opts,
+ D = case proplists:get_value(password, Opts) of
+ undefined ->
+ D0;
+ _ ->
+ D0#data{ssh_params =
+ Ssh0#ssh{opts =
+ lists:keyreplace(password,1,Opts,
+ {password,not_ok})}} % FIXME:intermodule dependency
+ end,
{next_state, {userauth,client}, D, [{next_event, internal, Msg}]};
handle_event(_, Msg=#ssh_msg_userauth_success{}, {userauth_keyboard_interactive_info_response, client}, D) ->
--
cgit v1.2.3
From 2219cdc9dfa500625527510a4e179cd9c068407a Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 17 Jun 2016 13:34:47 +0200
Subject: ssh: Fix type error in args of ssh_auth:sort_selected_mthds
---
lib/ssh/src/ssh_auth.erl | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl
index 1c6f656913..c8f66c9d61 100644
--- a/lib/ssh/src/ssh_auth.erl
+++ b/lib/ssh/src/ssh_auth.erl
@@ -66,11 +66,15 @@ userauth_request_msg(#ssh{userauth_methods = ServerMethods,
sort_select_mthds(Clients, undefined, Servers) ->
%% User has not expressed an opinion via option "auth_methods", use the server's prefs
- sort_select_mthds(Clients, Servers, Servers);
+ sort_select_mthds1(Clients, Servers, string:tokens(?SUPPORTED_AUTH_METHODS,","));
sort_select_mthds(Clients, Users0, Servers0) ->
%% The User has an opinion, use the intersection of that and the Servers whishes but
%% in the Users order
+ sort_select_mthds1(Clients, string:tokens(Users0,","), Servers0).
+
+
+sort_select_mthds1(Clients, Users0, Servers0) ->
Servers = unique(Servers0),
Users = unique(Users0),
[C || Key <- Users,
--
cgit v1.2.3
From 51f0950b714505a036df7e1c3030b1c16828fd3c Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 17 Jun 2016 14:41:22 +0200
Subject: ssh: Some code cuddling in ssh_io
---
lib/ssh/src/ssh_io.erl | 42 +++++++++++++++++-------------------------
1 file changed, 17 insertions(+), 25 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_io.erl b/lib/ssh/src/ssh_io.erl
index 026d0f6151..759ee71877 100644
--- a/lib/ssh/src/ssh_io.erl
+++ b/lib/ssh/src/ssh_io.erl
@@ -36,47 +36,42 @@ read_line(Prompt, Ssh) ->
end.
yes_no(Prompt, Ssh) ->
- io:format("~s [y/n]?", [Prompt]),
+ format("~s [y/n]?", [Prompt]),
proplists:get_value(user_pid, Ssh#ssh.opts) ! {self(), question},
receive
+ %% I can't see that the atoms y and n are ever received, but it must
+ %% be investigated before removing
+ y -> yes;
+ n -> no;
+
Answer ->
case trim(Answer) of
"y" -> yes;
"n" -> no;
"Y" -> yes;
"N" -> no;
- y -> yes;
- n -> no;
_ ->
- io:format("please answer y or n\n"),
+ format("please answer y or n\n",[]),
yes_no(Prompt, Ssh)
end
end.
-read_password(Prompt, Ssh) ->
+read_password(Prompt, #ssh{opts=Opts}) -> read_password(Prompt, Opts);
+read_password(Prompt, Opts) when is_list(Opts) ->
format("~s", [listify(Prompt)]),
- case is_list(Ssh) of
- false ->
- proplists:get_value(user_pid, Ssh#ssh.opts) ! {self(), user_password};
- _ ->
- proplists:get_value(user_pid, Ssh) ! {self(), user_password}
- end,
+ proplists:get_value(user_pid, Opts) ! {self(), user_password},
receive
+ "" ->
+ read_password(Prompt, Opts);
Answer ->
- case Answer of
- "" ->
- read_password(Prompt, Ssh);
- Pass -> Pass
- end
+ Answer
end.
-listify(A) when is_atom(A) ->
- atom_to_list(A);
-listify(L) when is_list(L) ->
- L;
-listify(B) when is_binary(B) ->
- binary_to_list(B).
+
+listify(A) when is_atom(A) -> atom_to_list(A);
+listify(L) when is_list(L) -> L;
+listify(B) when is_binary(B) -> binary_to_list(B).
format(Fmt, Args) ->
io:format(Fmt, Args).
@@ -93,6 +88,3 @@ trim1([$\r|Cs]) -> trim(Cs);
trim1([$\n|Cs]) -> trim(Cs);
trim1([$\t|Cs]) -> trim(Cs);
trim1(Cs) -> Cs.
-
-
-
--
cgit v1.2.3
From 4586fd6fa3447a1c4191620fe5b8f4412d5af0ad Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 17 Jun 2016 14:49:04 +0200
Subject: ssh: Fix a hazard bug in ssh_auth
---
lib/ssh/src/ssh_io.erl | 22 +++++++++++++---------
1 file changed, 13 insertions(+), 9 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_io.erl b/lib/ssh/src/ssh_io.erl
index 759ee71877..1d8f370884 100644
--- a/lib/ssh/src/ssh_io.erl
+++ b/lib/ssh/src/ssh_io.erl
@@ -31,7 +31,7 @@ read_line(Prompt, Ssh) ->
format("~s", [listify(Prompt)]),
proplists:get_value(user_pid, Ssh) ! {self(), question},
receive
- Answer ->
+ Answer when is_list(Answer) ->
Answer
end.
@@ -44,7 +44,7 @@ yes_no(Prompt, Ssh) ->
y -> yes;
n -> no;
- Answer ->
+ Answer when is_list(Answer) ->
case trim(Answer) of
"y" -> yes;
"n" -> no;
@@ -62,20 +62,24 @@ read_password(Prompt, Opts) when is_list(Opts) ->
format("~s", [listify(Prompt)]),
proplists:get_value(user_pid, Opts) ! {self(), user_password},
receive
- "" ->
- read_password(Prompt, Opts);
- Answer ->
- Answer
+ Answer when is_list(Answer) ->
+ case trim(Answer) of
+ "" ->
+ read_password(Prompt, Opts);
+ Pwd ->
+ Pwd
+ end
end.
+format(Fmt, Args) ->
+ io:format(Fmt, Args).
+
+%%%================================================================
listify(A) when is_atom(A) -> atom_to_list(A);
listify(L) when is_list(L) -> L;
listify(B) when is_binary(B) -> binary_to_list(B).
-format(Fmt, Args) ->
- io:format(Fmt, Args).
-
trim(Line) when is_list(Line) ->
lists:reverse(trim1(lists:reverse(trim1(Line))));
--
cgit v1.2.3
From 12cdbfec9d19378057e92200564198f359ea3c43 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 17 Jun 2016 16:01:38 +0200
Subject: ssh: polishing of password prompt's linefeed
---
lib/ssh/src/ssh_auth.erl | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl
index c8f66c9d61..fb5e086656 100644
--- a/lib/ssh/src/ssh_auth.erl
+++ b/lib/ssh/src/ssh_auth.erl
@@ -528,17 +528,18 @@ keyboard_interact_get_responses(true, Fun, _Pwd, _IoCb, Name, Instr, PromptInfos
keyboard_interact_fun(Fun, Name, Instr, PromptInfos, NumPrompts).
keyboard_interact(IoCb, Name, Instr, Prompts, Opts) ->
- if Name /= "" -> IoCb:format("~s~n", [Name]);
- true -> ok
- end,
- if Instr /= "" -> IoCb:format("~s~n", [Instr]);
- true -> ok
- end,
+ write_if_nonempty(IoCb, Name),
+ write_if_nonempty(IoCb, Instr),
lists:map(fun({Prompt, true}) -> IoCb:read_line(Prompt, Opts);
({Prompt, false}) -> IoCb:read_password(Prompt, Opts)
end,
Prompts).
+write_if_nonempty(_, "") -> ok;
+write_if_nonempty(_, <<>>) -> ok;
+write_if_nonempty(IoCb, Text) -> IoCb:format("~s~n",[Text]).
+
+
keyboard_interact_fun(KbdInteractFun, Name, Instr, PromptInfos, NumPrompts) ->
Prompts = lists:map(fun({Prompt, _Echo}) -> Prompt end,
PromptInfos),
--
cgit v1.2.3
From e6e8b9bd005910ba3840b5ff154e37d5e1366a8b Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 27 Jun 2016 13:49:44 +0200
Subject: ssh: update vsn.mk
---
lib/ssh/vsn.mk | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index b165928877..575c1af3a9 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,5 +1,5 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 4.3
+SSH_VSN = 4.3.1
APP_VSN = "ssh-$(SSH_VSN)"
--
cgit v1.2.3
From 4fb1bf9584cd2a9efb5dd0b527961087a3871387 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 22 Jun 2016 12:06:37 +0200
Subject: ssh: remove 'sync sleeps'
---
lib/ssh/src/ssh_connection_handler.erl | 3 ---
1 file changed, 3 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index e952a333ff..a62af9e1ce 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -1315,12 +1315,10 @@ terminate(shutdown, StateName, State0) ->
State = send_msg(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_BY_APPLICATION,
description = "Application shutdown"},
State0),
-timer:sleep(400), %% FIXME!!! gen_tcp:shutdown instead
finalize_termination(StateName, State);
%% terminate({shutdown,Msg}, StateName, State0) when is_record(Msg,ssh_msg_disconnect)->
%% State = send_msg(Msg, State0),
-%% timer:sleep(400), %% FIXME!!! gen_tcp:shutdown instead
%% finalize_termination(StateName, Msg, State);
terminate({shutdown,_R}, StateName, State) ->
@@ -1635,7 +1633,6 @@ new_channel_id(#data{connection_state = #connection{channel_id_seed = Id} =
disconnect(Msg=#ssh_msg_disconnect{description=Description}, _StateName, State0) ->
State = send_msg(Msg, State0),
disconnect_fun(Description, State),
-timer:sleep(400),
{stop, {shutdown,Description}, State}.
%%%----------------------------------------------------------------
--
cgit v1.2.3
From 4b8ac323044db286123c3f9734681b53e824b6ac Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 22 Jun 2016 12:07:35 +0200
Subject: ssh: Extend experimental ssh_dbg.erl
1) extend ssh_dbg:message with second arg, a fun/1 that is intended to replace pids in the trace printouts with better descriptions.
2) printout improvments
---
lib/ssh/src/ssh_dbg.erl | 37 ++++++++++++++++++++++++++++---------
1 file changed, 28 insertions(+), 9 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_dbg.erl b/lib/ssh/src/ssh_dbg.erl
index 480795cfc7..bd6bc0335b 100644
--- a/lib/ssh/src/ssh_dbg.erl
+++ b/lib/ssh/src/ssh_dbg.erl
@@ -24,6 +24,7 @@
-export([messages/0,
messages/1,
+ messages/2,
stop/0
]).
@@ -36,12 +37,16 @@
writer,
acc = []}).
%%%================================================================
-messages() -> messages(fun(String,_D) -> io:format(String) end).
-%% messages() -> messages(fun(String,Acc) -> [String|Acc] end)
+messages() ->
+ messages(fun(String,_D) -> io:format(String) end).
messages(Write) when is_function(Write,2) ->
+ messages(Write, fun(X) -> X end).
+
+messages(Write, MangleArg) when is_function(Write,2),
+ is_function(MangleArg,1) ->
catch dbg:start(),
- setup_tracer(Write),
+ setup_tracer(Write, MangleArg),
dbg:p(new,c),
dbg_ssh_messages().
@@ -63,18 +68,30 @@ msg_formater({trace,_Pid,return_from,{ssh_message,encode,1},_Res}, D) ->
msg_formater({trace,_Pid,call,{ssh_message,decode,_}}, D) ->
D;
msg_formater({trace,Pid,return_from,{ssh_message,decode,1},Msg}, D) ->
- fmt("~nRECV ~p ~s~n", [Pid,wr_record(shrink_bin(Msg))], D);
+ fmt("~n~p RECV ~s~n", [Pid,wr_record(shrink_bin(Msg))], D);
msg_formater({trace,_Pid,call,{ssh_transport,select_algorithm,_}}, D) ->
D;
msg_formater({trace,Pid,return_from,{ssh_transport,select_algorithm,3},{ok,Alg}}, D) ->
- fmt("~nALGORITHMS ~p~n~s~n", [Pid, wr_record(Alg)], D);
+ fmt("~n~p ALGORITHMS~n~s~n", [Pid, wr_record(Alg)], D);
+
+
+msg_formater({trace,Pid,send,{tcp,Sock,Bytes},Pid}, D) ->
+ fmt("~n~p TCP SEND on ~p~n ~p~n", [Pid,Sock, shrink_bin(Bytes)], D);
+
+msg_formater({trace,Pid,send,{tcp,Sock,Bytes},Dest}, D) ->
+ fmt("~n~p TCP SEND from ~p TO ~p~n ~p~n", [Pid,Sock,Dest, shrink_bin(Bytes)], D);
msg_formater({trace,Pid,send,ErlangMsg,Dest}, D) ->
- fmt("~nERL MSG ~p SEND TO ~p~n ~p~n", [Pid,Dest, shrink_bin(ErlangMsg)], D);
+ fmt("~n~p ERL MSG SEND TO ~p~n ~p~n", [Pid,Dest, shrink_bin(ErlangMsg)], D);
+
+
+msg_formater({trace,Pid,'receive',{tcp,Sock,Bytes}}, D) ->
+ fmt("~n~p TCP RECEIVE on ~p~n ~p~n", [Pid,Sock,shrink_bin(Bytes)], D);
msg_formater({trace,Pid,'receive',ErlangMsg}, D) ->
- fmt("~nERL MSG ~p RECIEVE~n ~p~n", [Pid,shrink_bin(ErlangMsg)], D);
+ fmt("~n~p ERL MSG RECEIVE~n ~p~n", [Pid,shrink_bin(ErlangMsg)], D);
+
msg_formater(M, D) ->
fmt("~nDBG ~n~p~n", [shrink_bin(M)], D).
@@ -87,8 +104,10 @@ fmt(Fmt, Args, D=#data{writer=Write,acc=Acc}) ->
D#data{acc = Write(io_lib:format(Fmt, Args), Acc)}.
%%%----------------------------------------------------------------
-setup_tracer(Write) ->
- Handler = fun msg_formater/2,
+setup_tracer(Write, MangleArg) ->
+ Handler = fun(Arg, D) ->
+ msg_formater(MangleArg(Arg), D)
+ end,
InitialData = #data{writer = Write},
{ok,_} = dbg:tracer(process, {Handler, InitialData}),
ok.
--
cgit v1.2.3
From 698b11ec4a4f9944ea66ace7bacb17535f6cb9ee Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 23 Jun 2016 15:47:48 +0200
Subject: ssh: added dbg keys to ssh:connection_info/2 and ssh:channel_info/3
---
lib/ssh/src/ssh_connection_handler.erl | 73 +++++++++++++++++-----------------
1 file changed, 36 insertions(+), 37 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index a62af9e1ce..f825f0fae2 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -1006,13 +1006,13 @@ handle_event({call,From}, get_print_info, StateName, D) ->
{keep_state_and_data, [{reply,From,Reply}]};
handle_event({call,From}, {connection_info, Options}, _, D) ->
- Info = ssh_info(Options, D, []),
+ Info = fold_keys(Options, fun conn_info/2, D),
{keep_state_and_data, [{reply,From,Info}]};
handle_event({call,From}, {channel_info,ChannelId,Options}, _, D) ->
case ssh_channel:cache_lookup(cache(D), ChannelId) of
#channel{} = Channel ->
- Info = ssh_channel_info(Options, Channel, []),
+ Info = fold_keys(Options, fun chann_info/2, Channel),
{keep_state_and_data, [{reply,From,Info}]};
undefined ->
{keep_state_and_data, [{reply,From,[]}]}
@@ -1641,43 +1641,43 @@ counterpart_versions(NumVsn, StrVsn, #ssh{role = server} = Ssh) ->
counterpart_versions(NumVsn, StrVsn, #ssh{role = client} = Ssh) ->
Ssh#ssh{s_vsn = NumVsn , s_version = StrVsn}.
-ssh_info([], _State, Acc) ->
- Acc;
-ssh_info([client_version | Rest], #data{ssh_params = #ssh{c_vsn = IntVsn,
- c_version = StringVsn}} = State, Acc) ->
- ssh_info(Rest, State, [{client_version, {IntVsn, StringVsn}} | Acc]);
-
-ssh_info([server_version | Rest], #data{ssh_params =#ssh{s_vsn = IntVsn,
- s_version = StringVsn}} = State, Acc) ->
- ssh_info(Rest, State, [{server_version, {IntVsn, StringVsn}} | Acc]);
-ssh_info([peer | Rest], #data{ssh_params = #ssh{peer = Peer}} = State, Acc) ->
- ssh_info(Rest, State, [{peer, Peer} | Acc]);
-ssh_info([sockname | Rest], #data{socket = Socket} = State, Acc) ->
- {ok, SockName} = inet:sockname(Socket),
- ssh_info(Rest, State, [{sockname, SockName}|Acc]);
-ssh_info([user | Rest], #data{auth_user = User} = State, Acc) ->
- ssh_info(Rest, State, [{user, User}|Acc]);
-ssh_info([ _ | Rest], State, Acc) ->
- ssh_info(Rest, State, Acc).
-
-
-ssh_channel_info([], _, Acc) ->
- Acc;
+%%%----------------------------------------------------------------
+conn_info(client_version, #data{ssh_params=S}) -> {S#ssh.c_vsn, S#ssh.c_version};
+conn_info(server_version, #data{ssh_params=S}) -> {S#ssh.s_vsn, S#ssh.s_version};
+conn_info(peer, #data{ssh_params=S}) -> S#ssh.peer;
+conn_info(user, D) -> D#data.auth_user;
+conn_info(sockname, D) -> {ok, SockName} = inet:sockname(D#data.socket),
+ SockName;
+%% dbg options ( = not documented):
+conn_info(socket, D) -> D#data.socket;
+conn_info(chan_ids, D) ->
+ ssh_channel:cache_foldl(fun(#channel{local_id=Id}, Acc) ->
+ [Id | Acc]
+ end, [], cache(D)).
-ssh_channel_info([recv_window | Rest], #channel{recv_window_size = WinSize,
- recv_packet_size = Packsize
- } = Channel, Acc) ->
- ssh_channel_info(Rest, Channel, [{recv_window, {{win_size, WinSize},
- {packet_size, Packsize}}} | Acc]);
-ssh_channel_info([send_window | Rest], #channel{send_window_size = WinSize,
- send_packet_size = Packsize
- } = Channel, Acc) ->
- ssh_channel_info(Rest, Channel, [{send_window, {{win_size, WinSize},
- {packet_size, Packsize}}} | Acc]);
-ssh_channel_info([ _ | Rest], Channel, Acc) ->
- ssh_channel_info(Rest, Channel, Acc).
+%%%----------------------------------------------------------------
+chann_info(recv_window, C) ->
+ {{win_size, C#channel.recv_window_size},
+ {packet_size, C#channel.recv_packet_size}};
+chann_info(send_window, C) ->
+ {{win_size, C#channel.send_window_size},
+ {packet_size, C#channel.send_packet_size}};
+%% dbg options ( = not documented):
+chann_info(pid, C) ->
+ C#channel.user.
+%%%----------------------------------------------------------------
+%% Assisting meta function for the *_info functions
+fold_keys(Keys, Fun, Extra) ->
+ lists:foldr(fun(Key, Acc) ->
+ try Fun(Key, Extra) of
+ Value -> [{Key,Value}|Acc]
+ catch
+ _:_ -> Acc
+ end
+ end, [], Keys).
+%%%----------------------------------------------------------------
log_error(Reason) ->
Report = io_lib:format("Erlang ssh connection handler failed with reason:~n"
" ~p~n"
@@ -1686,7 +1686,6 @@ log_error(Reason) ->
[Reason, erlang:get_stacktrace()]),
error_logger:error_report(Report).
-
%%%----------------------------------------------------------------
not_connected_filter({connection_reply, _Data}) -> true;
not_connected_filter(_) -> false.
--
cgit v1.2.3
From 50aa639c4c3398c40fdce514e45ce687aa189189 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Tue, 28 Jun 2016 16:57:51 +0200
Subject: ssh: Remove possible hanging in TCs when server and client is on the
same node
---
lib/ssh/src/ssh_connection_handler.erl | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index f825f0fae2..5e05188e7f 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -1206,8 +1206,9 @@ handle_event(internal, prepare_next_packet, _, D) ->
Sz when Sz >= Enough ->
self() ! {D#data.transport_protocol, D#data.socket, <<>>};
_ ->
- inet:setopts(D#data.socket, [{active, once}])
+ ok
end,
+ inet:setopts(D#data.socket, [{active, once}]),
keep_state_and_data;
handle_event(info, {CloseTag,Socket}, StateName,
--
cgit v1.2.3
From 3dca3e5732b8fe02531f17a6fb25ca513f75ed4c Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 29 Jun 2016 13:36:01 +0200
Subject: ssh: Update ssh version
---
lib/ssh/vsn.mk | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index b165928877..575c1af3a9 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,5 +1,5 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 4.3
+SSH_VSN = 4.3.1
APP_VSN = "ssh-$(SSH_VSN)"
--
cgit v1.2.3
From 9517c37a8c2319be620d304db0d5b11d398057be Mon Sep 17 00:00:00 2001
From: Erlang/OTP
Date: Wed, 29 Jun 2016 17:43:27 +0200
Subject: Update release notes
---
lib/ssh/doc/src/notes.xml | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index fd15c334a3..ef6ee79654 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -30,6 +30,30 @@
notes.xml
+Ssh 4.3.1
+
+ Fixed Bugs and Malfunctions
+
+ -
+
+ SSH client does not any longer retry a bad password given
+ as option to ssh:connect et al.
+
+ Own Id: OTP-13674 Aux Id: TR-HU92273
+
+ -
+
+ Removed possible hanging risk for a certain timing
+ sequence when communicating client and server executes on
+ the same node.
+
+ Own Id: OTP-13715
+
+
+
+
+
+
Ssh 4.3
Improvements and New Features
--
cgit v1.2.3
From adf04d0c3dbb20e539892a1262078eb5a6538c97 Mon Sep 17 00:00:00 2001
From: Raimo Niskanen
Date: Mon, 25 Jul 2016 15:41:19 +0200
Subject: Rewrite SSH for gen_statem M:callback_mode/0
---
lib/ssh/src/ssh_connection_handler.erl | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index f9f4c82351..dcb6ff9343 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -60,7 +60,8 @@
]).
%%% Behaviour callbacks
--export([handle_event/4, terminate/3, format_status/2, code_change/4]).
+-export([callback_mode/0, handle_event/4, terminate/3,
+ format_status/2, code_change/4]).
%%% Exports not intended to be used :). They are used for spawning and tests
-export([init_connection_handler/3, % proc_lib:spawn needs this
@@ -374,14 +375,12 @@ init_connection_handler(Role, Socket, Opts) ->
S ->
gen_statem:enter_loop(?MODULE,
[], %%[{debug,[trace,log,statistics,debug]} || Role==server],
- handle_event_function,
{hello,Role},
S)
catch
_:Error ->
gen_statem:enter_loop(?MODULE,
[],
- handle_event_function,
{init_error,Error},
S0)
end.
@@ -504,6 +503,9 @@ init_ssh_record(Role, Socket, Opts) ->
%%% ######## Error in the initialisation ####
+callback_mode() ->
+ handle_event_function.
+
handle_event(_, _Event, {init_error,Error}, _) ->
case Error of
{badmatch,{error,enotconn}} ->
@@ -1401,12 +1403,12 @@ fmt_stat_rec(FieldNames, Rec, Exclude) ->
state_name(),
#data{},
term()
- ) -> {gen_statem:callback_mode(), state_name(), #data{}}.
+ ) -> {ok, state_name(), #data{}}.
%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
code_change(_OldVsn, StateName, State, _Extra) ->
- {handle_event_function, StateName, State}.
+ {ok, StateName, State}.
%%====================================================================
--
cgit v1.2.3
From f97b1d8914b54ac6c9202db4298ef5618e6a9d14 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Tue, 2 Aug 2016 09:29:58 +0200
Subject: ssh: update version number
---
lib/ssh/vsn.mk | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index dc5e7092f8..c62faf8357 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,5 +1,5 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 4.2.2.1
+SSH_VSN = 4.2.2.2
APP_VSN = "ssh-$(SSH_VSN)"
--
cgit v1.2.3
From 63b3d3a4d5afbf73f215cd343b9a84591d520d72 Mon Sep 17 00:00:00 2001
From: Lukas Larsson
Date: Fri, 29 Apr 2016 15:56:09 +0200
Subject: ssh: sshc_sup to use worker for ssh_con_handler
---
lib/ssh/src/sshc_sup.erl | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/sshc_sup.erl b/lib/ssh/src/sshc_sup.erl
index 8ee6aacfb5..b8275ba1eb 100644
--- a/lib/ssh/src/sshc_sup.erl
+++ b/lib/ssh/src/sshc_sup.erl
@@ -64,7 +64,7 @@ child_spec(_) ->
Name = undefined, % As simple_one_for_one is used.
StartFunc = {ssh_connection_handler, start_link, []},
Restart = temporary,
- Shutdown = infinity,
+ Shutdown = 4000,
Modules = [ssh_connection_handler],
- Type = supervisor,
+ Type = worker,
{Name, StartFunc, Restart, Shutdown, Type, Modules}.
--
cgit v1.2.3
From d732b4b8abfe59d1ac5ec475633ca08501341a49 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 4 Aug 2016 15:53:48 +0200
Subject: ssh: update test suite for supervisors
---
lib/ssh/test/ssh_sup_SUITE.erl | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_sup_SUITE.erl b/lib/ssh/test/ssh_sup_SUITE.erl
index 18e91a9af3..98441e0046 100644
--- a/lib/ssh/test/ssh_sup_SUITE.erl
+++ b/lib/ssh/test/ssh_sup_SUITE.erl
@@ -105,16 +105,16 @@ sshc_subtree(Config) when is_list(Config) ->
{ok, Pid1} = ssh:connect(Host, Port, [{silently_accept_hosts, true},
{user_interaction, false},
{user, ?USER}, {password, ?PASSWD},{user_dir, UserDir}]),
- [{_, _,supervisor,[ssh_connection_handler]}] =
+ [{_, _,worker,[ssh_connection_handler]}] =
supervisor:which_children(sshc_sup),
{ok, Pid2} = ssh:connect(Host, Port, [{silently_accept_hosts, true},
{user_interaction, false},
{user, ?USER}, {password, ?PASSWD}, {user_dir, UserDir}]),
- [{_,_,supervisor,[ssh_connection_handler]},
- {_,_,supervisor,[ssh_connection_handler]}] =
+ [{_,_,worker,[ssh_connection_handler]},
+ {_,_,worker,[ssh_connection_handler]}] =
supervisor:which_children(sshc_sup),
ssh:close(Pid1),
- [{_,_,supervisor,[ssh_connection_handler]}] =
+ [{_,_,worker,[ssh_connection_handler]}] =
supervisor:which_children(sshc_sup),
ssh:close(Pid2),
ct:sleep(?WAIT_FOR_SHUTDOWN),
--
cgit v1.2.3
From dd9502f0f3e72809760be2a00acc67080180c6a1 Mon Sep 17 00:00:00 2001
From: Erlang/OTP
Date: Thu, 4 Aug 2016 16:09:09 +0200
Subject: Update release notes
---
lib/ssh/doc/src/notes.xml | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index 00a8bceb4a..4764d9ffe6 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -30,6 +30,23 @@
notes.xml
+Ssh 4.2.2.2
+
+ Fixed Bugs and Malfunctions
+
+ -
+
+ Upgrade of an established client connection could crash
+ because the ssh client supervisors children had wrong
+ type. This is fixed now.
+
+ Own Id: OTP-13782 Aux Id: seq13158
+
+
+
+
+
+
Ssh 4.2.2.1
Fixed Bugs and Malfunctions
--
cgit v1.2.3
From 6f15ceab49bf106bd023cad3ddec6af50235dd42 Mon Sep 17 00:00:00 2001
From: Aleksei Magusev
Date: Tue, 23 Aug 2016 00:44:10 +0200
Subject: Improve ssh:start/1,2 functions
Use application:ensure_all_started/2 instead of hard-coding dependencies
---
lib/ssh/src/ssh.erl | 123 ++++++++++++++++++++++++++--------------------------
1 file changed, 61 insertions(+), 62 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 0570853a9b..1d7be3547b 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -52,16 +52,15 @@
%% is temporary. see application(3)
%%--------------------------------------------------------------------
start() ->
- application:start(crypto),
- application:start(asn1),
- application:start(public_key),
- application:start(ssh).
+ start(temporary).
start(Type) ->
- application:start(crypto, Type),
- application:start(asn1),
- application:start(public_key, Type),
- application:start(ssh, Type).
+ case application:ensure_all_started(ssh, Type) of
+ {ok, _} ->
+ ok;
+ Other ->
+ Other
+ end.
%%--------------------------------------------------------------------
-spec stop() -> ok | {error, term()}.
@@ -90,7 +89,7 @@ connect(Socket, Options, Timeout) when is_port(Socket) ->
{error, Error};
{_SocketOptions, SshOptions} ->
case valid_socket_to_use(Socket, Options) of
- ok ->
+ ok ->
{ok, {Host,_Port}} = inet:sockname(Socket),
Opts = [{user_pid,self()}, {host,fmt_host(Host)} | SshOptions],
ssh_connection_handler:start_connection(client, Socket, Opts, Timeout);
@@ -128,23 +127,23 @@ connect(Host, Port, Options, Timeout) ->
-spec close(pid()) -> ok.
%%
%% Description: Closes an ssh connection.
-%%--------------------------------------------------------------------
+%%--------------------------------------------------------------------
close(ConnectionRef) ->
ssh_connection_handler:stop(ConnectionRef).
%%--------------------------------------------------------------------
-spec connection_info(pid(), [atom()]) -> [{atom(), term()}].
%%
-%% Description: Retrieves information about a connection.
-%%--------------------------------------------------------------------
+%% Description: Retrieves information about a connection.
+%%--------------------------------------------------------------------
connection_info(ConnectionRef, Options) ->
ssh_connection_handler:connection_info(ConnectionRef, Options).
%%--------------------------------------------------------------------
-spec channel_info(pid(), channel_id(), [atom()]) -> [{atom(), term()}].
%%
-%% Description: Retrieves information about a connection.
-%%--------------------------------------------------------------------
+%% Description: Retrieves information about a connection.
+%%--------------------------------------------------------------------
channel_info(ConnectionRef, ChannelId, Options) ->
ssh_connection_handler:channel_info(ConnectionRef, ChannelId, Options).
@@ -153,9 +152,9 @@ channel_info(ConnectionRef, ChannelId, Options) ->
-spec daemon(integer()|port(), proplists:proplist()) -> {ok, pid()} | {error, term()}.
-spec daemon(any | inet:ip_address(), integer(), proplists:proplist()) -> {ok, pid()} | {error, term()}.
-%% Description: Starts a server listening for SSH connections
+%% Description: Starts a server listening for SSH connections
%% on the given port.
-%%--------------------------------------------------------------------
+%%--------------------------------------------------------------------
daemon(Port) ->
daemon(Port, []).
@@ -188,9 +187,9 @@ daemon_info(Pid) ->
-spec stop_listener(pid()) -> ok.
-spec stop_listener(inet:ip_address(), integer()) -> ok.
%%
-%% Description: Stops the listener, but leaves
+%% Description: Stops the listener, but leaves
%% existing connections started by the listener up and running.
-%%--------------------------------------------------------------------
+%%--------------------------------------------------------------------
stop_listener(SysSup) ->
ssh_system_sup:stop_listener(SysSup).
stop_listener(Address, Port) ->
@@ -202,9 +201,9 @@ stop_listener(Address, Port, Profile) ->
-spec stop_daemon(pid()) -> ok.
-spec stop_daemon(inet:ip_address(), integer()) -> ok.
%%
-%% Description: Stops the listener and all connections started by
+%% Description: Stops the listener and all connections started by
%% the listener.
-%%--------------------------------------------------------------------
+%%--------------------------------------------------------------------
stop_daemon(SysSup) ->
ssh_system_sup:stop_system(SysSup).
stop_daemon(Address, Port) ->
@@ -243,7 +242,7 @@ start_shell({ok, ConnectionRef}) ->
case ssh_connection:session_channel(ConnectionRef, infinity) of
{ok,ChannelId} ->
success = ssh_connection:ptty_alloc(ConnectionRef, ChannelId, []),
- Args = [{channel_cb, ssh_shell},
+ Args = [{channel_cb, ssh_shell},
{init_args,[ConnectionRef, ChannelId]},
{cm, ConnectionRef}, {channel_id, ChannelId}],
{ok, State} = ssh_channel:init([Args]),
@@ -256,7 +255,7 @@ start_shell(Error) ->
%%--------------------------------------------------------------------
%%--------------------------------------------------------------------
-default_algorithms() ->
+default_algorithms() ->
ssh_transport:default_algorithms().
%%--------------------------------------------------------------------
@@ -296,13 +295,13 @@ daemon_shell_opt(Options) ->
daemon_host_inet_opt(HostAddr, Options1) ->
case HostAddr of
any ->
- {ok, Host0} = inet:gethostname(),
+ {ok, Host0} = inet:gethostname(),
{Host0, proplists:get_value(inet, Options1, inet), Options1};
{_,_,_,_} ->
- {HostAddr, inet,
+ {HostAddr, inet,
[{ip, HostAddr} | Options1]};
{_,_,_,_,_,_,_,_} ->
- {HostAddr, inet6,
+ {HostAddr, inet6,
[{ip, HostAddr} | Options1]}
end.
@@ -313,8 +312,8 @@ start_daemon(Socket, Options) ->
{error, Error};
{SocketOptions, SshOptions} ->
case valid_socket_to_use(Socket, Options) of
- ok ->
- try
+ ok ->
+ try
do_start_daemon(Socket, [{role,server}|SshOptions], SocketOptions)
catch
throw:bad_fd -> {error,bad_fd};
@@ -330,16 +329,16 @@ start_daemon(Host, Port, Options, Inet) ->
{error, _Reason} = Error ->
Error;
{SocketOptions, SshOptions}->
- try
+ try
do_start_daemon(Host, Port, [{role,server}|SshOptions] , [Inet|SocketOptions])
catch
throw:bad_fd -> {error,bad_fd};
_C:_E -> {error,{cannot_start_daemon,_C,_E}}
end
end.
-
+
do_start_daemon(Socket, SshOptions, SocketOptions) ->
- {ok, {IP,Port}} =
+ {ok, {IP,Port}} =
try {ok,_} = inet:sockname(Socket)
catch
_:_ -> throw(bad_socket)
@@ -351,7 +350,7 @@ do_start_daemon(Socket, SshOptions, SocketOptions) ->
{address, Host},
{port, Port},
{role, server},
- {socket_opts, SocketOptions},
+ {socket_opts, SocketOptions},
{ssh_opts, SshOptions}],
{_, Callback, _} = proplists:get_value(transport, SshOptions, {tcp, gen_tcp, tcp_closed}),
case ssh_system_sup:system_supervisor(Host, Port, Profile) of
@@ -385,7 +384,7 @@ do_start_daemon(Socket, SshOptions, SocketOptions) ->
end.
do_start_daemon(Host0, Port0, SshOptions, SocketOptions) ->
- {Host,Port1} =
+ {Host,Port1} =
try
case proplists:get_value(fd, SocketOptions) of
undefined ->
@@ -402,21 +401,21 @@ do_start_daemon(Host0, Port0, SshOptions, SocketOptions) ->
{Port, WaitRequestControl, Opts0} =
case Port1 of
0 -> %% Allocate the socket here to get the port number...
- {_, Callback, _} =
+ {_, Callback, _} =
proplists:get_value(transport, SshOptions, {tcp, gen_tcp, tcp_closed}),
{ok,LSock} = ssh_acceptor:callback_listen(Callback, 0, SocketOptions),
{ok,{_,LPort}} = inet:sockname(LSock),
- {LPort,
- {LSock,Callback},
+ {LPort,
+ {LSock,Callback},
[{lsocket,LSock},{lsock_owner,self()}]
};
_ ->
{Port1, false, []}
end,
- Opts = [{address, Host},
+ Opts = [{address, Host},
{port, Port},
{role, server},
- {socket_opts, SocketOptions},
+ {socket_opts, SocketOptions},
{ssh_opts, SshOptions} | Opts0],
case ssh_system_sup:system_supervisor(Host, Port, Profile) of
undefined ->
@@ -465,7 +464,7 @@ find_hostport(Fd) ->
{ok, HostPort} = inet:sockname(S),
ok = inet:close(S),
HostPort.
-
+
handle_options(Opts) ->
try handle_option(algs_compatibility(proplists:unfold(Opts)), [], []) of
@@ -480,9 +479,9 @@ handle_options(Opts) ->
algs_compatibility(Os0) ->
%% Take care of old options 'public_key_alg' and 'pref_public_key_algs'
case proplists:get_value(public_key_alg, Os0) of
- undefined ->
+ undefined ->
Os0;
- A when is_atom(A) ->
+ A when is_atom(A) ->
%% Skip public_key_alg if pref_public_key_algs is defined:
Os = lists:keydelete(public_key_alg, 1, Os0),
case proplists:get_value(pref_public_key_algs,Os) of
@@ -492,7 +491,7 @@ algs_compatibility(Os0) ->
[{pref_public_key_algs,['ssh-dss','ssh-rsa']} | Os];
undefined ->
throw({error, {eoptions, {public_key_alg,A} }});
- _ ->
+ _ ->
Os
end;
V ->
@@ -620,7 +619,7 @@ handle_ssh_option({silently_accept_hosts, Value} = Opt) when is_boolean(Value) -
Opt;
handle_ssh_option({user_interaction, Value} = Opt) when is_boolean(Value) ->
Opt;
-handle_ssh_option({preferred_algorithms,[_|_]} = Opt) ->
+handle_ssh_option({preferred_algorithms,[_|_]} = Opt) ->
handle_pref_algs(Opt);
handle_ssh_option({dh_gex_groups,L0}) when is_list(L0) ->
@@ -629,7 +628,7 @@ handle_ssh_option({dh_gex_groups,L0}) when is_list(L0) ->
lists:foldl(
fun({N,G,P}, Acc) when is_integer(N),N>0,
is_integer(G),G>0,
- is_integer(P),P>0 ->
+ is_integer(P),P>0 ->
[{N,{G,P}} | Acc];
({N,{G,P}}, Acc) when is_integer(N),N>0,
is_integer(G),G>0,
@@ -637,7 +636,7 @@ handle_ssh_option({dh_gex_groups,L0}) when is_list(L0) ->
[{N,{G,P}} | Acc];
({N,GPs}, Acc) when is_list(GPs) ->
lists:foldr(fun({Gi,Pi}, Acci) when is_integer(Gi),Gi>0,
- is_integer(Pi),Pi>0 ->
+ is_integer(Pi),Pi>0 ->
[{N,{Gi,Pi}} | Acci]
end, Acc, GPs)
end, [], L0))};
@@ -647,7 +646,7 @@ handle_ssh_option({dh_gex_groups,{Tag,File=[C|_]}}=Opt) when is_integer(C), C>0,
Tag == ssh_moduli_file ->
{ok,GroupDefs} =
case Tag of
- file ->
+ file ->
file:consult(File);
ssh_moduli_file ->
case file:open(File,[read]) of
@@ -672,14 +671,14 @@ handle_ssh_option({dh_gex_groups,{Tag,File=[C|_]}}=Opt) when is_integer(C), C>0,
catch
_:_ ->
throw({error, {{eoptions, Opt}, "Bad format in file: "++File}})
- end;
-
+ end;
+
-handle_ssh_option({dh_gex_limits,{Min,Max}} = Opt) when is_integer(Min), Min>0,
+handle_ssh_option({dh_gex_limits,{Min,Max}} = Opt) when is_integer(Min), Min>0,
is_integer(Max), Max>=Min ->
%% Server
Opt;
-handle_ssh_option({dh_gex_limits,{Min,I,Max}} = Opt) when is_integer(Min), Min>0,
+handle_ssh_option({dh_gex_limits,{Min,I,Max}} = Opt) when is_integer(Min), Min>0,
is_integer(I), I>=Min,
is_integer(Max), Max>=I ->
%% Client
@@ -724,7 +723,7 @@ handle_ssh_option({keyboard_interact_fun, Value} = Opt) when is_function(Value,3
Opt;
handle_ssh_option({compression, Value} = Opt) when is_atom(Value) ->
Opt;
-handle_ssh_option({exec, {Module, Function, _}} = Opt) when is_atom(Module),
+handle_ssh_option({exec, {Module, Function, _}} = Opt) when is_atom(Module),
is_atom(Function) ->
Opt;
handle_ssh_option({exec, Function} = Opt) when is_function(Function) ->
@@ -772,7 +771,7 @@ handle_ssh_option({quiet_mode, Value} = Opt) when is_boolean(Value) ->
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) ->
+handle_ssh_option({rekey_limit, Value} = Opt) when is_integer(Value) ->
Opt;
handle_ssh_option({id_string, random}) ->
{id_string, {random,2,5}}; %% 2 - 5 random characters
@@ -814,11 +813,11 @@ handle_pref_algs({preferred_algorithms,Algs}) ->
of
DefAlgs -> handle_pref_alg(Key,Vals,DefAlgs)
catch
- _:_ -> throw({error, {{eoptions, {preferred_algorithms,Key}},
+ _:_ -> throw({error, {{eoptions, {preferred_algorithms,Key}},
"Bad preferred_algorithms key"}})
end || {Key,Vals} <- Algs]
};
-
+
Dups ->
throw({error, {{eoptions, {preferred_algorithms,Dups}}, "Duplicates found"}})
catch
@@ -857,13 +856,13 @@ handle_pref_alg(Key,
) ->
handle_pref_alg(Key, lists:reverse(Vs), Sup);
-handle_pref_alg(Key,
+handle_pref_alg(Key,
Vs=[V|_],
Sup=[{client2server,_},{server2client,_}]
) when is_atom(V) ->
handle_pref_alg(Key, [{client2server,Vs},{server2client,Vs}], Sup);
-handle_pref_alg(Key,
+handle_pref_alg(Key,
Vs=[V|_],
Sup=[S|_]
) when is_atom(V), is_atom(S) ->
@@ -878,14 +877,14 @@ chk_alg_vs(OptKey, Values, SupportedValues) ->
[] -> Values;
Bad -> throw({error, {{eoptions, {OptKey,Bad}}, "Unsupported value(s) found"}})
end.
-
+
handle_ip(Inet) -> %% Default to ipv4
case lists:member(inet, Inet) of
true ->
Inet;
false ->
case lists:member(inet6, Inet) of
- true ->
+ true ->
Inet;
false ->
[inet | Inet]
@@ -916,8 +915,8 @@ directory_exist_readable(Dir) ->
{error, Error} ->
{error, Error}
end.
-
-
+
+
collect_per_size(L) ->
lists:foldr(
@@ -948,7 +947,7 @@ read_moduli_file(D, I, Acc) ->
read_moduli_file(D, I+1, Acc)
end
end.
-
+
handle_user_pref_pubkey_algs([], Acc) ->
{true, lists:reverse(Acc)};
handle_user_pref_pubkey_algs([H|T], Acc) ->
@@ -963,7 +962,7 @@ handle_user_pref_pubkey_algs([H|T], Acc) ->
false
end.
-fmt_host({A,B,C,D}) ->
+fmt_host({A,B,C,D}) ->
lists:concat([A,".",B,".",C,".",D]);
-fmt_host(T={_,_,_,_,_,_,_,_}) ->
+fmt_host(T={_,_,_,_,_,_,_,_}) ->
lists:flatten(string:join([io_lib:format("~.16B",[A]) || A <- tuple_to_list(T)], ":")).
--
cgit v1.2.3
From cd1ca5e2dd8dde12a33ab7d4ffb9524d7f141fa7 Mon Sep 17 00:00:00 2001
From: Raimo Niskanen
Date: Thu, 25 Aug 2016 14:18:24 +0200
Subject: Fix version numbers and dependencies
---
lib/ssh/src/ssh.app.src | 2 +-
lib/ssh/vsn.mk | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh.app.src b/lib/ssh/src/ssh.app.src
index 3245ba5197..76b7d8cd55 100644
--- a/lib/ssh/src/ssh.app.src
+++ b/lib/ssh/src/ssh.app.src
@@ -45,7 +45,7 @@
"erts-6.0",
"kernel-3.0",
"public_key-1.1",
- "stdlib-3.0"
+ "stdlib-3.1"
]}]}.
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index 575c1af3a9..212b99c695 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,5 +1,5 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 4.3.1
+SSH_VSN = 4.3.2
APP_VSN = "ssh-$(SSH_VSN)"
--
cgit v1.2.3
From 912f701dde1aa24e81de6fa37dfec5de8f8c989d Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 29 Aug 2016 12:49:22 +0200
Subject: ssh: fix changed badmatch error msg in ssh_algorithms_SUITE
---
lib/ssh/test/ssh_algorithms_SUITE.erl | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_algorithms_SUITE.erl b/lib/ssh/test/ssh_algorithms_SUITE.erl
index 0f68130a05..8b2db0e1a8 100644
--- a/lib/ssh/test/ssh_algorithms_SUITE.erl
+++ b/lib/ssh/test/ssh_algorithms_SUITE.erl
@@ -180,21 +180,19 @@ simple_exec(Config) ->
%%--------------------------------------------------------------------
%% Testing if no group matches
simple_exec_groups_no_match_too_small(Config) ->
- try simple_exec_group({400,500,600}, Config)
- of
- _ -> ct:fail("Exec though no group available")
- catch
- error:{badmatch,{error,"No possible diffie-hellman-group-exchange group found"}} ->
- ok
- end.
+ try_exec_simple_group({400,500,600}, Config).
simple_exec_groups_no_match_too_large(Config) ->
- try simple_exec_group({9200,9500,9700}, Config)
+ try_exec_simple_group({9200,9500,9700}, Config).
+
+
+try_exec_simple_group(Group, Config) ->
+ try simple_exec_group(Group, Config)
of
_ -> ct:fail("Exec though no group available")
catch
- error:{badmatch,{error,"No possible diffie-hellman-group-exchange group found"}} ->
- ok
+ error:{badmatch,{error,"No possible diffie-hellman-group-exchange group found"}} -> ok;
+ error:{badmatch,{error,"Connection closed"}} -> ok
end.
%%--------------------------------------------------------------------
--
cgit v1.2.3
From 85fc9764cee4ba48bb6cac71efc400415508e0d0 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 29 Aug 2016 13:07:57 +0200
Subject: ssh: fix Codenomicon/Defensics auth problem with incomplete pdu
Trailing pdu values being 0 or empty strings are just excluded from the pdu
by Codenomicon/Defensics.
This is wrong but some kind of habit "out there". This commit makes Erlang SSH
accept such pdu in one place because Defensics is king of security tests ...
---
lib/ssh/src/ssh_auth.erl | 21 ++++++++++++++++-----
1 file changed, 16 insertions(+), 5 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl
index fb5e086656..1dcf5d0708 100644
--- a/lib/ssh/src/ssh_auth.erl
+++ b/lib/ssh/src/ssh_auth.erl
@@ -264,12 +264,23 @@ handle_userauth_request(#ssh_msg_userauth_request{user = User,
SessionId,
#ssh{opts = Opts,
userauth_supported_methods = Methods} = Ssh) ->
- <> = Data,
- Alg = binary_to_list(BAlg),
+
+ <> = Data,
+
+ {KeyBlob, SigWLen} =
+ case Rest of
+ <> ->
+ {KeyBlob0, SigWLen0};
+ <<>> ->
+ {<<>>, <<>>}
+ end,
+
case HaveSig of
?TRUE ->
- case verify_sig(SessionId, User, "ssh-connection", Alg,
+ case verify_sig(SessionId, User, "ssh-connection",
+ binary_to_list(BAlg),
KeyBlob, SigWLen, Opts) of
true ->
{authorized, User,
@@ -284,7 +295,7 @@ handle_userauth_request(#ssh_msg_userauth_request{user = User,
?FALSE ->
{not_authorized, {User, undefined},
ssh_transport:ssh_packet(
- #ssh_msg_userauth_pk_ok{algorithm_name = Alg,
+ #ssh_msg_userauth_pk_ok{algorithm_name = binary_to_list(BAlg),
key_blob = KeyBlob}, Ssh)}
end;
--
cgit v1.2.3
From 28baf1314b556bb592c24181f6967e1f324f44a7 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 18 Aug 2016 13:28:00 +0200
Subject: ssh: Add non-blocking send
This is to try to fix ssh_connection_SUITE:interrupted_send problem. On machines with small buffers (<65k) like some Windows and *BSDs, this test case could deadlock with both sides having filled tcp receice buffers but stuck in prim_inet:send. This commit fixes this.
---
lib/ssh/src/ssh_connection_handler.erl | 92 +++++++++++++++++++++-------------
1 file changed, 58 insertions(+), 34 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index dcb6ff9343..2eb29c9b32 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -339,6 +339,7 @@ renegotiate_data(ConnectionHandler) ->
ssh_params :: #ssh{}
| undefined,
socket :: inet:socket(),
+ sender :: pid() | undefined,
decrypted_data_buffer = <<>> :: binary(),
encrypted_data_buffer = <<>> :: binary(),
undecrypted_packet_length :: undefined | non_neg_integer(),
@@ -367,9 +368,10 @@ init_connection_handler(Role, Socket, Opts) ->
{Protocol, Callback, CloseTag} =
proplists:get_value(transport, Opts, ?DefaultTransport),
S0#data{ssh_params = init_ssh_record(Role, Socket, Opts),
- transport_protocol = Protocol,
- transport_cb = Callback,
- transport_close_tag = CloseTag
+ sender = spawn_link(fun() -> nonblocking_sender(Socket, Callback) end),
+ transport_protocol = Protocol,
+ transport_cb = Callback,
+ transport_close_tag = CloseTag
}
of
S ->
@@ -525,7 +527,7 @@ handle_event(_, _Event, {init_error,Error}, _) ->
%% The very first event that is sent when the we are set as controlling process of Socket
handle_event(_, socket_control, {hello,_}, D) ->
VsnMsg = ssh_transport:hello_version_msg(string_version(D#data.ssh_params)),
- ok = send_bytes(VsnMsg, D),
+ send_bytes(VsnMsg, D),
case inet:getopts(Socket=D#data.socket, [recbuf]) of
{ok, [{recbuf,Size}]} ->
%% Set the socket to the hello text line handling mode:
@@ -550,7 +552,7 @@ handle_event(_, {info_line,_Line}, {hello,Role}, D) ->
server ->
%% But the client may NOT send them to the server. Openssh answers with cleartext,
%% and so do we
- ok = send_bytes("Protocol mismatch.", D),
+ send_bytes("Protocol mismatch.", D),
{stop, {shutdown,"Protocol mismatch in version exchange. Client sent info lines."}}
end;
@@ -565,7 +567,7 @@ handle_event(_, {version_exchange,Version}, {hello,Role}, D) ->
{active, once},
{recbuf, D#data.inet_initial_recbuf_size}]),
{KeyInitMsg, SshPacket, Ssh} = ssh_transport:key_exchange_init_msg(Ssh1),
- ok = send_bytes(SshPacket, D),
+ send_bytes(SshPacket, D),
{next_state, {kexinit,Role,init}, D#data{ssh_params = Ssh,
key_exchange_init_msg = KeyInitMsg}};
not_supported ->
@@ -583,7 +585,7 @@ handle_event(_, {#ssh_msg_kexinit{}=Kex, Payload}, {kexinit,Role,ReNeg},
Ssh1 = ssh_transport:key_init(peer_role(Role), D#data.ssh_params, Payload),
Ssh = case ssh_transport:handle_kexinit_msg(Kex, OwnKex, Ssh1) of
{ok, NextKexMsg, Ssh2} when Role==client ->
- ok = send_bytes(NextKexMsg, D),
+ send_bytes(NextKexMsg, D),
Ssh2;
{ok, Ssh2} when Role==server ->
Ssh2
@@ -596,43 +598,43 @@ handle_event(_, {#ssh_msg_kexinit{}=Kex, Payload}, {kexinit,Role,ReNeg},
%%%---- diffie-hellman
handle_event(_, #ssh_msg_kexdh_init{} = Msg, {key_exchange,server,ReNeg}, D) ->
{ok, KexdhReply, Ssh1} = ssh_transport:handle_kexdh_init(Msg, D#data.ssh_params),
- ok = send_bytes(KexdhReply, D),
+ send_bytes(KexdhReply, D),
{ok, NewKeys, Ssh} = ssh_transport:new_keys_message(Ssh1),
- ok = send_bytes(NewKeys, D),
+ send_bytes(NewKeys, D),
{next_state, {new_keys,server,ReNeg}, D#data{ssh_params=Ssh}};
handle_event(_, #ssh_msg_kexdh_reply{} = Msg, {key_exchange,client,ReNeg}, D) ->
{ok, NewKeys, Ssh} = ssh_transport:handle_kexdh_reply(Msg, D#data.ssh_params),
- ok = send_bytes(NewKeys, D),
+ send_bytes(NewKeys, D),
{next_state, {new_keys,client,ReNeg}, D#data{ssh_params=Ssh}};
%%%---- diffie-hellman group exchange
handle_event(_, #ssh_msg_kex_dh_gex_request{} = Msg, {key_exchange,server,ReNeg}, D) ->
{ok, GexGroup, Ssh} = ssh_transport:handle_kex_dh_gex_request(Msg, D#data.ssh_params),
- ok = send_bytes(GexGroup, D),
+ send_bytes(GexGroup, D),
{next_state, {key_exchange_dh_gex_init,server,ReNeg}, D#data{ssh_params=Ssh}};
handle_event(_, #ssh_msg_kex_dh_gex_request_old{} = Msg, {key_exchange,server,ReNeg}, D) ->
{ok, GexGroup, Ssh} = ssh_transport:handle_kex_dh_gex_request(Msg, D#data.ssh_params),
- ok = send_bytes(GexGroup, D),
+ send_bytes(GexGroup, D),
{next_state, {key_exchange_dh_gex_init,server,ReNeg}, D#data{ssh_params=Ssh}};
handle_event(_, #ssh_msg_kex_dh_gex_group{} = Msg, {key_exchange,client,ReNeg}, D) ->
{ok, KexGexInit, Ssh} = ssh_transport:handle_kex_dh_gex_group(Msg, D#data.ssh_params),
- ok = send_bytes(KexGexInit, D),
+ send_bytes(KexGexInit, D),
{next_state, {key_exchange_dh_gex_reply,client,ReNeg}, D#data{ssh_params=Ssh}};
%%%---- elliptic curve diffie-hellman
handle_event(_, #ssh_msg_kex_ecdh_init{} = Msg, {key_exchange,server,ReNeg}, D) ->
{ok, KexEcdhReply, Ssh1} = ssh_transport:handle_kex_ecdh_init(Msg, D#data.ssh_params),
- ok = send_bytes(KexEcdhReply, D),
+ send_bytes(KexEcdhReply, D),
{ok, NewKeys, Ssh} = ssh_transport:new_keys_message(Ssh1),
- ok = send_bytes(NewKeys, D),
+ send_bytes(NewKeys, D),
{next_state, {new_keys,server,ReNeg}, D#data{ssh_params=Ssh}};
handle_event(_, #ssh_msg_kex_ecdh_reply{} = Msg, {key_exchange,client,ReNeg}, D) ->
{ok, NewKeys, Ssh} = ssh_transport:handle_kex_ecdh_reply(Msg, D#data.ssh_params),
- ok = send_bytes(NewKeys, D),
+ send_bytes(NewKeys, D),
{next_state, {new_keys,client,ReNeg}, D#data{ssh_params=Ssh}};
@@ -640,9 +642,9 @@ handle_event(_, #ssh_msg_kex_ecdh_reply{} = Msg, {key_exchange,client,ReNeg}, D)
handle_event(_, #ssh_msg_kex_dh_gex_init{} = Msg, {key_exchange_dh_gex_init,server,ReNeg}, D) ->
{ok, KexGexReply, Ssh1} = ssh_transport:handle_kex_dh_gex_init(Msg, D#data.ssh_params),
- ok = send_bytes(KexGexReply, D),
+ send_bytes(KexGexReply, D),
{ok, NewKeys, Ssh} = ssh_transport:new_keys_message(Ssh1),
- ok = send_bytes(NewKeys, D),
+ send_bytes(NewKeys, D),
{next_state, {new_keys,server,ReNeg}, D#data{ssh_params=Ssh}};
@@ -650,7 +652,7 @@ handle_event(_, #ssh_msg_kex_dh_gex_init{} = Msg, {key_exchange_dh_gex_init,serv
handle_event(_, #ssh_msg_kex_dh_gex_reply{} = Msg, {key_exchange_dh_gex_reply,client,ReNeg}, D) ->
{ok, NewKeys, Ssh1} = ssh_transport:handle_kex_dh_gex_reply(Msg, D#data.ssh_params),
- ok = send_bytes(NewKeys, D),
+ send_bytes(NewKeys, D),
{next_state, {new_keys,client,ReNeg}, D#data{ssh_params=Ssh1}};
@@ -662,7 +664,7 @@ handle_event(_, #ssh_msg_newkeys{} = Msg, {new_keys,Role,init}, D) ->
Ssh = case Role of
client ->
{MsgReq, Ssh2} = ssh_auth:service_request_msg(Ssh1),
- ok = send_bytes(MsgReq, D),
+ send_bytes(MsgReq, D),
Ssh2;
server ->
Ssh1
@@ -680,7 +682,7 @@ handle_event(_, Msg = #ssh_msg_service_request{name=ServiceName}, StateName = {s
"ssh-userauth" ->
Ssh0 = #ssh{session_id=SessionId} = D#data.ssh_params,
{ok, {Reply, Ssh}} = ssh_auth:handle_userauth_request(Msg, SessionId, Ssh0),
- ok = send_bytes(Reply, D),
+ send_bytes(Reply, D),
{next_state, {userauth,server}, D#data{ssh_params = Ssh}};
_ ->
@@ -692,7 +694,7 @@ handle_event(_, Msg = #ssh_msg_service_request{name=ServiceName}, StateName = {s
handle_event(_, #ssh_msg_service_accept{name = "ssh-userauth"}, {service_request,client},
#data{ssh_params = #ssh{service="ssh-userauth"} = Ssh0} = State) ->
{Msg, Ssh} = ssh_auth:init_userauth_request_msg(Ssh0),
- ok = send_bytes(Msg, State),
+ send_bytes(Msg, State),
{next_state, {userauth,client}, State#data{auth_user = Ssh#ssh.user, ssh_params = Ssh}};
@@ -709,7 +711,7 @@ handle_event(_,
%% Probably the very first userauth_request but we deny unauthorized login
{not_authorized, _, {Reply,Ssh}} =
ssh_auth:handle_userauth_request(Msg, Ssh0#ssh.session_id, Ssh0),
- ok = send_bytes(Reply, D),
+ send_bytes(Reply, D),
{keep_state, D#data{ssh_params = Ssh}};
{"ssh-connection", "ssh-connection", Method} ->
@@ -719,7 +721,7 @@ handle_event(_,
%% Yepp! we support this method
case ssh_auth:handle_userauth_request(Msg, Ssh0#ssh.session_id, Ssh0) of
{authorized, User, {Reply, Ssh}} ->
- ok = send_bytes(Reply, D),
+ send_bytes(Reply, D),
D#data.starter ! ssh_connected,
connected_fun(User, Method, D),
{next_state, {connected,server},
@@ -727,11 +729,11 @@ handle_event(_,
ssh_params = Ssh#ssh{authenticated = true}}};
{not_authorized, {User, Reason}, {Reply, Ssh}} when Method == "keyboard-interactive" ->
retry_fun(User, Reason, D),
- ok = send_bytes(Reply, D),
+ send_bytes(Reply, D),
{next_state, {userauth_keyboard_interactive,server}, D#data{ssh_params = Ssh}};
{not_authorized, {User, Reason}, {Reply, Ssh}} ->
retry_fun(User, Reason, D),
- ok = send_bytes(Reply, D),
+ send_bytes(Reply, D),
{keep_state, D#data{ssh_params = Ssh}}
end;
false ->
@@ -1430,18 +1432,15 @@ start_the_connection_child(UserPid, Role, Socket, Options) ->
%% Stopping
-type finalize_termination_result() :: ok .
-finalize_termination(_StateName, #data{transport_cb = Transport,
- connection_state = Connection,
- socket = Socket}) ->
- case Connection of
+finalize_termination(_StateName, D) ->
+ case D#data.connection_state of
#connection{system_supervisor = SysSup,
sub_system_supervisor = SubSysSup} when is_pid(SubSysSup) ->
ssh_system_sup:stop_subsystem(SysSup, SubSysSup);
_ ->
do_nothing
end,
- (catch Transport:close(Socket)),
- ok.
+ close_transport(D).
%%--------------------------------------------------------------------
%% "Invert" the Role
@@ -1496,8 +1495,33 @@ send_msg(Msg, State=#data{ssh_params=Ssh0}) when is_tuple(Msg) ->
send_bytes(Bytes, State),
State#data{ssh_params=Ssh}.
-send_bytes(Bytes, #data{socket = Socket, transport_cb = Transport}) ->
- Transport:send(Socket, Bytes).
+send_bytes(Bytes, #data{sender = Sender}) ->
+ Sender ! {send,Bytes},
+ ok.
+
+close_transport(D) ->
+ D#data.sender ! close,
+ ok.
+
+
+nonblocking_sender(Socket, Callback) ->
+ receive
+ {send, Bytes} ->
+ case Callback:send(Socket, Bytes) of
+ ok ->
+ nonblocking_sender(Socket, Callback);
+ E = {error,_} ->
+ exit({shutdown,E})
+ end;
+
+ close ->
+ case Callback:close(Socket) of
+ ok ->
+ ok;
+ E = {error,_} ->
+ exit({shutdown,E})
+ end
+ end.
handle_version({2, 0} = NumVsn, StrVsn, Ssh0) ->
Ssh = counterpart_versions(NumVsn, StrVsn, Ssh0),
--
cgit v1.2.3
From 3430829486d4c2a2af32214107ba39f9028d7aa8 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 29 Aug 2016 17:20:37 +0200
Subject: ssh: reduce random padding to 15 bytes
This is to get rid of some warnings in Codenomicon/Defensics. It also speeds up the communications.
---
lib/ssh/src/ssh.hrl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh.hrl b/lib/ssh/src/ssh.hrl
index 868f3a9181..4cd91177f6 100644
--- a/lib/ssh/src/ssh.hrl
+++ b/lib/ssh/src/ssh.hrl
@@ -127,7 +127,7 @@
recv_sequence = 0,
keyex_key,
keyex_info,
- random_length_padding = 255, % From RFC 4253 section 6.
+ random_length_padding = 15, % From RFC 4253 section 6.
%% User auth
user,
--
cgit v1.2.3
From ad6e765bcd4f35a282ef00e38ed9129f3a5c1d83 Mon Sep 17 00:00:00 2001
From: Hans Bolinder
Date: Thu, 1 Sep 2016 14:32:27 +0200
Subject: doc: Correct errors introduced by Editorial changes
Fix some older errors as well.
---
lib/ssh/doc/src/ssh.xml | 6 +++---
lib/ssh/doc/src/ssh_app.xml | 4 ++--
lib/ssh/doc/src/ssh_channel.xml | 2 +-
3 files changed, 6 insertions(+), 6 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index e6c54d27bf..ef9f7cbd9b 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -4,7 +4,7 @@
@@ -769,7 +769,7 @@
Stops the ssh application.
For more information, see the application(3)
- manual page in kernel.
+ manual page in Kernel.
diff --git a/lib/ssh/doc/src/ssh_app.xml b/lib/ssh/doc/src/ssh_app.xml
index f6ce44c015..5cc4c24889 100644
--- a/lib/ssh/doc/src/ssh_app.xml
+++ b/lib/ssh/doc/src/ssh_app.xml
@@ -4,7 +4,7 @@
- 20122015
+ 20122016
Ericsson AB. All Rights Reserved.
@@ -203,7 +203,7 @@
Unicode support
Unicode filenames are supported if the emulator and the underlaying OS support it. See section DESCRIPTION in the
- file manual page in kernel for information about this subject.
+ file manual page in Kernel for information about this subject.
The shell and the cli both support unicode.
diff --git a/lib/ssh/doc/src/ssh_channel.xml b/lib/ssh/doc/src/ssh_channel.xml
index 907b0b3bec..7b598494f7 100644
--- a/lib/ssh/doc/src/ssh_channel.xml
+++ b/lib/ssh/doc/src/ssh_channel.xml
@@ -139,7 +139,7 @@
enters the ssh_channel process receive loop and become an
ssh_channel process. The process must have been started using
one of the start functions in proc_lib, see the proc_lib(3) manual page in stdlib.
+ marker="stdlib:proc_lib">proc_lib(3) manual page in STDLIB.
The user is responsible for any initialization of the process
and must call ssh_channel:init/1.
--
cgit v1.2.3
From 7fa1f7e973369dedd56f1be17d3b075d72ec0b60 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 1 Sep 2016 18:20:22 +0200
Subject: ssh: fix no detect of tcp close
---
lib/ssh/src/ssh_connection_handler.erl | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 2eb29c9b32..00bf1a3885 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -1238,9 +1238,12 @@ handle_event(internal, prepare_next_packet, _, D) ->
handle_event(info, {CloseTag,Socket}, StateName,
D = #data{socket = Socket,
transport_close_tag = CloseTag}) ->
- disconnect(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_BY_APPLICATION,
- description = "Connection closed"},
- StateName, D);
+ %% Simulate a disconnect from the peer
+ handle_event(info,
+ #ssh_msg_disconnect{code = ?SSH_DISCONNECT_BY_APPLICATION,
+ description = "Connection closed"},
+ StateName,
+ D);
handle_event(info, {timeout, {_, From} = Request}, _,
#data{connection_state = #connection{requests = Requests} = C0} = D) ->
--
cgit v1.2.3
From c4e9732c040966366e0719a62550f30e45fc01a3 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 1 Sep 2016 22:38:13 +0200
Subject: ssh: separate clauses for first and second pk auth msg
SSH sends the public key and user name twice. If we do not
check the validity of that pair at the first time, Codenomicon Defensics
will complain.
---
lib/ssh/src/ssh_auth.erl | 66 +++++++++++++++++++++++++-----------------------
1 file changed, 35 insertions(+), 31 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl
index 1dcf5d0708..7793d77f36 100644
--- a/lib/ssh/src/ssh_auth.erl
+++ b/lib/ssh/src/ssh_auth.erl
@@ -260,43 +260,45 @@ handle_userauth_request(#ssh_msg_userauth_request{user = User,
handle_userauth_request(#ssh_msg_userauth_request{user = User,
service = "ssh-connection",
method = "publickey",
- data = Data},
+ data = <>
+ },
SessionId,
#ssh{opts = Opts,
userauth_supported_methods = Methods} = Ssh) ->
- <> = Data,
-
- {KeyBlob, SigWLen} =
- case Rest of
- <> ->
- {KeyBlob0, SigWLen0};
- <<>> ->
- {<<>>, <<>>}
- end,
+ {not_authorized, {User, undefined},
+ ssh_transport:ssh_packet(
+ #ssh_msg_userauth_pk_ok{algorithm_name = binary_to_list(BAlg),
+ key_blob = KeyBlob}, Ssh)};
- case HaveSig of
- ?TRUE ->
- case verify_sig(SessionId, User, "ssh-connection",
- binary_to_list(BAlg),
- KeyBlob, SigWLen, Opts) of
- true ->
- {authorized, User,
- ssh_transport:ssh_packet(
- #ssh_msg_userauth_success{}, Ssh)};
- false ->
- {not_authorized, {User, undefined},
- ssh_transport:ssh_packet(#ssh_msg_userauth_failure{
- authentications = Methods,
- partial_success = false}, Ssh)}
- end;
- ?FALSE ->
- {not_authorized, {User, undefined},
+handle_userauth_request(#ssh_msg_userauth_request{user = User,
+ service = "ssh-connection",
+ method = "publickey",
+ data = <>
+ },
+ SessionId,
+ #ssh{opts = Opts,
+ userauth_supported_methods = Methods} = Ssh) ->
+
+ case verify_sig(SessionId, User, "ssh-connection",
+ binary_to_list(BAlg),
+ KeyBlob, SigWLen, Opts) of
+ true ->
+ {authorized, User,
ssh_transport:ssh_packet(
- #ssh_msg_userauth_pk_ok{algorithm_name = binary_to_list(BAlg),
- key_blob = KeyBlob}, Ssh)}
+ #ssh_msg_userauth_success{}, Ssh)};
+ false ->
+ {not_authorized, {User, undefined},
+ ssh_transport:ssh_packet(#ssh_msg_userauth_failure{
+ authentications = Methods,
+ partial_success = false}, Ssh)}
end;
handle_userauth_request(#ssh_msg_userauth_request{user = User,
@@ -484,6 +486,8 @@ get_password_option(Opts, User) ->
false -> proplists:get_value(password, Opts, false)
end.
+%%pre_verify_sig(SessionId, User, Service, Alg, KeyBlob, Opts) ->
+
verify_sig(SessionId, User, Service, Alg, KeyBlob, SigWLen, Opts) ->
{ok, Key} = decode_public_key_v2(KeyBlob, Alg),
KeyCb = proplists:get_value(key_cb, Opts, ssh_file),
--
cgit v1.2.3
From 9b988fa6edd9db2396ade2141e14f0fc7b68cfd2 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 1 Sep 2016 21:31:54 +0200
Subject: ssh: make ecdsa sha dependent on curve
Bug fix.
---
lib/ssh/src/ssh_auth.erl | 4 ++--
lib/ssh/src/ssh_transport.erl | 7 ++++++-
2 files changed, 8 insertions(+), 3 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl
index 1dcf5d0708..afc6ec5a56 100644
--- a/lib/ssh/src/ssh_auth.erl
+++ b/lib/ssh/src/ssh_auth.erl
@@ -140,7 +140,7 @@ publickey_msg([Alg, #ssh{user = User,
session_id = SessionId,
service = Service,
opts = Opts} = Ssh]) ->
- Hash = sha, %% Maybe option?!
+ Hash = ssh_transport:sha(Alg),
KeyCb = proplists:get_value(key_cb, Opts, ssh_file),
case KeyCb:user_key(Alg, Opts) of
{ok, PrivKey} ->
@@ -495,7 +495,7 @@ verify_sig(SessionId, User, Service, Alg, KeyBlob, SigWLen, Opts) ->
<> = SigWLen,
<> = AlgSig,
- ssh_transport:verify(PlainText, sha, Sig, Key);
+ ssh_transport:verify(PlainText, ssh_transport:sha(list_to_atom(Alg)), Sig, Key);
false ->
false
end.
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 7cb3b75ac0..15b80de30a 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -46,7 +46,7 @@
handle_kex_ecdh_reply/2,
extract_public_key/1,
ssh_packet/2, pack/2,
- sign/3, verify/4]).
+ sha/1, sign/3, verify/4]).
%%% For test suites
-export([pack/3]).
@@ -1619,6 +1619,11 @@ kex_h(SSH, Key, Min, NBits, Max, Prime, Gen, E, F, K) ->
crypto:hash(sha((SSH#ssh.algorithms)#alg.kex), L).
+sha('ssh-rsa') -> sha;
+sha('ssh-dss') -> sha;
+sha('ecdsa-sha2-nistp256') -> sha(secp256r1);
+sha('ecdsa-sha2-nistp384') -> sha(secp384r1);
+sha('ecdsa-sha2-nistp521') -> sha(secp521r1);
sha(secp256r1) -> sha256;
sha(secp384r1) -> sha384;
sha(secp521r1) -> sha512;
--
cgit v1.2.3
From c0dfb5487a5ca79c35506905090b14e4abe06e3a Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 1 Sep 2016 22:52:04 +0200
Subject: ssh: pre-verify key
Conflicts:
lib/ssh/src/ssh_auth.erl
---
lib/ssh/src/ssh_auth.erl | 58 +++++++++++++++++++++++++++++++++---------------
1 file changed, 40 insertions(+), 18 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl
index 7793d77f36..0c1aaa2ede 100644
--- a/lib/ssh/src/ssh_auth.erl
+++ b/lib/ssh/src/ssh_auth.erl
@@ -266,14 +266,23 @@ handle_userauth_request(#ssh_msg_userauth_request{user = User,
_/binary
>>
},
- SessionId,
+ _SessionId,
#ssh{opts = Opts,
userauth_supported_methods = Methods} = Ssh) ->
- {not_authorized, {User, undefined},
- ssh_transport:ssh_packet(
- #ssh_msg_userauth_pk_ok{algorithm_name = binary_to_list(BAlg),
- key_blob = KeyBlob}, Ssh)};
+ case pre_verify_sig(User, binary_to_list(BAlg),
+ KeyBlob, Opts) of
+ true ->
+ {not_authorized, {User, undefined},
+ ssh_transport:ssh_packet(
+ #ssh_msg_userauth_pk_ok{algorithm_name = binary_to_list(BAlg),
+ key_blob = KeyBlob}, Ssh)};
+ false ->
+ {not_authorized, {User, undefined},
+ ssh_transport:ssh_packet(#ssh_msg_userauth_failure{
+ authentications = Methods,
+ partial_success = false}, Ssh)}
+ end;
handle_userauth_request(#ssh_msg_userauth_request{user = User,
service = "ssh-connection",
@@ -486,21 +495,34 @@ get_password_option(Opts, User) ->
false -> proplists:get_value(password, Opts, false)
end.
-%%pre_verify_sig(SessionId, User, Service, Alg, KeyBlob, Opts) ->
+pre_verify_sig(User, Alg, KeyBlob, Opts) ->
+ try
+ {ok, Key} = decode_public_key_v2(KeyBlob, Alg),
+ KeyCb = proplists:get_value(key_cb, Opts, ssh_file),
+ KeyCb:is_auth_key(Key, User, Opts)
+ catch
+ _:_ ->
+ false
+ end.
verify_sig(SessionId, User, Service, Alg, KeyBlob, SigWLen, Opts) ->
- {ok, Key} = decode_public_key_v2(KeyBlob, Alg),
- KeyCb = proplists:get_value(key_cb, Opts, ssh_file),
-
- case KeyCb:is_auth_key(Key, User, Opts) of
- true ->
- PlainText = build_sig_data(SessionId, User,
- Service, KeyBlob, Alg),
- <> = SigWLen,
- <> = AlgSig,
- ssh_transport:verify(PlainText, sha, Sig, Key);
- false ->
+ try
+ {ok, Key} = decode_public_key_v2(KeyBlob, Alg),
+ KeyCb = proplists:get_value(key_cb, Opts, ssh_file),
+
+ case KeyCb:is_auth_key(Key, User, Opts) of
+ true ->
+ PlainText = build_sig_data(SessionId, User,
+ Service, KeyBlob, Alg),
+ <> = SigWLen,
+ <> = AlgSig,
+ ssh_transport:verify(PlainText, ssh_transport:sha(list_to_atom(Alg)), Sig, Key);
+ false ->
+ false
+ end
+ catch
+ _:_ ->
false
end.
--
cgit v1.2.3
From df8da1d56961e999a43531b64a6f312b60da93d9 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 2 Sep 2016 14:55:58 +0200
Subject: ssh: add tstflg value one_empty to force daemon send empty
ssh_msg_userauth_info_request
This behavour is assumed by Codenomicon Defensics.
---
lib/ssh/src/ssh_auth.erl | 131 ++++++++++++++++++++++-----------
lib/ssh/src/ssh_connection_handler.erl | 14 +++-
lib/ssh/src/ssh_transport.erl | 7 +-
3 files changed, 106 insertions(+), 46 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl
index 1dcf5d0708..ac35b70209 100644
--- a/lib/ssh/src/ssh_auth.erl
+++ b/lib/ssh/src/ssh_auth.erl
@@ -140,7 +140,7 @@ publickey_msg([Alg, #ssh{user = User,
session_id = SessionId,
service = Service,
opts = Opts} = Ssh]) ->
- Hash = sha, %% Maybe option?!
+ Hash = ssh_transport:sha(Alg),
KeyCb = proplists:get_value(key_cb, Opts, ssh_file),
case KeyCb:user_key(Alg, Opts) of
{ok, PrivKey} ->
@@ -260,43 +260,54 @@ handle_userauth_request(#ssh_msg_userauth_request{user = User,
handle_userauth_request(#ssh_msg_userauth_request{user = User,
service = "ssh-connection",
method = "publickey",
- data = Data},
- SessionId,
+ data = <>
+ },
+ _SessionId,
#ssh{opts = Opts,
userauth_supported_methods = Methods} = Ssh) ->
- <> = Data,
-
- {KeyBlob, SigWLen} =
- case Rest of
- <> ->
- {KeyBlob0, SigWLen0};
- <<>> ->
- {<<>>, <<>>}
- end,
-
- case HaveSig of
- ?TRUE ->
- case verify_sig(SessionId, User, "ssh-connection",
- binary_to_list(BAlg),
- KeyBlob, SigWLen, Opts) of
- true ->
- {authorized, User,
- ssh_transport:ssh_packet(
- #ssh_msg_userauth_success{}, Ssh)};
- false ->
- {not_authorized, {User, undefined},
- ssh_transport:ssh_packet(#ssh_msg_userauth_failure{
- authentications = Methods,
- partial_success = false}, Ssh)}
- end;
- ?FALSE ->
+ case pre_verify_sig(User, binary_to_list(BAlg),
+ KeyBlob, Opts) of
+ true ->
{not_authorized, {User, undefined},
ssh_transport:ssh_packet(
#ssh_msg_userauth_pk_ok{algorithm_name = binary_to_list(BAlg),
- key_blob = KeyBlob}, Ssh)}
+ key_blob = KeyBlob}, Ssh)};
+ false ->
+ {not_authorized, {User, undefined},
+ ssh_transport:ssh_packet(#ssh_msg_userauth_failure{
+ authentications = Methods,
+ partial_success = false}, Ssh)}
+ end;
+
+handle_userauth_request(#ssh_msg_userauth_request{user = User,
+ service = "ssh-connection",
+ method = "publickey",
+ data = <>
+ },
+ SessionId,
+ #ssh{opts = Opts,
+ userauth_supported_methods = Methods} = Ssh) ->
+
+ case verify_sig(SessionId, User, "ssh-connection",
+ binary_to_list(BAlg),
+ KeyBlob, SigWLen, Opts) of
+ true ->
+ {authorized, User,
+ ssh_transport:ssh_packet(
+ #ssh_msg_userauth_success{}, Ssh)};
+ false ->
+ {not_authorized, {User, undefined},
+ ssh_transport:ssh_packet(#ssh_msg_userauth_failure{
+ authentications = Methods,
+ partial_success = false}, Ssh)}
end;
handle_userauth_request(#ssh_msg_userauth_request{user = User,
@@ -395,10 +406,22 @@ handle_userauth_info_response(#ssh_msg_userauth_info_response{num_responses = 1,
kb_tries_left = KbTriesLeft,
user = User,
userauth_supported_methods = Methods} = Ssh) ->
+ SendOneEmpty = proplists:get_value(tstflg, Opts) == one_empty,
case check_password(User, unicode:characters_to_list(Password), Opts, Ssh) of
+ {true,Ssh1} when SendOneEmpty==true ->
+ Msg = #ssh_msg_userauth_info_request{name = "",
+ instruction = "",
+ language_tag = "",
+ num_prompts = 0,
+ data = <>
+ },
+ {authorized_but_one_more, User,
+ ssh_transport:ssh_packet(Msg, Ssh1)};
+
{true,Ssh1} ->
{authorized, User,
ssh_transport:ssh_packet(#ssh_msg_userauth_success{}, Ssh1)};
+
{false,Ssh1} ->
{not_authorized, {User, {error,"Bad user or password"}},
ssh_transport:ssh_packet(#ssh_msg_userauth_failure{
@@ -408,6 +431,11 @@ handle_userauth_info_response(#ssh_msg_userauth_info_response{num_responses = 1,
)}
end;
+handle_userauth_info_response({extra,#ssh_msg_userauth_info_response{}},
+ #ssh{user = User} = Ssh) ->
+ {authorized, User,
+ ssh_transport:ssh_packet(#ssh_msg_userauth_success{}, Ssh)};
+
handle_userauth_info_response(#ssh_msg_userauth_info_response{},
_Auth) ->
ssh_connection_handler:disconnect(
@@ -484,19 +512,34 @@ get_password_option(Opts, User) ->
false -> proplists:get_value(password, Opts, false)
end.
-verify_sig(SessionId, User, Service, Alg, KeyBlob, SigWLen, Opts) ->
- {ok, Key} = decode_public_key_v2(KeyBlob, Alg),
- KeyCb = proplists:get_value(key_cb, Opts, ssh_file),
+pre_verify_sig(User, Alg, KeyBlob, Opts) ->
+ try
+ {ok, Key} = decode_public_key_v2(KeyBlob, Alg),
+ KeyCb = proplists:get_value(key_cb, Opts, ssh_file),
+ KeyCb:is_auth_key(Key, User, Opts)
+ catch
+ _:_ ->
+ false
+ end.
- case KeyCb:is_auth_key(Key, User, Opts) of
- true ->
- PlainText = build_sig_data(SessionId, User,
- Service, KeyBlob, Alg),
- <> = SigWLen,
- <> = AlgSig,
- ssh_transport:verify(PlainText, sha, Sig, Key);
- false ->
+verify_sig(SessionId, User, Service, Alg, KeyBlob, SigWLen, Opts) ->
+ try
+ {ok, Key} = decode_public_key_v2(KeyBlob, Alg),
+ KeyCb = proplists:get_value(key_cb, Opts, ssh_file),
+
+ case KeyCb:is_auth_key(Key, User, Opts) of
+ true ->
+ PlainText = build_sig_data(SessionId, User,
+ Service, KeyBlob, Alg),
+ <> = SigWLen,
+ <> = AlgSig,
+ ssh_transport:verify(PlainText, ssh_transport:sha(list_to_atom(Alg)), Sig, Key);
+ false ->
+ false
+ end
+ catch
+ _:_ ->
false
end.
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 2eb29c9b32..8ed638cec9 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -822,9 +822,21 @@ handle_event(_, #ssh_msg_userauth_info_response{} = Msg, {userauth_keyboard_inte
{not_authorized, {User, Reason}, {Reply, Ssh}} ->
retry_fun(User, Reason, D),
send_bytes(Reply, D),
- {next_state, {userauth,server}, D#data{ssh_params = Ssh}}
+ {next_state, {userauth,server}, D#data{ssh_params = Ssh}};
+
+ {authorized_but_one_more, _User, {Reply, Ssh}} ->
+ send_bytes(Reply, D),
+ {next_state, {userauth_keyboard_interactive_extra,server}, D#data{ssh_params = Ssh}}
end;
+handle_event(_, #ssh_msg_userauth_info_response{} = Msg, {userauth_keyboard_interactive_extra, server}, D) ->
+ {authorized, User, {Reply, Ssh}} = ssh_auth:handle_userauth_info_response({extra,Msg}, D#data.ssh_params),
+ send_bytes(Reply, D),
+ D#data.starter ! ssh_connected,
+ connected_fun(User, "keyboard-interactive", D),
+ {next_state, {connected,server}, D#data{auth_user = User,
+ ssh_params = Ssh#ssh{authenticated = true}}};
+
handle_event(_, Msg = #ssh_msg_userauth_failure{}, {userauth_keyboard_interactive, client},
#data{ssh_params = Ssh0} = D0) ->
Prefs = [{Method,M,F,A} || {Method,M,F,A} <- Ssh0#ssh.userauth_preference,
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 7cb3b75ac0..15b80de30a 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -46,7 +46,7 @@
handle_kex_ecdh_reply/2,
extract_public_key/1,
ssh_packet/2, pack/2,
- sign/3, verify/4]).
+ sha/1, sign/3, verify/4]).
%%% For test suites
-export([pack/3]).
@@ -1619,6 +1619,11 @@ kex_h(SSH, Key, Min, NBits, Max, Prime, Gen, E, F, K) ->
crypto:hash(sha((SSH#ssh.algorithms)#alg.kex), L).
+sha('ssh-rsa') -> sha;
+sha('ssh-dss') -> sha;
+sha('ecdsa-sha2-nistp256') -> sha(secp256r1);
+sha('ecdsa-sha2-nistp384') -> sha(secp384r1);
+sha('ecdsa-sha2-nistp521') -> sha(secp521r1);
sha(secp256r1) -> sha256;
sha(secp384r1) -> sha384;
sha(secp521r1) -> sha512;
--
cgit v1.2.3
From 27d3d5c6f6ddd51dc27d684b613c8c261f19a82f Mon Sep 17 00:00:00 2001
From: Svilen Ivanov
Date: Mon, 19 Sep 2016 14:58:48 +0300
Subject: Add SSH custom REPL exit status test
Test that when used defined shell REPL exit with reason normal
SSH client receives exit status 0.
---
lib/ssh/test/ssh_basic_SUITE.erl | 33 +++++++++++++++++++++++++++++++--
1 file changed, 31 insertions(+), 2 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index d52d453007..51e0d5196b 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -67,7 +67,8 @@
shell_unicode_string/1,
ssh_info_print/1,
key_callback/1,
- key_callback_options/1
+ key_callback_options/1,
+ shell_exit_status/1
]).
%%% Common test callbacks
@@ -106,7 +107,8 @@ all() ->
multi_daemon_opt_fd,
packet_size_zero,
ssh_info_print,
- {group, login_bad_pwd_no_retry}
+ {group, login_bad_pwd_no_retry},
+ shell_exit_status
].
groups() ->
@@ -1167,6 +1169,33 @@ login_bad_pwd_no_retry(Config, AuthMethods) ->
end
end.
+
+%%----------------------------------------------------------------------------
+%%% Test that when shell REPL exit with reason normal client receives status 0
+shell_exit_status(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ SystemDir = proplists:get_value(data_dir, Config),
+ UserDir = proplists:get_value(priv_dir, Config),
+
+ ShellFun = fun (_User) -> spawn(fun() -> ok end) end,
+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ {user_dir, UserDir},
+ {user_passwords, [{"vego", "morot"}]},
+ {shell, ShellFun},
+ {failfun, fun ssh_test_lib:failfun/2}]),
+ ConnectionRef =
+ ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
+ {user_dir, UserDir},
+ {user, "vego"},
+ {password, "morot"},
+ {user_interaction, false}]),
+
+ {ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity),
+ ok = ssh_connection:shell(ConnectionRef, ChannelId),
+ ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId),
+ ssh:stop_daemon(Pid).
+
+
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
--
cgit v1.2.3
From 5e698cb679546dae32c64fabd4e5a65cb5886297 Mon Sep 17 00:00:00 2001
From: Svilen Ivanov
Date: Mon, 19 Sep 2016 15:59:21 +0300
Subject: Fix SSH custom REPL exit status
When user defined SSH shell REPL process exits with reason normal
SSH channel callback module should report successful exit status
to the SSH client. This provides simple way for SSH clients to check
for successful completion of executed commands.
---
lib/ssh/src/ssh_cli.erl | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_cli.erl b/lib/ssh/src/ssh_cli.erl
index 74cd2e081a..8af0ecc5f9 100644
--- a/lib/ssh/src/ssh_cli.erl
+++ b/lib/ssh/src/ssh_cli.erl
@@ -208,8 +208,15 @@ 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,
- channel = ChannelId} = State) ->
+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};
handle_msg(_, State) ->
--
cgit v1.2.3
From 37e14c395a0d3621d65552b3954856d1cbeaed9a Mon Sep 17 00:00:00 2001
From: Erlang/OTP
Date: Tue, 20 Sep 2016 09:36:54 +0200
Subject: Prepare release
---
lib/ssh/doc/src/notes.xml | 62 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 62 insertions(+)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index f9d11b2a60..b990c18e9a 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -30,6 +30,68 @@
notes.xml
+Ssh 4.3.2
+
+ Fixed Bugs and Malfunctions
+
+ -
+
+ Upgrade of an established client connection could crash
+ because the ssh client supervisors children had wrong
+ type. This is fixed now.
+
+ Own Id: OTP-13782 Aux Id: seq13158
+
+ -
+
+ Partly checks the public key early in public key
+ authorization
+
+ Own Id: OTP-13847 Aux Id:
+ defensics-ssh3.1.0-190243,205277,219318
+
+ -
+
+ Corrected handling of SHA for ECDSA (Elliptic curve
+ public keys)
+
+ Own Id: OTP-13850 Aux Id: defensics-ssh3.1.0-214168
+
+ -
+
+ Problems found by test suites as well as by
+ Codenomicon/Defensics fixed: - reduce max random padding
+ to 15 bytes (Codenomicon/Defensics) - inclomplete pdu
+ handling (Codenomicon/Defensics) - badmatch in test suite
+ - non-blocking send fixes deadlock in
+ ssh_connection_SUITE:interrupted_send
+
+ Own Id: OTP-13854
+
+ -
+
+ Caller is now notified when a tcp close is received.
+
+ Own Id: OTP-13859 Aux Id: seq13177
+
+
+
+
+
+ Improvements and New Features
+
+ -
+
+ Use application:ensure_all_started/2 instead of
+ hard-coding deps
+
+ Own Id: OTP-13843 Aux Id: PR-1147
+
+
+
+
+
+
Ssh 4.3.1
Fixed Bugs and Malfunctions
--
cgit v1.2.3
From b19458dcb7a7ce3a02de0b7062843454e8467d86 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 28 Sep 2016 12:32:24 +0200
Subject: ssh: Update vsn.mk
---
lib/ssh/vsn.mk | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index 212b99c695..09e707ad07 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,5 +1,5 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 4.3.2
+SSH_VSN = 4.3.3
APP_VSN = "ssh-$(SSH_VSN)"
--
cgit v1.2.3
From abf7b8c8397acaa9bee0ccf284b1af4e130c16af Mon Sep 17 00:00:00 2001
From: Ingela Anderton Andin
Date: Wed, 5 Oct 2016 15:15:35 +0200
Subject: ssh: Handle gen_server:call/3 exits properly
Handle all possible exit values that should be interpreted as {error,
closed}. Failing to do so could lead to unexpected crashes for users
of the ssh application.
---
lib/ssh/src/ssh_channel.erl | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_channel.erl b/lib/ssh/src/ssh_channel.erl
index a8e6ebde16..426e2f5125 100644
--- a/lib/ssh/src/ssh_channel.erl
+++ b/lib/ssh/src/ssh_channel.erl
@@ -93,11 +93,16 @@ call(ChannelPid, Msg, TimeOute) ->
catch
exit:{noproc, _} ->
{error, closed};
+ exit:{normal, _} ->
+ {error, closed};
+ exit:{shutdown, _} ->
+ {error, closed};
+ exit:{{shutdown, _}, _} ->
+ {error, closed};
exit:{timeout, _} ->
{error, timeout}
end.
-
cast(ChannelPid, Msg) ->
gen_server:cast(ChannelPid, Msg).
--
cgit v1.2.3
From eadc9b7a1a0349422a6b9ad1d52229562fc22375 Mon Sep 17 00:00:00 2001
From: Ingela Anderton Andin
Date: Wed, 5 Oct 2016 16:02:21 +0200
Subject: ssh: Prepare release
---
lib/ssh/src/ssh.appup.src | 4 ++++
lib/ssh/vsn.mk | 2 +-
2 files changed, 5 insertions(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh.appup.src b/lib/ssh/src/ssh.appup.src
index e38cecf226..4cda8fee95 100644
--- a/lib/ssh/src/ssh.appup.src
+++ b/lib/ssh/src/ssh.appup.src
@@ -20,9 +20,13 @@
{"%VSN%",
[
+ {<<"4.3.2">>, [{load_module, ssh_channel, soft_purge, soft_purge, []}
+ ]},
{<<".*">>, [{restart_application, ssh}]}
],
[
+ {<<"4.3.2">>, [{load_module, ssh_channel, soft_purge, soft_purge, []}
+ ]},
{<<".*">>, [{restart_application, ssh}]}
]
}.
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index 212b99c695..09e707ad07 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,5 +1,5 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 4.3.2
+SSH_VSN = 4.3.3
APP_VSN = "ssh-$(SSH_VSN)"
--
cgit v1.2.3
From b886c19c55165007d68e26147e756310bac5ae70 Mon Sep 17 00:00:00 2001
From: Erlang/OTP
Date: Thu, 6 Oct 2016 11:29:55 +0200
Subject: Update release notes
---
lib/ssh/doc/src/notes.xml | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index b990c18e9a..a4897668e4 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -30,6 +30,24 @@
notes.xml
+Ssh 4.3.3
+
+ Fixed Bugs and Malfunctions
+
+ -
+
+ Handle all possible exit values that should be
+ interpreted as {error, closed}. Failing to do so could
+ lead to unexpected crashes for users of the ssh
+ application.
+
+ Own Id: OTP-13932 Aux Id: seq13189
+
+
+
+
+
+
Ssh 4.3.2
Fixed Bugs and Malfunctions
--
cgit v1.2.3
From 046539298604ef214c0986524f731695d0c47262 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 10 Oct 2016 12:06:46 +0200
Subject: Revert "ssh: Add non-blocking send" since it introduces Error Reports
This reverts commit 28baf1314b556bb592c24181f6967e1f324f44a7.
---
lib/ssh/src/ssh_connection_handler.erl | 92 +++++++++++++---------------------
1 file changed, 34 insertions(+), 58 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index facf6b561a..abfba4baf1 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -339,7 +339,6 @@ renegotiate_data(ConnectionHandler) ->
ssh_params :: #ssh{}
| undefined,
socket :: inet:socket(),
- sender :: pid() | undefined,
decrypted_data_buffer = <<>> :: binary(),
encrypted_data_buffer = <<>> :: binary(),
undecrypted_packet_length :: undefined | non_neg_integer(),
@@ -368,10 +367,9 @@ init_connection_handler(Role, Socket, Opts) ->
{Protocol, Callback, CloseTag} =
proplists:get_value(transport, Opts, ?DefaultTransport),
S0#data{ssh_params = init_ssh_record(Role, Socket, Opts),
- sender = spawn_link(fun() -> nonblocking_sender(Socket, Callback) end),
- transport_protocol = Protocol,
- transport_cb = Callback,
- transport_close_tag = CloseTag
+ transport_protocol = Protocol,
+ transport_cb = Callback,
+ transport_close_tag = CloseTag
}
of
S ->
@@ -527,7 +525,7 @@ handle_event(_, _Event, {init_error,Error}, _) ->
%% The very first event that is sent when the we are set as controlling process of Socket
handle_event(_, socket_control, {hello,_}, D) ->
VsnMsg = ssh_transport:hello_version_msg(string_version(D#data.ssh_params)),
- send_bytes(VsnMsg, D),
+ ok = send_bytes(VsnMsg, D),
case inet:getopts(Socket=D#data.socket, [recbuf]) of
{ok, [{recbuf,Size}]} ->
%% Set the socket to the hello text line handling mode:
@@ -552,7 +550,7 @@ handle_event(_, {info_line,_Line}, {hello,Role}, D) ->
server ->
%% But the client may NOT send them to the server. Openssh answers with cleartext,
%% and so do we
- send_bytes("Protocol mismatch.", D),
+ ok = send_bytes("Protocol mismatch.", D),
{stop, {shutdown,"Protocol mismatch in version exchange. Client sent info lines."}}
end;
@@ -567,7 +565,7 @@ handle_event(_, {version_exchange,Version}, {hello,Role}, D) ->
{active, once},
{recbuf, D#data.inet_initial_recbuf_size}]),
{KeyInitMsg, SshPacket, Ssh} = ssh_transport:key_exchange_init_msg(Ssh1),
- send_bytes(SshPacket, D),
+ ok = send_bytes(SshPacket, D),
{next_state, {kexinit,Role,init}, D#data{ssh_params = Ssh,
key_exchange_init_msg = KeyInitMsg}};
not_supported ->
@@ -585,7 +583,7 @@ handle_event(_, {#ssh_msg_kexinit{}=Kex, Payload}, {kexinit,Role,ReNeg},
Ssh1 = ssh_transport:key_init(peer_role(Role), D#data.ssh_params, Payload),
Ssh = case ssh_transport:handle_kexinit_msg(Kex, OwnKex, Ssh1) of
{ok, NextKexMsg, Ssh2} when Role==client ->
- send_bytes(NextKexMsg, D),
+ ok = send_bytes(NextKexMsg, D),
Ssh2;
{ok, Ssh2} when Role==server ->
Ssh2
@@ -598,43 +596,43 @@ handle_event(_, {#ssh_msg_kexinit{}=Kex, Payload}, {kexinit,Role,ReNeg},
%%%---- diffie-hellman
handle_event(_, #ssh_msg_kexdh_init{} = Msg, {key_exchange,server,ReNeg}, D) ->
{ok, KexdhReply, Ssh1} = ssh_transport:handle_kexdh_init(Msg, D#data.ssh_params),
- send_bytes(KexdhReply, D),
+ ok = send_bytes(KexdhReply, D),
{ok, NewKeys, Ssh} = ssh_transport:new_keys_message(Ssh1),
- send_bytes(NewKeys, D),
+ ok = send_bytes(NewKeys, D),
{next_state, {new_keys,server,ReNeg}, D#data{ssh_params=Ssh}};
handle_event(_, #ssh_msg_kexdh_reply{} = Msg, {key_exchange,client,ReNeg}, D) ->
{ok, NewKeys, Ssh} = ssh_transport:handle_kexdh_reply(Msg, D#data.ssh_params),
- send_bytes(NewKeys, D),
+ ok = send_bytes(NewKeys, D),
{next_state, {new_keys,client,ReNeg}, D#data{ssh_params=Ssh}};
%%%---- diffie-hellman group exchange
handle_event(_, #ssh_msg_kex_dh_gex_request{} = Msg, {key_exchange,server,ReNeg}, D) ->
{ok, GexGroup, Ssh} = ssh_transport:handle_kex_dh_gex_request(Msg, D#data.ssh_params),
- send_bytes(GexGroup, D),
+ ok = send_bytes(GexGroup, D),
{next_state, {key_exchange_dh_gex_init,server,ReNeg}, D#data{ssh_params=Ssh}};
handle_event(_, #ssh_msg_kex_dh_gex_request_old{} = Msg, {key_exchange,server,ReNeg}, D) ->
{ok, GexGroup, Ssh} = ssh_transport:handle_kex_dh_gex_request(Msg, D#data.ssh_params),
- send_bytes(GexGroup, D),
+ ok = send_bytes(GexGroup, D),
{next_state, {key_exchange_dh_gex_init,server,ReNeg}, D#data{ssh_params=Ssh}};
handle_event(_, #ssh_msg_kex_dh_gex_group{} = Msg, {key_exchange,client,ReNeg}, D) ->
{ok, KexGexInit, Ssh} = ssh_transport:handle_kex_dh_gex_group(Msg, D#data.ssh_params),
- send_bytes(KexGexInit, D),
+ ok = send_bytes(KexGexInit, D),
{next_state, {key_exchange_dh_gex_reply,client,ReNeg}, D#data{ssh_params=Ssh}};
%%%---- elliptic curve diffie-hellman
handle_event(_, #ssh_msg_kex_ecdh_init{} = Msg, {key_exchange,server,ReNeg}, D) ->
{ok, KexEcdhReply, Ssh1} = ssh_transport:handle_kex_ecdh_init(Msg, D#data.ssh_params),
- send_bytes(KexEcdhReply, D),
+ ok = send_bytes(KexEcdhReply, D),
{ok, NewKeys, Ssh} = ssh_transport:new_keys_message(Ssh1),
- send_bytes(NewKeys, D),
+ ok = send_bytes(NewKeys, D),
{next_state, {new_keys,server,ReNeg}, D#data{ssh_params=Ssh}};
handle_event(_, #ssh_msg_kex_ecdh_reply{} = Msg, {key_exchange,client,ReNeg}, D) ->
{ok, NewKeys, Ssh} = ssh_transport:handle_kex_ecdh_reply(Msg, D#data.ssh_params),
- send_bytes(NewKeys, D),
+ ok = send_bytes(NewKeys, D),
{next_state, {new_keys,client,ReNeg}, D#data{ssh_params=Ssh}};
@@ -642,9 +640,9 @@ handle_event(_, #ssh_msg_kex_ecdh_reply{} = Msg, {key_exchange,client,ReNeg}, D)
handle_event(_, #ssh_msg_kex_dh_gex_init{} = Msg, {key_exchange_dh_gex_init,server,ReNeg}, D) ->
{ok, KexGexReply, Ssh1} = ssh_transport:handle_kex_dh_gex_init(Msg, D#data.ssh_params),
- send_bytes(KexGexReply, D),
+ ok = send_bytes(KexGexReply, D),
{ok, NewKeys, Ssh} = ssh_transport:new_keys_message(Ssh1),
- send_bytes(NewKeys, D),
+ ok = send_bytes(NewKeys, D),
{next_state, {new_keys,server,ReNeg}, D#data{ssh_params=Ssh}};
@@ -652,7 +650,7 @@ handle_event(_, #ssh_msg_kex_dh_gex_init{} = Msg, {key_exchange_dh_gex_init,serv
handle_event(_, #ssh_msg_kex_dh_gex_reply{} = Msg, {key_exchange_dh_gex_reply,client,ReNeg}, D) ->
{ok, NewKeys, Ssh1} = ssh_transport:handle_kex_dh_gex_reply(Msg, D#data.ssh_params),
- send_bytes(NewKeys, D),
+ ok = send_bytes(NewKeys, D),
{next_state, {new_keys,client,ReNeg}, D#data{ssh_params=Ssh1}};
@@ -664,7 +662,7 @@ handle_event(_, #ssh_msg_newkeys{} = Msg, {new_keys,Role,init}, D) ->
Ssh = case Role of
client ->
{MsgReq, Ssh2} = ssh_auth:service_request_msg(Ssh1),
- send_bytes(MsgReq, D),
+ ok = send_bytes(MsgReq, D),
Ssh2;
server ->
Ssh1
@@ -682,7 +680,7 @@ handle_event(_, Msg = #ssh_msg_service_request{name=ServiceName}, StateName = {s
"ssh-userauth" ->
Ssh0 = #ssh{session_id=SessionId} = D#data.ssh_params,
{ok, {Reply, Ssh}} = ssh_auth:handle_userauth_request(Msg, SessionId, Ssh0),
- send_bytes(Reply, D),
+ ok = send_bytes(Reply, D),
{next_state, {userauth,server}, D#data{ssh_params = Ssh}};
_ ->
@@ -694,7 +692,7 @@ handle_event(_, Msg = #ssh_msg_service_request{name=ServiceName}, StateName = {s
handle_event(_, #ssh_msg_service_accept{name = "ssh-userauth"}, {service_request,client},
#data{ssh_params = #ssh{service="ssh-userauth"} = Ssh0} = State) ->
{Msg, Ssh} = ssh_auth:init_userauth_request_msg(Ssh0),
- send_bytes(Msg, State),
+ ok = send_bytes(Msg, State),
{next_state, {userauth,client}, State#data{auth_user = Ssh#ssh.user, ssh_params = Ssh}};
@@ -711,7 +709,7 @@ handle_event(_,
%% Probably the very first userauth_request but we deny unauthorized login
{not_authorized, _, {Reply,Ssh}} =
ssh_auth:handle_userauth_request(Msg, Ssh0#ssh.session_id, Ssh0),
- send_bytes(Reply, D),
+ ok = send_bytes(Reply, D),
{keep_state, D#data{ssh_params = Ssh}};
{"ssh-connection", "ssh-connection", Method} ->
@@ -721,7 +719,7 @@ handle_event(_,
%% Yepp! we support this method
case ssh_auth:handle_userauth_request(Msg, Ssh0#ssh.session_id, Ssh0) of
{authorized, User, {Reply, Ssh}} ->
- send_bytes(Reply, D),
+ ok = send_bytes(Reply, D),
D#data.starter ! ssh_connected,
connected_fun(User, Method, D),
{next_state, {connected,server},
@@ -729,11 +727,11 @@ handle_event(_,
ssh_params = Ssh#ssh{authenticated = true}}};
{not_authorized, {User, Reason}, {Reply, Ssh}} when Method == "keyboard-interactive" ->
retry_fun(User, Reason, D),
- send_bytes(Reply, D),
+ ok = send_bytes(Reply, D),
{next_state, {userauth_keyboard_interactive,server}, D#data{ssh_params = Ssh}};
{not_authorized, {User, Reason}, {Reply, Ssh}} ->
retry_fun(User, Reason, D),
- send_bytes(Reply, D),
+ ok = send_bytes(Reply, D),
{keep_state, D#data{ssh_params = Ssh}}
end;
false ->
@@ -1447,15 +1445,18 @@ start_the_connection_child(UserPid, Role, Socket, Options) ->
%% Stopping
-type finalize_termination_result() :: ok .
-finalize_termination(_StateName, D) ->
- case D#data.connection_state of
+finalize_termination(_StateName, #data{transport_cb = Transport,
+ connection_state = Connection,
+ socket = Socket}) ->
+ case Connection of
#connection{system_supervisor = SysSup,
sub_system_supervisor = SubSysSup} when is_pid(SubSysSup) ->
ssh_system_sup:stop_subsystem(SysSup, SubSysSup);
_ ->
do_nothing
end,
- close_transport(D).
+ (catch Transport:close(Socket)),
+ ok.
%%--------------------------------------------------------------------
%% "Invert" the Role
@@ -1510,33 +1511,8 @@ send_msg(Msg, State=#data{ssh_params=Ssh0}) when is_tuple(Msg) ->
send_bytes(Bytes, State),
State#data{ssh_params=Ssh}.
-send_bytes(Bytes, #data{sender = Sender}) ->
- Sender ! {send,Bytes},
- ok.
-
-close_transport(D) ->
- D#data.sender ! close,
- ok.
-
-
-nonblocking_sender(Socket, Callback) ->
- receive
- {send, Bytes} ->
- case Callback:send(Socket, Bytes) of
- ok ->
- nonblocking_sender(Socket, Callback);
- E = {error,_} ->
- exit({shutdown,E})
- end;
-
- close ->
- case Callback:close(Socket) of
- ok ->
- ok;
- E = {error,_} ->
- exit({shutdown,E})
- end
- end.
+send_bytes(Bytes, #data{socket = Socket, transport_cb = Transport}) ->
+ Transport:send(Socket, Bytes).
handle_version({2, 0} = NumVsn, StrVsn, Ssh0) ->
Ssh = counterpart_versions(NumVsn, StrVsn, Ssh0),
--
cgit v1.2.3
From 42a2e7530d3c7eafcf0ed9afb12d2dde7b116bda Mon Sep 17 00:00:00 2001
From: Erlang/OTP
Date: Mon, 10 Oct 2016 14:10:04 +0200
Subject: Prepare release
---
lib/ssh/doc/src/notes.xml | 16 ++++++++++++++++
lib/ssh/vsn.mk | 2 +-
2 files changed, 17 insertions(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index a4897668e4..f6ad8d8dea 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -30,6 +30,22 @@
notes.xml
+Ssh 4.3.4
+
+ Fixed Bugs and Malfunctions
+
+ -
+
+ Intermittent ssh ERROR REPORT mentioning
+ nonblocking_sender
+
+ Own Id: OTP-13953 Aux Id: seq13199
+
+
+
+
+
+
Ssh 4.3.3
Fixed Bugs and Malfunctions
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index 09e707ad07..536e559514 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,5 +1,5 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 4.3.3
+SSH_VSN = 4.3.4
APP_VSN = "ssh-$(SSH_VSN)"
--
cgit v1.2.3
From d53bd4936297f6310e59f88191014bb5dd0d8b2c Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 13 Oct 2016 13:09:42 +0200
Subject: ssh: property test case for illegal infoline and close This tests an
illegal client that sends an info line and closes 'immediatly'.
---
lib/ssh/test/Makefile | 3 +-
.../property_test/ssh_eqc_client_info_timing.erl | 92 ++++++++++++++++++++++
lib/ssh/test/ssh_eqc_event_handler.erl | 43 ++++++++++
lib/ssh/test/ssh_property_test_SUITE.erl | 7 ++
lib/ssh/test/ssh_test_lib.erl | 25 ++++++
5 files changed, 169 insertions(+), 1 deletion(-)
create mode 100644 lib/ssh/test/property_test/ssh_eqc_client_info_timing.erl
create mode 100644 lib/ssh/test/ssh_eqc_event_handler.erl
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/Makefile b/lib/ssh/test/Makefile
index 6ce6d6f537..3fca78237c 100644
--- a/lib/ssh/test/Makefile
+++ b/lib/ssh/test/Makefile
@@ -52,7 +52,8 @@ MODULES= \
ssh_echo_server \
ssh_peername_sockname_server \
ssh_test_cli \
- ssh_relay
+ ssh_relay \
+ ssh_eqc_event_handler
HRL_FILES_NEEDED_IN_TEST= \
$(ERL_TOP)/lib/ssh/test/ssh_test_lib.hrl \
diff --git a/lib/ssh/test/property_test/ssh_eqc_client_info_timing.erl b/lib/ssh/test/property_test/ssh_eqc_client_info_timing.erl
new file mode 100644
index 0000000000..c07140dc43
--- /dev/null
+++ b/lib/ssh/test/property_test/ssh_eqc_client_info_timing.erl
@@ -0,0 +1,92 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+
+-module(ssh_eqc_client_info_timing).
+
+-compile(export_all).
+
+-proptest(eqc).
+-proptest([triq,proper]).
+
+-ifndef(EQC).
+-ifndef(PROPER).
+-ifndef(TRIQ).
+-define(EQC,true).
+%%-define(PROPER,true).
+%%-define(TRIQ,true).
+-endif.
+-endif.
+-endif.
+
+-ifdef(EQC).
+-include_lib("eqc/include/eqc.hrl").
+-define(MOD_eqc,eqc).
+
+-else.
+-ifdef(PROPER).
+-include_lib("proper/include/proper.hrl").
+-define(MOD_eqc,proper).
+
+-else.
+-ifdef(TRIQ).
+-define(MOD_eqc,triq).
+-include_lib("triq/include/triq.hrl").
+
+-endif.
+-endif.
+-endif.
+
+
+%%% Properties:
+
+prop_seq(_Config) ->
+ {ok,Pid} = ssh_eqc_event_handler:add_report_handler(),
+ {_, _, Port} = init_daemon(),
+ numtests(1000,
+ ?FORALL(Delay, choose(0,100),%% Micro seconds
+ try
+ send_bad_sequence(Port, Delay, Pid),
+ not any_relevant_error_report(Pid)
+ catch
+ C:E -> io:format('~p:~p~n',[C,E]),
+ false
+ end
+ )).
+
+send_bad_sequence(Port, Delay, Pid) ->
+ {ok,S} = gen_tcp:connect("localhost",Port,[]),
+ gen_tcp:send(S,"Illegal info-string\r\n"),
+ ssh_test_lib:sleep_microsec(Delay),
+ gen_tcp:close(S).
+
+any_relevant_error_report(Pid) ->
+ {ok, Reports} = ssh_eqc_event_handler:get_reports(Pid),
+ lists:any(fun({error_report,_,{_,supervisor_report,L}}) when is_list(L) ->
+ lists:member({reason,{badmatch,{error,closed}}}, L);
+ (_) ->
+ false
+ end, Reports).
+
+%%%================================================================
+init_daemon() ->
+ ok = begin ssh:stop(), ssh:start() end,
+ ssh_test_lib:daemon([]).
+
diff --git a/lib/ssh/test/ssh_eqc_event_handler.erl b/lib/ssh/test/ssh_eqc_event_handler.erl
new file mode 100644
index 0000000000..233965012a
--- /dev/null
+++ b/lib/ssh/test/ssh_eqc_event_handler.erl
@@ -0,0 +1,43 @@
+-module(ssh_eqc_event_handler).
+
+-compile(export_all).
+
+-behaviour(gen_event).
+
+add_report_handler() ->
+ error_logger:add_report_handler(?MODULE, [self(),Ref=make_ref()]),
+ receive
+ {event_handler_started,HandlerPid,Ref} ->
+ {ok,HandlerPid}
+ end.
+
+get_reports(Pid) ->
+ Pid ! {get_reports,self(),Ref=make_ref()},
+ receive
+ {reports,Reports,Ref} ->
+ {ok,Reports}
+ end.
+
+%%%================================================================
+
+-record(state, {
+ reports = []
+ }).
+
+%% error_logger:add_report_handler(ssh_eqc_event_handler, [self()]).
+
+init([CallerPid,Ref]) ->
+ CallerPid ! {event_handler_started,self(),Ref},
+ {ok, #state{}}.
+
+handle_event(Event, State) ->
+ {ok, State#state{reports = [Event|State#state.reports]}}.
+
+handle_info({get_reports,From,Ref}, State) ->
+ From ! {reports, lists:reverse(State#state.reports), Ref},
+ {ok, State#state{reports=[]}}.
+
+handle_call(_Request, State) -> {ok,reply,State}.
+terminate(_Arg, _State) -> stop.
+
+code_change(_OldVsn, State, _Extra) -> {ok, State}.
diff --git a/lib/ssh/test/ssh_property_test_SUITE.erl b/lib/ssh/test/ssh_property_test_SUITE.erl
index c8aabcedb7..7ba2732a88 100644
--- a/lib/ssh/test/ssh_property_test_SUITE.erl
+++ b/lib/ssh/test/ssh_property_test_SUITE.erl
@@ -38,6 +38,7 @@
-include_lib("common_test/include/ct.hrl").
all() -> [{group, messages},
+ client_sends_info_timing,
{group, client_server}
].
@@ -106,3 +107,9 @@ client_server_parallel_multi(Config) ->
ssh_eqc_client_server:prop_parallel_multi(Config),
Config
).
+
+client_sends_info_timing(Config) ->
+ ct_property_test:quickcheck(
+ ssh_eqc_client_info_timing:prop_seq(Config),
+ Config
+ ).
diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl
index 6233680dce..c43c6519f9 100644
--- a/lib/ssh/test/ssh_test_lib.erl
+++ b/lib/ssh/test/ssh_test_lib.erl
@@ -767,3 +767,28 @@ open_port(Arg1, ExtraOpts) ->
use_stdio,
overlapped_io, hide %only affects windows
| ExtraOpts]).
+
+%%%----------------------------------------------------------------
+%%% Sleeping
+
+%%% Milli sec
+sleep_millisec(Nms) -> receive after Nms -> ok end.
+
+%%% Micro sec
+sleep_microsec(Nus) ->
+ busy_wait(Nus, erlang:system_time(microsecond)).
+
+busy_wait(Nus, T0) ->
+ T = erlang:system_time(microsecond) - T0,
+ Tleft = Nus - T,
+ if
+ Tleft > 2000 ->
+ sleep_millisec((Tleft-1500) div 1000), % μs -> ms
+ busy_wait(Nus,T0);
+ Tleft > 1 ->
+ busy_wait(Nus, T0);
+ true ->
+ T
+ end.
+
+%%%----------------------------------------------------------------
--
cgit v1.2.3
From d35017055aa3a138177270221369008d9d263674 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 13 Oct 2016 15:22:40 +0200
Subject: ssh: ssh_protocol_SUITE test for handling of illegal info_lines
---
lib/ssh/test/ssh_protocol_SUITE.erl | 31 +++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_protocol_SUITE.erl b/lib/ssh/test/ssh_protocol_SUITE.erl
index 4fac1f718a..93d0bc2eb0 100644
--- a/lib/ssh/test/ssh_protocol_SUITE.erl
+++ b/lib/ssh/test/ssh_protocol_SUITE.erl
@@ -48,6 +48,7 @@ suite() ->
all() ->
[{group,tool_tests},
+ client_info_line,
{group,kex},
{group,service_requests},
{group,authentication},
@@ -575,6 +576,36 @@ client_handles_keyboard_interactive_0_pwds(Config) ->
).
+
+%%%--------------------------------------------------------------------
+client_info_line(_Config) ->
+ %% A client must not send an info-line. If it does, the server should handle
+ %% handle this gracefully
+ {ok,Pid} = ssh_eqc_event_handler:add_report_handler(),
+ {_, _, Port} = ssh_test_lib:daemon([]),
+
+ %% Fake client:
+ {ok,S} = gen_tcp:connect("localhost",Port,[]),
+ gen_tcp:send(S,"An illegal info-string\r\n"),
+ gen_tcp:close(S),
+
+ %% wait for server to react:
+ timer:sleep(1000),
+
+ %% check if a badmatch was received:
+ {ok, Reports} = ssh_eqc_event_handler:get_reports(Pid),
+ case lists:any(fun({error_report,_,{_,supervisor_report,L}}) when is_list(L) ->
+ lists:member({reason,{badmatch,{error,closed}}}, L);
+ (_) ->
+ false
+ end, Reports) of
+ true ->
+ ct:fail("Bad error report on info_line from client");
+ false ->
+ ok
+ end.
+
+
%%%================================================================
%%%==== Internal functions ========================================
%%%================================================================
--
cgit v1.2.3
From f6c9b5caaa1ba6c22248ff22cc678b30d89cdd36 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 13 Oct 2016 10:33:26 +0200
Subject: ssh: Removed matching of 'ok' after send which could cause error
reports
---
lib/ssh/src/ssh_connection_handler.erl | 50 ++++++++++++++++++----------------
1 file changed, 26 insertions(+), 24 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index abfba4baf1..ced049f0d0 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -525,7 +525,7 @@ handle_event(_, _Event, {init_error,Error}, _) ->
%% The very first event that is sent when the we are set as controlling process of Socket
handle_event(_, socket_control, {hello,_}, D) ->
VsnMsg = ssh_transport:hello_version_msg(string_version(D#data.ssh_params)),
- ok = send_bytes(VsnMsg, D),
+ send_bytes(VsnMsg, D),
case inet:getopts(Socket=D#data.socket, [recbuf]) of
{ok, [{recbuf,Size}]} ->
%% Set the socket to the hello text line handling mode:
@@ -545,12 +545,13 @@ handle_event(_, {info_line,_Line}, {hello,Role}, D) ->
case Role of
client ->
%% The server may send info lines to the client before the version_exchange
+ %% RFC4253/4.2
inet:setopts(D#data.socket, [{active, once}]),
keep_state_and_data;
server ->
%% But the client may NOT send them to the server. Openssh answers with cleartext,
%% and so do we
- ok = send_bytes("Protocol mismatch.", D),
+ send_bytes("Protocol mismatch.", D),
{stop, {shutdown,"Protocol mismatch in version exchange. Client sent info lines."}}
end;
@@ -565,7 +566,7 @@ handle_event(_, {version_exchange,Version}, {hello,Role}, D) ->
{active, once},
{recbuf, D#data.inet_initial_recbuf_size}]),
{KeyInitMsg, SshPacket, Ssh} = ssh_transport:key_exchange_init_msg(Ssh1),
- ok = send_bytes(SshPacket, D),
+ send_bytes(SshPacket, D),
{next_state, {kexinit,Role,init}, D#data{ssh_params = Ssh,
key_exchange_init_msg = KeyInitMsg}};
not_supported ->
@@ -583,7 +584,7 @@ handle_event(_, {#ssh_msg_kexinit{}=Kex, Payload}, {kexinit,Role,ReNeg},
Ssh1 = ssh_transport:key_init(peer_role(Role), D#data.ssh_params, Payload),
Ssh = case ssh_transport:handle_kexinit_msg(Kex, OwnKex, Ssh1) of
{ok, NextKexMsg, Ssh2} when Role==client ->
- ok = send_bytes(NextKexMsg, D),
+ send_bytes(NextKexMsg, D),
Ssh2;
{ok, Ssh2} when Role==server ->
Ssh2
@@ -596,43 +597,43 @@ handle_event(_, {#ssh_msg_kexinit{}=Kex, Payload}, {kexinit,Role,ReNeg},
%%%---- diffie-hellman
handle_event(_, #ssh_msg_kexdh_init{} = Msg, {key_exchange,server,ReNeg}, D) ->
{ok, KexdhReply, Ssh1} = ssh_transport:handle_kexdh_init(Msg, D#data.ssh_params),
- ok = send_bytes(KexdhReply, D),
+ send_bytes(KexdhReply, D),
{ok, NewKeys, Ssh} = ssh_transport:new_keys_message(Ssh1),
- ok = send_bytes(NewKeys, D),
+ send_bytes(NewKeys, D),
{next_state, {new_keys,server,ReNeg}, D#data{ssh_params=Ssh}};
handle_event(_, #ssh_msg_kexdh_reply{} = Msg, {key_exchange,client,ReNeg}, D) ->
{ok, NewKeys, Ssh} = ssh_transport:handle_kexdh_reply(Msg, D#data.ssh_params),
- ok = send_bytes(NewKeys, D),
+ send_bytes(NewKeys, D),
{next_state, {new_keys,client,ReNeg}, D#data{ssh_params=Ssh}};
%%%---- diffie-hellman group exchange
handle_event(_, #ssh_msg_kex_dh_gex_request{} = Msg, {key_exchange,server,ReNeg}, D) ->
{ok, GexGroup, Ssh} = ssh_transport:handle_kex_dh_gex_request(Msg, D#data.ssh_params),
- ok = send_bytes(GexGroup, D),
+ send_bytes(GexGroup, D),
{next_state, {key_exchange_dh_gex_init,server,ReNeg}, D#data{ssh_params=Ssh}};
handle_event(_, #ssh_msg_kex_dh_gex_request_old{} = Msg, {key_exchange,server,ReNeg}, D) ->
{ok, GexGroup, Ssh} = ssh_transport:handle_kex_dh_gex_request(Msg, D#data.ssh_params),
- ok = send_bytes(GexGroup, D),
+ send_bytes(GexGroup, D),
{next_state, {key_exchange_dh_gex_init,server,ReNeg}, D#data{ssh_params=Ssh}};
handle_event(_, #ssh_msg_kex_dh_gex_group{} = Msg, {key_exchange,client,ReNeg}, D) ->
{ok, KexGexInit, Ssh} = ssh_transport:handle_kex_dh_gex_group(Msg, D#data.ssh_params),
- ok = send_bytes(KexGexInit, D),
+ send_bytes(KexGexInit, D),
{next_state, {key_exchange_dh_gex_reply,client,ReNeg}, D#data{ssh_params=Ssh}};
%%%---- elliptic curve diffie-hellman
handle_event(_, #ssh_msg_kex_ecdh_init{} = Msg, {key_exchange,server,ReNeg}, D) ->
{ok, KexEcdhReply, Ssh1} = ssh_transport:handle_kex_ecdh_init(Msg, D#data.ssh_params),
- ok = send_bytes(KexEcdhReply, D),
+ send_bytes(KexEcdhReply, D),
{ok, NewKeys, Ssh} = ssh_transport:new_keys_message(Ssh1),
- ok = send_bytes(NewKeys, D),
+ send_bytes(NewKeys, D),
{next_state, {new_keys,server,ReNeg}, D#data{ssh_params=Ssh}};
handle_event(_, #ssh_msg_kex_ecdh_reply{} = Msg, {key_exchange,client,ReNeg}, D) ->
{ok, NewKeys, Ssh} = ssh_transport:handle_kex_ecdh_reply(Msg, D#data.ssh_params),
- ok = send_bytes(NewKeys, D),
+ send_bytes(NewKeys, D),
{next_state, {new_keys,client,ReNeg}, D#data{ssh_params=Ssh}};
@@ -640,9 +641,9 @@ handle_event(_, #ssh_msg_kex_ecdh_reply{} = Msg, {key_exchange,client,ReNeg}, D)
handle_event(_, #ssh_msg_kex_dh_gex_init{} = Msg, {key_exchange_dh_gex_init,server,ReNeg}, D) ->
{ok, KexGexReply, Ssh1} = ssh_transport:handle_kex_dh_gex_init(Msg, D#data.ssh_params),
- ok = send_bytes(KexGexReply, D),
+ send_bytes(KexGexReply, D),
{ok, NewKeys, Ssh} = ssh_transport:new_keys_message(Ssh1),
- ok = send_bytes(NewKeys, D),
+ send_bytes(NewKeys, D),
{next_state, {new_keys,server,ReNeg}, D#data{ssh_params=Ssh}};
@@ -650,7 +651,7 @@ handle_event(_, #ssh_msg_kex_dh_gex_init{} = Msg, {key_exchange_dh_gex_init,serv
handle_event(_, #ssh_msg_kex_dh_gex_reply{} = Msg, {key_exchange_dh_gex_reply,client,ReNeg}, D) ->
{ok, NewKeys, Ssh1} = ssh_transport:handle_kex_dh_gex_reply(Msg, D#data.ssh_params),
- ok = send_bytes(NewKeys, D),
+ send_bytes(NewKeys, D),
{next_state, {new_keys,client,ReNeg}, D#data{ssh_params=Ssh1}};
@@ -662,7 +663,7 @@ handle_event(_, #ssh_msg_newkeys{} = Msg, {new_keys,Role,init}, D) ->
Ssh = case Role of
client ->
{MsgReq, Ssh2} = ssh_auth:service_request_msg(Ssh1),
- ok = send_bytes(MsgReq, D),
+ send_bytes(MsgReq, D),
Ssh2;
server ->
Ssh1
@@ -680,7 +681,7 @@ handle_event(_, Msg = #ssh_msg_service_request{name=ServiceName}, StateName = {s
"ssh-userauth" ->
Ssh0 = #ssh{session_id=SessionId} = D#data.ssh_params,
{ok, {Reply, Ssh}} = ssh_auth:handle_userauth_request(Msg, SessionId, Ssh0),
- ok = send_bytes(Reply, D),
+ send_bytes(Reply, D),
{next_state, {userauth,server}, D#data{ssh_params = Ssh}};
_ ->
@@ -692,7 +693,7 @@ handle_event(_, Msg = #ssh_msg_service_request{name=ServiceName}, StateName = {s
handle_event(_, #ssh_msg_service_accept{name = "ssh-userauth"}, {service_request,client},
#data{ssh_params = #ssh{service="ssh-userauth"} = Ssh0} = State) ->
{Msg, Ssh} = ssh_auth:init_userauth_request_msg(Ssh0),
- ok = send_bytes(Msg, State),
+ send_bytes(Msg, State),
{next_state, {userauth,client}, State#data{auth_user = Ssh#ssh.user, ssh_params = Ssh}};
@@ -709,7 +710,7 @@ handle_event(_,
%% Probably the very first userauth_request but we deny unauthorized login
{not_authorized, _, {Reply,Ssh}} =
ssh_auth:handle_userauth_request(Msg, Ssh0#ssh.session_id, Ssh0),
- ok = send_bytes(Reply, D),
+ send_bytes(Reply, D),
{keep_state, D#data{ssh_params = Ssh}};
{"ssh-connection", "ssh-connection", Method} ->
@@ -719,7 +720,7 @@ handle_event(_,
%% Yepp! we support this method
case ssh_auth:handle_userauth_request(Msg, Ssh0#ssh.session_id, Ssh0) of
{authorized, User, {Reply, Ssh}} ->
- ok = send_bytes(Reply, D),
+ send_bytes(Reply, D),
D#data.starter ! ssh_connected,
connected_fun(User, Method, D),
{next_state, {connected,server},
@@ -727,11 +728,11 @@ handle_event(_,
ssh_params = Ssh#ssh{authenticated = true}}};
{not_authorized, {User, Reason}, {Reply, Ssh}} when Method == "keyboard-interactive" ->
retry_fun(User, Reason, D),
- ok = send_bytes(Reply, D),
+ send_bytes(Reply, D),
{next_state, {userauth_keyboard_interactive,server}, D#data{ssh_params = Ssh}};
{not_authorized, {User, Reason}, {Reply, Ssh}} ->
retry_fun(User, Reason, D),
- ok = send_bytes(Reply, D),
+ send_bytes(Reply, D),
{keep_state, D#data{ssh_params = Ssh}}
end;
false ->
@@ -1512,7 +1513,8 @@ send_msg(Msg, State=#data{ssh_params=Ssh0}) when is_tuple(Msg) ->
State#data{ssh_params=Ssh}.
send_bytes(Bytes, #data{socket = Socket, transport_cb = Transport}) ->
- Transport:send(Socket, Bytes).
+ _ = Transport:send(Socket, Bytes),
+ ok.
handle_version({2, 0} = NumVsn, StrVsn, Ssh0) ->
Ssh = counterpart_versions(NumVsn, StrVsn, Ssh0),
--
cgit v1.2.3
From 646148180690881b0b8148705a15764a39538924 Mon Sep 17 00:00:00 2001
From: Erlang/OTP
Date: Thu, 13 Oct 2016 16:17:10 +0200
Subject: Prepare release
---
lib/ssh/doc/src/notes.xml | 17 +++++++++++++++++
lib/ssh/vsn.mk | 2 +-
2 files changed, 18 insertions(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index f6ad8d8dea..773a472818 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -30,6 +30,23 @@
notes.xml
+Ssh 4.3.5
+
+ Fixed Bugs and Malfunctions
+
+ -
+
+ If a client illegaly sends an info-line and then
+ immediatly closes the TCP-connection, a badmatch
+ exception was raised.
+
+ Own Id: OTP-13966
+
+
+
+
+
+
Ssh 4.3.4
Fixed Bugs and Malfunctions
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index 536e559514..7eeeaf796e 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,5 +1,5 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 4.3.4
+SSH_VSN = 4.3.5
APP_VSN = "ssh-$(SSH_VSN)"
--
cgit v1.2.3
From dff506800fe54de928e430ce8e76f4eeb76100fb Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 17 Oct 2016 12:54:06 +0200
Subject: ssh: test case for renegotiation with openssh client
---
lib/ssh/test/ssh_test_lib.erl | 10 +++++++++
lib/ssh/test/ssh_to_openssh_SUITE.erl | 38 ++++++++++++++++++++++++++++++++++-
2 files changed, 47 insertions(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl
index c43c6519f9..6fd401d182 100644
--- a/lib/ssh/test/ssh_test_lib.erl
+++ b/lib/ssh/test/ssh_test_lib.erl
@@ -208,6 +208,16 @@ reply(TestCase, Result) ->
rcv_expected(Expect, SshPort, Timeout) ->
receive
+ {SshPort, Recvd} when is_function(Expect) ->
+ case Expect(Recvd) of
+ true ->
+ ct:log("Got expected ~p from ~p",[Recvd,SshPort]),
+ catch port_close(SshPort),
+ rcv_lingering(50);
+ false ->
+ ct:log("Got UNEXPECTED ~p~n",[Recvd]),
+ rcv_expected(Expect, SshPort, Timeout)
+ end;
{SshPort, Expect} ->
ct:log("Got expected ~p from ~p",[Expect,SshPort]),
catch port_close(SshPort),
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl
index a914938c41..f481e9c1ce 100644
--- a/lib/ssh/test/ssh_to_openssh_SUITE.erl
+++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl
@@ -58,7 +58,8 @@ groups() ->
erlang_client_openssh_server_nonexistent_subsystem
]},
{erlang_server, [], [erlang_server_openssh_client_public_key_dsa,
- erlang_server_openssh_client_public_key_rsa
+ erlang_server_openssh_client_public_key_rsa,
+ erlang_server_openssh_client_renegotiate
]}
].
@@ -385,6 +386,41 @@ erlang_server_openssh_client_public_key_X(Config, PubKeyAlg) ->
ssh_test_lib:rcv_expected({data,<<"2\n">>}, OpenSsh, ?TIMEOUT),
ssh:stop_daemon(Pid).
+%%--------------------------------------------------------------------
+%% Test that the Erlang/OTP server can renegotiate with openSSH
+erlang_server_openssh_client_renegotiate(Config) ->
+ PubKeyAlg = ssh_rsa,
+ SystemDir = proplists:get_value(data_dir, Config),
+ PrivDir = proplists:get_value(priv_dir, Config),
+ KnownHosts = filename:join(PrivDir, "known_hosts"),
+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ {public_key_alg, PubKeyAlg},
+ {failfun, fun ssh_test_lib:failfun/2}]),
+
+ ct:sleep(500),
+
+ DataFile = filename:join(PrivDir, "renegotiate_openssh_client.data"),
+ Data = lists:duplicate(32000, $a),
+ ok = file:write_file(DataFile, Data),
+
+ Cmd = "ssh -p " ++ integer_to_list(Port) ++
+ " -o UserKnownHostsFile=" ++ KnownHosts ++
+ " -o RekeyLimit=20K" ++
+ " " ++ Host ++ " < " ++ DataFile,
+ OpenSsh = ssh_test_lib:open_port({spawn, Cmd}),
+
+ Expect = fun({data,R}) ->
+ try lists:prefix(binary_to_list(R), Data)
+ catch
+ _:_ -> false
+ end;
+ (_) ->
+ false
+ end,
+
+ ssh_test_lib:rcv_expected(Expect, OpenSsh, ?TIMEOUT),
+ ssh:stop_daemon(Pid).
+
%%--------------------------------------------------------------------
erlang_client_openssh_server_password() ->
[{doc, "Test client password option"}].
--
cgit v1.2.3
From e875ff334a6d6f8db547868e5d57e71c80ff1859 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 17 Oct 2016 12:03:21 +0200
Subject: ssh: fix renegotiation problem
---
lib/ssh/src/ssh_connection_handler.erl | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index ced049f0d0..dd414894d4 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -671,8 +671,9 @@ handle_event(_, #ssh_msg_newkeys{} = Msg, {new_keys,Role,init}, D) ->
{next_state, {service_request,Role}, D#data{ssh_params=Ssh}};
%% Subsequent key exchange rounds (renegotiation):
-handle_event(_, #ssh_msg_newkeys{}, {new_keys,Role,renegotiate}, D) ->
- {next_state, {connected,Role}, D};
+handle_event(_, #ssh_msg_newkeys{} = Msg, {new_keys,Role,renegotiate}, D) ->
+ {ok, Ssh} = ssh_transport:handle_new_keys(Msg, D#data.ssh_params),
+ {next_state, {connected,Role}, D#data{ssh_params=Ssh}};
%%% ######## {service_request, client|server}
--
cgit v1.2.3
From ea5e385f9e20e29e34fdc12480e8fd00241d9093 Mon Sep 17 00:00:00 2001
From: Erlang/OTP
Date: Mon, 17 Oct 2016 14:20:07 +0200
Subject: Prepare release
---
lib/ssh/doc/src/notes.xml | 15 +++++++++++++++
lib/ssh/vsn.mk | 2 +-
2 files changed, 16 insertions(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index 773a472818..f5a67bc00e 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -30,6 +30,21 @@
notes.xml
+Ssh 4.3.6
+
+ Fixed Bugs and Malfunctions
+
+ -
+
+ Re-negotiation problems with OpenSSH client solved.
+
+ Own Id: OTP-13972
+
+
+
+
+
+
Ssh 4.3.5
Fixed Bugs and Malfunctions
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index 7eeeaf796e..c023429056 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,5 +1,5 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 4.3.5
+SSH_VSN = 4.3.6
APP_VSN = "ssh-$(SSH_VSN)"
--
cgit v1.2.3
From 1e9134eaac9df9743e28e5eb5913d76fa556a52b Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 24 Oct 2016 15:34:33 +0200
Subject: ssh: Reduce the renegotiation limit in test with OpenSSH client in
ssh_to_openssh_SUITE:erlang_server_openssh_client_renegotiate/1
The reason is that it seems that on some small machines
we get an out-of-memory exception if the limit is to high.
This is probably because a chunk of data larger than the limit
is piped from a file into the OpenSSH runing in a shell in a port.
---
lib/ssh/test/ssh_to_openssh_SUITE.erl | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl
index f481e9c1ce..34d65ddbfd 100644
--- a/lib/ssh/test/ssh_to_openssh_SUITE.erl
+++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl
@@ -399,18 +399,26 @@ erlang_server_openssh_client_renegotiate(Config) ->
ct:sleep(500),
+ RenegLimitK = 3,
DataFile = filename:join(PrivDir, "renegotiate_openssh_client.data"),
- Data = lists:duplicate(32000, $a),
+ Data = lists:duplicate(trunc(1.1*RenegLimitK*1024), $a),
ok = file:write_file(DataFile, Data),
Cmd = "ssh -p " ++ integer_to_list(Port) ++
" -o UserKnownHostsFile=" ++ KnownHosts ++
- " -o RekeyLimit=20K" ++
+ " -o RekeyLimit=" ++ integer_to_list(RenegLimitK) ++"K" ++
" " ++ Host ++ " < " ++ DataFile,
OpenSsh = ssh_test_lib:open_port({spawn, Cmd}),
Expect = fun({data,R}) ->
- try lists:prefix(binary_to_list(R), Data)
+ try
+ NonAlphaChars = [C || C<-lists:seq(1,255),
+ not lists:member(C,lists:seq($a,$z)),
+ not lists:member(C,lists:seq($A,$Z))
+ ],
+ Lines = string:tokens(binary_to_list(R), NonAlphaChars),
+ lists:any(fun(L) -> lists:prefix(L, Data) end,
+ Lines)
catch
_:_ -> false
end;
--
cgit v1.2.3
From f52b2eca4fd8efdde8d0c178d03ddce780bc61b1 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 27 Oct 2016 15:11:32 +0200
Subject: ssh: improve result processing in test
---
lib/ssh/test/ssh_to_openssh_SUITE.erl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl
index 34d65ddbfd..82288ca142 100644
--- a/lib/ssh/test/ssh_to_openssh_SUITE.erl
+++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl
@@ -417,7 +417,7 @@ erlang_server_openssh_client_renegotiate(Config) ->
not lists:member(C,lists:seq($A,$Z))
],
Lines = string:tokens(binary_to_list(R), NonAlphaChars),
- lists:any(fun(L) -> lists:prefix(L, Data) end,
+ lists:any(fun(L) -> length(L)>1 andalso lists:prefix(L, Data) end,
Lines)
catch
_:_ -> false
--
cgit v1.2.3
From f26d0ba5d3d4c75df593b3406b9f3f3b81560e3c Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Tue, 25 Oct 2016 11:48:33 +0200
Subject: ssh: better ssh_basic_SUITE:end_per_suite/2
The testcases shell_unicode_string and shell_no_unicode in ssh_basic_SUITE could
raise an exception in the end_per_suite when stopping the dameon. This is due to
a natural race condition between the server and the client.
---
lib/ssh/test/ssh_basic_SUITE.erl | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index 51e0d5196b..b102ede1cb 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -343,14 +343,15 @@ end_per_testcase(TC, Config) when TC==shell_no_unicode ;
TC==shell_unicode_string ->
case proplists:get_value(sftpd, Config) of
{Pid, _, _} ->
- ssh:stop_daemon(Pid),
- ssh:stop();
+ catch ssh:stop_daemon(Pid);
_ ->
- ssh:stop()
- end;
+ ok
+ end,
+ end_per_testcase(Config);
end_per_testcase(_TestCase, Config) ->
end_per_testcase(Config).
-end_per_testcase(_Config) ->
+
+end_per_testcase(_Config) ->
ssh:stop(),
ok.
--
cgit v1.2.3
From 39cb552ba0a5aaa36cb07526b3b895677ba1f3dc Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 26 Oct 2016 12:31:27 +0200
Subject: ssh: Add a 'catch' in ssh_channel.erl to prevent double close errors
---
lib/ssh/src/ssh_channel.erl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_channel.erl b/lib/ssh/src/ssh_channel.erl
index 426e2f5125..85b31f3669 100644
--- a/lib/ssh/src/ssh_channel.erl
+++ b/lib/ssh/src/ssh_channel.erl
@@ -261,7 +261,7 @@ handle_info({ssh_cm, _, _} = Msg, #state{cm = ConnectionManager,
adjust_window(Msg),
{noreply, State#state{channel_state = ChannelState}, Timeout};
{stop, ChannelId, ChannelState} ->
- ssh_connection:close(ConnectionManager, ChannelId),
+ catch ssh_connection:close(ConnectionManager, ChannelId),
{stop, normal, State#state{close_sent = true,
channel_state = ChannelState}}
end;
--
cgit v1.2.3
From 22a29422236f28adc24090dace03c0fd29311c9c Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 27 Oct 2016 15:14:38 +0200
Subject: ssh: more info about shrinked binaries in ssh_dbg
---
lib/ssh/src/ssh_dbg.erl | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_dbg.erl b/lib/ssh/src/ssh_dbg.erl
index bd6bc0335b..ce5596e0f9 100644
--- a/lib/ssh/src/ssh_dbg.erl
+++ b/lib/ssh/src/ssh_dbg.erl
@@ -113,7 +113,12 @@ setup_tracer(Write, MangleArg) ->
ok.
%%%----------------------------------------------------------------
-shrink_bin(B) when is_binary(B), size(B)>100 -> {'*** SHRINKED BIN',size(B),element(1,split_binary(B,20)),'***'};
+shrink_bin(B) when is_binary(B), size(B)>100 -> {'*** SHRINKED BIN',
+ size(B),
+ element(1,split_binary(B,20)),
+ '...',
+ element(2,split_binary(B,size(B)-20))
+ };
shrink_bin(L) when is_list(L) -> lists:map(fun shrink_bin/1, L);
shrink_bin(T) when is_tuple(T) -> list_to_tuple(shrink_bin(tuple_to_list(T)));
shrink_bin(X) -> X.
--
cgit v1.2.3
From 520e2ab8eac8d91fd4fef56729f16614052a6655 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 27 Oct 2016 15:21:07 +0200
Subject: ssh: trace all messages in
ssh_to_openssh_SUITE:erlang_server_openssh_client_renegotiate/1
---
lib/ssh/test/ssh_to_openssh_SUITE.erl | 1 +
1 file changed, 1 insertion(+)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl
index 82288ca142..230b7d2191 100644
--- a/lib/ssh/test/ssh_to_openssh_SUITE.erl
+++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl
@@ -397,6 +397,7 @@ erlang_server_openssh_client_renegotiate(Config) ->
{public_key_alg, PubKeyAlg},
{failfun, fun ssh_test_lib:failfun/2}]),
+ ssh_dbg:messages(fun(String,_D) -> ct:log(String) end),
ct:sleep(500),
RenegLimitK = 3,
--
cgit v1.2.3
From 56627426e9a0ffb516a11ec2d4bd737c24fa3fd1 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 28 Oct 2016 13:04:29 +0200
Subject: ssh: increase timeout in test in ssh_options_SUITE Prevents timeout
before the processing is done on slow machines
---
lib/ssh/test/ssh_options_SUITE.erl | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_options_SUITE.erl b/lib/ssh/test/ssh_options_SUITE.erl
index 61883c0647..9b1ff65e64 100644
--- a/lib/ssh/test/ssh_options_SUITE.erl
+++ b/lib/ssh/test/ssh_options_SUITE.erl
@@ -540,10 +540,18 @@ connectfun_disconnectfun_server(Config) ->
{disconnect,Ref,R} ->
ct:log("Disconnect result: ~p",[R]),
ssh:stop_daemon(Pid)
- after 2000 ->
+ after 5000 ->
+ receive
+ X -> ct:log("received ~p",[X])
+ after 0 -> ok
+ end,
{fail, "No disconnectfun action"}
end
- after 2000 ->
+ after 5000 ->
+ receive
+ X -> ct:log("received ~p",[X])
+ after 0 -> ok
+ end,
{fail, "No connectfun action"}
end.
@@ -649,7 +657,7 @@ disconnectfun_option_server(Config) ->
ct:log("Server detected disconnect: ~p",[Reason]),
ssh:stop_daemon(Pid),
ok
- after 3000 ->
+ after 5000 ->
receive
X -> ct:log("received ~p",[X])
after 0 -> ok
--
cgit v1.2.3
From 284d4e244c6c4605c619cb44d807464bd5bc8f52 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 28 Oct 2016 13:28:24 +0200
Subject: ssh: change of test helper ssh_test_lib:start_shell
---
lib/ssh/test/ssh_basic_SUITE.erl | 22 +++++++++++-----------
lib/ssh/test/ssh_options_SUITE.erl | 2 +-
lib/ssh/test/ssh_test_lib.erl | 27 +++++++++++----------------
3 files changed, 23 insertions(+), 28 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index b102ede1cb..0a0ab5cdf7 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -315,9 +315,9 @@ init_per_testcase(TC, Config) when TC==shell_no_unicode ;
{user_passwords, [{"foo", "bar"}]}]),
ct:sleep(500),
IO = ssh_test_lib:start_io_server(),
- Shell = ssh_test_lib:start_shell(Port, IO, UserDir,
- [{silently_accept_hosts, true},
- {user,"foo"},{password,"bar"}]),
+ Shell = ssh_test_lib:start_shell(Port, IO, [{user_dir,UserDir},
+ {silently_accept_hosts, true},
+ {user,"foo"},{password,"bar"}]),
ct:log("IO=~p, Shell=~p, self()=~p",[IO,Shell,self()]),
ct:log("file:native_name_encoding() = ~p,~nio:getopts() = ~p",
[file:native_name_encoding(),io:getopts()]),
@@ -525,7 +525,7 @@ shell(Config) when is_list(Config) ->
ct:sleep(500),
IO = ssh_test_lib:start_io_server(),
- Shell = ssh_test_lib:start_shell(Port, IO, UserDir),
+ Shell = ssh_test_lib:start_shell(Port, IO, [{user_dir,UserDir}]),
receive
{'EXIT', _, _} ->
ct:fail(no_ssh_connection);
@@ -563,10 +563,10 @@ exec_key_differs(Config, UserPKAlgs) ->
ct:sleep(500),
IO = ssh_test_lib:start_io_server(),
- Shell = ssh_test_lib:start_shell(Port, IO, UserDir,
- [{preferred_algorithms,[{public_key,['ssh-rsa']}]},
- {pref_public_key_algs,UserPKAlgs}
- ]),
+ Shell = ssh_test_lib:start_shell(Port, IO, [{user_dir,UserDir},
+ {preferred_algorithms,[{public_key,['ssh-rsa']}]},
+ {pref_public_key_algs,UserPKAlgs}
+ ]),
receive
@@ -597,9 +597,9 @@ exec_key_differs_fail(Config) when is_list(Config) ->
ct:sleep(500),
IO = ssh_test_lib:start_io_server(),
- ssh_test_lib:start_shell(Port, IO, UserDir,
- [{preferred_algorithms,[{public_key,['ssh-rsa']}]},
- {pref_public_key_algs,['ssh-dss']}]),
+ ssh_test_lib:start_shell(Port, IO, [{user_dir,UserDir},
+ {preferred_algorithms,[{public_key,['ssh-rsa']}]},
+ {pref_public_key_algs,['ssh-dss']}]),
receive
{'EXIT', _, _} ->
ok;
diff --git a/lib/ssh/test/ssh_options_SUITE.erl b/lib/ssh/test/ssh_options_SUITE.erl
index 9b1ff65e64..60eae5a850 100644
--- a/lib/ssh/test/ssh_options_SUITE.erl
+++ b/lib/ssh/test/ssh_options_SUITE.erl
@@ -1011,7 +1011,7 @@ ssh_connect_nonegtimeout_connected(Config, Parallel) ->
ct:sleep(500),
IO = ssh_test_lib:start_io_server(),
- Shell = ssh_test_lib:start_shell(Port, IO, UserDir),
+ Shell = ssh_test_lib:start_shell(Port, IO, [{user_dir,UserDir}]),
receive
Error = {'EXIT', _, _} ->
ct:log("~p",[Error]),
diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl
index 6fd401d182..6c8fd95b2e 100644
--- a/lib/ssh/test/ssh_test_lib.erl
+++ b/lib/ssh/test/ssh_test_lib.erl
@@ -127,24 +127,19 @@ std_simple_exec(Host, Port, Config, Opts) ->
ssh:close(ConnectionRef).
-start_shell(Port, IOServer, 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, []]).
-
-init_shell(Port, IOServer, UserDir) ->
- Host = hostname(),
- Options = [{user_interaction, false}, {silently_accept_hosts,
- true}] ++ UserDir,
- group_leader(IOServer, self()),
- loop_shell(Host, Port, Options).
+ start_shell(Port, IOServer, []).
+
+start_shell(Port, IOServer, ExtraOptions) ->
+ spawn_link(
+ fun() ->
+ Host = hostname(),
+ Options = [{user_interaction, false},
+ {silently_accept_hosts,true} | ExtraOptions],
+ group_leader(IOServer, self()),
+ ssh:shell(Host, Port, Options)
+ end).
-loop_shell(Host, Port, Options) ->
- ssh:shell(Host, Port, Options).
start_io_server() ->
spawn_link(?MODULE, init_io_server, [self()]).
--
cgit v1.2.3
From 46bed9a80840ce658c16d6983c0b3a2548bf1a6b Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 28 Oct 2016 17:57:31 +0200
Subject: ssh: move rekeying test to ssh_test_lib
---
lib/ssh/test/ssh_renegotiate_SUITE.erl | 40 ++++++++++------------------------
lib/ssh/test/ssh_test_lib.erl | 17 +++++++++++++++
2 files changed, 29 insertions(+), 28 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_renegotiate_SUITE.erl b/lib/ssh/test/ssh_renegotiate_SUITE.erl
index b10ec3707f..74bbc291b2 100644
--- a/lib/ssh/test/ssh_renegotiate_SUITE.erl
+++ b/lib/ssh/test/ssh_renegotiate_SUITE.erl
@@ -92,11 +92,11 @@ rekey(Config) ->
ConnectionRef =
ssh_test_lib:std_connect(Config, Host, Port,
[{rekey_limit, 0}]),
- Kex1 = get_kex_init(ConnectionRef),
+ Kex1 = ssh_test_lib:get_kex_init(ConnectionRef),
receive
after ?REKEY_DATA_TMO ->
%%By this time rekeying would have been done
- Kex2 = get_kex_init(ConnectionRef),
+ Kex2 = ssh_test_lib:get_kex_init(ConnectionRef),
false = (Kex2 == Kex1),
ssh:close(ConnectionRef),
ssh:stop_daemon(Pid)
@@ -120,31 +120,31 @@ rekey_limit(Config) ->
{max_random_length_padding,0}]),
{ok, SftpPid} = ssh_sftp:start_channel(ConnectionRef),
- Kex1 = get_kex_init(ConnectionRef),
+ Kex1 = ssh_test_lib:get_kex_init(ConnectionRef),
timer:sleep(?REKEY_DATA_TMO),
- Kex1 = get_kex_init(ConnectionRef),
+ Kex1 = ssh_test_lib:get_kex_init(ConnectionRef),
Data = lists:duplicate(159000,1),
ok = ssh_sftp:write_file(SftpPid, DataFile, Data),
timer:sleep(?REKEY_DATA_TMO),
- Kex2 = get_kex_init(ConnectionRef),
+ Kex2 = ssh_test_lib:get_kex_init(ConnectionRef),
false = (Kex2 == Kex1),
timer:sleep(?REKEY_DATA_TMO),
- Kex2 = get_kex_init(ConnectionRef),
+ Kex2 = ssh_test_lib:get_kex_init(ConnectionRef),
ok = ssh_sftp:write_file(SftpPid, DataFile, "hi\n"),
timer:sleep(?REKEY_DATA_TMO),
- Kex2 = get_kex_init(ConnectionRef),
+ Kex2 = ssh_test_lib:get_kex_init(ConnectionRef),
false = (Kex2 == Kex1),
timer:sleep(?REKEY_DATA_TMO),
- Kex2 = get_kex_init(ConnectionRef),
+ Kex2 = ssh_test_lib:get_kex_init(ConnectionRef),
ssh_sftp:stop_channel(SftpPid),
ssh:close(ConnectionRef),
@@ -169,7 +169,7 @@ renegotiate1(Config) ->
ConnectionRef = ssh_test_lib:std_connect(Config, Host, RPort, [{max_random_length_padding,0}]),
{ok, SftpPid} = ssh_sftp:start_channel(ConnectionRef),
- Kex1 = get_kex_init(ConnectionRef),
+ Kex1 = ssh_test_lib:get_kex_init(ConnectionRef),
{ok, Handle} = ssh_sftp:open(SftpPid, DataFile, [write]),
@@ -181,7 +181,7 @@ renegotiate1(Config) ->
timer:sleep(2000),
- Kex2 = get_kex_init(ConnectionRef),
+ Kex2 = ssh_test_lib:get_kex_init(ConnectionRef),
false = (Kex2 == Kex1),
@@ -208,7 +208,7 @@ renegotiate2(Config) ->
ConnectionRef = ssh_test_lib:std_connect(Config, Host, RPort, [{max_random_length_padding,0}]),
{ok, SftpPid} = ssh_sftp:start_channel(ConnectionRef),
- Kex1 = get_kex_init(ConnectionRef),
+ Kex1 = ssh_test_lib:get_kex_init(ConnectionRef),
{ok, Handle} = ssh_sftp:open(SftpPid, DataFile, [write]),
@@ -223,7 +223,7 @@ renegotiate2(Config) ->
timer:sleep(2000),
- Kex2 = get_kex_init(ConnectionRef),
+ Kex2 = ssh_test_lib:get_kex_init(ConnectionRef),
false = (Kex2 == Kex1),
@@ -235,19 +235,3 @@ renegotiate2(Config) ->
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
-%% get_kex_init - helper function to get key_exchange_init_msg
-get_kex_init(Conn) ->
- %% First, validate the key exchange is complete (StateName == connected)
- {{connected,_},S} = sys:get_state(Conn),
- %% Next, walk through the elements of the #state record looking
- %% for the #ssh_msg_kexinit record. This method is robust against
- %% changes to either record. The KEXINIT message contains a cookie
- %% unique to each invocation of the key exchange procedure (RFC4253)
- SL = tuple_to_list(S),
- case lists:keyfind(ssh_msg_kexinit, 1, SL) of
- false ->
- throw(not_found);
- KexInit ->
- KexInit
- end.
-
diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl
index 6c8fd95b2e..7cd364a6dc 100644
--- a/lib/ssh/test/ssh_test_lib.erl
+++ b/lib/ssh/test/ssh_test_lib.erl
@@ -797,3 +797,20 @@ busy_wait(Nus, T0) ->
end.
%%%----------------------------------------------------------------
+%% get_kex_init - helper function to get key_exchange_init_msg
+
+get_kex_init(Conn) ->
+ %% First, validate the key exchange is complete (StateName == connected)
+ {{connected,_},S} = sys:get_state(Conn),
+ %% Next, walk through the elements of the #state record looking
+ %% for the #ssh_msg_kexinit record. This method is robust against
+ %% changes to either record. The KEXINIT message contains a cookie
+ %% unique to each invocation of the key exchange procedure (RFC4253)
+ SL = tuple_to_list(S),
+ case lists:keyfind(ssh_msg_kexinit, 1, SL) of
+ false ->
+ throw(not_found);
+ KexInit ->
+ KexInit
+ end.
+
--
cgit v1.2.3
From fc3bef2215a15a91d7f8f58d2a039477bcff25e0 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 28 Oct 2016 17:58:48 +0200
Subject: ssh: test for rekey with OpenSSH server
---
lib/ssh/test/ssh_to_openssh_SUITE.erl | 93 ++++++++++++++++++++++++++++++++++-
1 file changed, 91 insertions(+), 2 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl
index 230b7d2191..9b43bad7f4 100644
--- a/lib/ssh/test/ssh_to_openssh_SUITE.erl
+++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl
@@ -29,6 +29,7 @@
-define(TIMEOUT, 50000).
-define(SSH_DEFAULT_PORT, 22).
+-define(REKEY_DATA_TMO, 65000).
%%--------------------------------------------------------------------
%% Common Test interface functions -----------------------------------
@@ -55,7 +56,8 @@ groups() ->
erlang_client_openssh_server_publickey_rsa,
erlang_client_openssh_server_password,
erlang_client_openssh_server_kexs,
- erlang_client_openssh_server_nonexistent_subsystem
+ erlang_client_openssh_server_nonexistent_subsystem,
+ erlang_client_openssh_server_renegotiate
]},
{erlang_server, [], [erlang_server_openssh_client_public_key_dsa,
erlang_server_openssh_client_public_key_rsa,
@@ -105,6 +107,11 @@ init_per_testcase(erlang_server_openssh_client_public_key_rsa, Config) ->
chk_key(sshc, 'ssh-rsa', ".ssh/id_rsa", Config);
init_per_testcase(erlang_client_openssh_server_publickey_dsa, Config) ->
chk_key(sshd, 'ssh-dss', ".ssh/id_dsa", Config);
+init_per_testcase(erlang_server_openssh_client_renegotiate, Config) ->
+ case os:type() of
+ {unix,_} -> ssh:start(), Config;
+ Type -> ct:fail("Unsupported test on ~p",[Type])
+ end;
init_per_testcase(_TestCase, Config) ->
ssh:start(),
Config.
@@ -393,11 +400,12 @@ erlang_server_openssh_client_renegotiate(Config) ->
SystemDir = proplists:get_value(data_dir, Config),
PrivDir = proplists:get_value(priv_dir, Config),
KnownHosts = filename:join(PrivDir, "known_hosts"),
+
{Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
{public_key_alg, PubKeyAlg},
{failfun, fun ssh_test_lib:failfun/2}]),
- ssh_dbg:messages(fun(String,_D) -> ct:log(String) end),
+ catch ssh_dbg:messages(fun(String,_D) -> ct:log(String) end),
ct:sleep(500),
RenegLimitK = 3,
@@ -428,8 +436,70 @@ erlang_server_openssh_client_renegotiate(Config) ->
end,
ssh_test_lib:rcv_expected(Expect, OpenSsh, ?TIMEOUT),
+ %% Unfortunatly we can't check that there has been a renegotiation, just trust OpenSSH.
ssh:stop_daemon(Pid).
+%%--------------------------------------------------------------------
+erlang_client_openssh_server_renegotiate(_Config) ->
+ process_flag(trap_exit, true),
+
+ IO = ssh_test_lib:start_io_server(),
+ Ref = make_ref(),
+ Parent = self(),
+
+ catch ssh_dbg:messages(fun(X,_) -> ct:pal(X) end),
+ Shell =
+ spawn_link(
+ fun() ->
+ Host = ssh_test_lib:hostname(),
+ Options = [{user_interaction, false},
+ {silently_accept_hosts,true}],
+ group_leader(IO, self()),
+ {ok, ConnRef} = ssh:connect(Host, ?SSH_DEFAULT_PORT, Options),
+ ct:pal("~p:~p ~p",[?MODULE,?LINE,self()]),
+ case ssh_connection:session_channel(ConnRef, infinity) of
+ {ok,ChannelId} ->
+ ct:pal("~p:~p ~p",[?MODULE,?LINE,self()]),
+ success = ssh_connection:ptty_alloc(ConnRef, ChannelId, []),
+ ct:pal("~p:~p ~p",[?MODULE,?LINE,self()]),
+ Args = [{channel_cb, ssh_shell},
+ {init_args,[ConnRef, ChannelId]},
+ {cm, ConnRef}, {channel_id, ChannelId}],
+ {ok, State} = ssh_channel:init([Args]),
+ ct:pal("~p:~p ~p",[?MODULE,?LINE,self()]),
+ Parent ! {ok, Ref, ConnRef},
+ ssh_channel:enter_loop(State);
+ Error ->
+ ct:pal("~p:~p ~p",[?MODULE,?LINE,self()]),
+ Parent ! {error, Ref, Error}
+ end,
+ ct:pal("~p:~p ~p",[?MODULE,?LINE,self()]),
+ receive
+ nothing -> ok
+ end
+ end),
+
+ ct:pal("~p:~p ~p",[?MODULE,?LINE,self()]),
+
+ receive
+ {error, Ref, Error} ->
+ ct:fail("Error=~p",[Error]);
+ {ok, Ref, ConnectionRef} ->
+ ct:pal("ConnRef = ~p",[ConnectionRef]),
+ IO ! {input, self(), "echo Hej\n"},
+ receive_hej(),
+ ct:pal("ConnRef = ~p",[ConnectionRef]),
+ Kex1 = ssh_test_lib:get_kex_init(ConnectionRef),
+ ssh_connection_handler:renegotiate(ConnectionRef),
+ IO ! {input, self(), "echo Hej\n"},
+ receive_hej(),
+ Kex2 = ssh_test_lib:get_kex_init(ConnectionRef),
+ IO ! {input, self(), "exit\n"},
+ receive_logout(),
+ receive_normal_exit(Shell),
+ true = (Kex1 =/= Kex2)
+ end.
+
%%--------------------------------------------------------------------
erlang_client_openssh_server_password() ->
[{doc, "Test client password option"}].
@@ -507,6 +577,25 @@ receive_hej() ->
30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE])
end.
+receive_data(Data) ->
+ receive
+ Info when is_binary(Info) ->
+ Lines = string:tokens(binary_to_list(Info), "\r\n "),
+ case lists:member(Data, Lines) of
+ true ->
+ ct:log("Expected result found in lines: ~p~n", [Lines]),
+ ok;
+ false ->
+ ct:log("Extra info: ~p~n", [Info]),
+ receive_data(Data)
+ end;
+ Other ->
+ ct:log("Unexpected: ~p",[Other]),
+ receive_data(Data)
+ after
+ 30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE])
+ end.
+
receive_logout() ->
receive
<<"logout">> ->
--
cgit v1.2.3
From 81c121e857beb30b7a30cb371adbdabc56973444 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 31 Oct 2016 10:04:03 +0100
Subject: ssh: Removed tracing in ssh_to_openssh_SUITE
---
lib/ssh/test/ssh_to_openssh_SUITE.erl | 14 ++------------
1 file changed, 2 insertions(+), 12 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl
index 9b43bad7f4..f378188b8b 100644
--- a/lib/ssh/test/ssh_to_openssh_SUITE.erl
+++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl
@@ -405,7 +405,7 @@ erlang_server_openssh_client_renegotiate(Config) ->
{public_key_alg, PubKeyAlg},
{failfun, fun ssh_test_lib:failfun/2}]),
- catch ssh_dbg:messages(fun(String,_D) -> ct:log(String) end),
+%% catch ssh_dbg:messages(fun(String,_D) -> ct:log(String) end),
ct:sleep(500),
RenegLimitK = 3,
@@ -447,7 +447,7 @@ erlang_client_openssh_server_renegotiate(_Config) ->
Ref = make_ref(),
Parent = self(),
- catch ssh_dbg:messages(fun(X,_) -> ct:pal(X) end),
+%% catch ssh_dbg:messages(fun(X,_) -> ct:log(X) end),
Shell =
spawn_link(
fun() ->
@@ -456,39 +456,29 @@ erlang_client_openssh_server_renegotiate(_Config) ->
{silently_accept_hosts,true}],
group_leader(IO, self()),
{ok, ConnRef} = ssh:connect(Host, ?SSH_DEFAULT_PORT, Options),
- ct:pal("~p:~p ~p",[?MODULE,?LINE,self()]),
case ssh_connection:session_channel(ConnRef, infinity) of
{ok,ChannelId} ->
- ct:pal("~p:~p ~p",[?MODULE,?LINE,self()]),
success = ssh_connection:ptty_alloc(ConnRef, ChannelId, []),
- ct:pal("~p:~p ~p",[?MODULE,?LINE,self()]),
Args = [{channel_cb, ssh_shell},
{init_args,[ConnRef, ChannelId]},
{cm, ConnRef}, {channel_id, ChannelId}],
{ok, State} = ssh_channel:init([Args]),
- ct:pal("~p:~p ~p",[?MODULE,?LINE,self()]),
Parent ! {ok, Ref, ConnRef},
ssh_channel:enter_loop(State);
Error ->
- ct:pal("~p:~p ~p",[?MODULE,?LINE,self()]),
Parent ! {error, Ref, Error}
end,
- ct:pal("~p:~p ~p",[?MODULE,?LINE,self()]),
receive
nothing -> ok
end
end),
- ct:pal("~p:~p ~p",[?MODULE,?LINE,self()]),
-
receive
{error, Ref, Error} ->
ct:fail("Error=~p",[Error]);
{ok, Ref, ConnectionRef} ->
- ct:pal("ConnRef = ~p",[ConnectionRef]),
IO ! {input, self(), "echo Hej\n"},
receive_hej(),
- ct:pal("ConnRef = ~p",[ConnectionRef]),
Kex1 = ssh_test_lib:get_kex_init(ConnectionRef),
ssh_connection_handler:renegotiate(ConnectionRef),
IO ! {input, self(), "echo Hej\n"},
--
cgit v1.2.3
From ba6202d58f56d1a2b71d1108b39d13d83505c085 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 31 Oct 2016 10:18:27 +0100
Subject: ssh: skip erlang_server_openssh_client_renegotiate test on non-unix
---
lib/ssh/test/ssh_to_openssh_SUITE.erl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl
index f378188b8b..b289327cbd 100644
--- a/lib/ssh/test/ssh_to_openssh_SUITE.erl
+++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl
@@ -110,7 +110,7 @@ init_per_testcase(erlang_client_openssh_server_publickey_dsa, Config) ->
init_per_testcase(erlang_server_openssh_client_renegotiate, Config) ->
case os:type() of
{unix,_} -> ssh:start(), Config;
- Type -> ct:fail("Unsupported test on ~p",[Type])
+ Type -> {skip, io_lib:format("Unsupported test on ~p",[Type])}
end;
init_per_testcase(_TestCase, Config) ->
ssh:start(),
--
cgit v1.2.3
From 1d6d13cc0ab1178d1603af90660963160817a03d Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 31 Oct 2016 10:21:56 +0100
Subject: ssh: simplify test in ssh_to_openssh_SUITE
---
lib/ssh/test/ssh_to_openssh_SUITE.erl | 28 +++-------------------------
1 file changed, 3 insertions(+), 25 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl
index b289327cbd..2fff097753 100644
--- a/lib/ssh/test/ssh_to_openssh_SUITE.erl
+++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl
@@ -153,7 +153,7 @@ erlang_shell_client_openssh_server(Config) when is_list(Config) ->
IO = ssh_test_lib:start_io_server(),
Shell = ssh_test_lib:start_shell(?SSH_DEFAULT_PORT, IO),
IO ! {input, self(), "echo Hej\n"},
- receive_hej(),
+ receive_data("Hej"),
IO ! {input, self(), "exit\n"},
receive_logout(),
receive_normal_exit(Shell).
@@ -478,11 +478,11 @@ erlang_client_openssh_server_renegotiate(_Config) ->
ct:fail("Error=~p",[Error]);
{ok, Ref, ConnectionRef} ->
IO ! {input, self(), "echo Hej\n"},
- receive_hej(),
+ receive_data("Hej"),
Kex1 = ssh_test_lib:get_kex_init(ConnectionRef),
ssh_connection_handler:renegotiate(ConnectionRef),
IO ! {input, self(), "echo Hej\n"},
- receive_hej(),
+ receive_data("Hej"),
Kex2 = ssh_test_lib:get_kex_init(ConnectionRef),
IO ! {input, self(), "exit\n"},
receive_logout(),
@@ -545,28 +545,6 @@ erlang_client_openssh_server_nonexistent_subsystem(Config) when is_list(Config)
%%--------------------------------------------------------------------
%%% Internal functions -----------------------------------------------
%%--------------------------------------------------------------------
-receive_hej() ->
- receive
- <<"Hej", _binary>> = Hej ->
- ct:log("Expected result: ~p~n", [Hej]);
- <<"Hej\n", _binary>> = Hej ->
- ct:log("Expected result: ~p~n", [Hej]);
- <<"Hej\r\n", _/binary>> = Hej ->
- ct:log("Expected result: ~p~n", [Hej]);
- Info ->
- Lines = binary:split(Info, [<<"\r\n">>], [global]),
- case lists:member(<<"Hej">>, Lines) of
- true ->
- ct:log("Expected result found in lines: ~p~n", [Lines]),
- ok;
- false ->
- ct:log("Extra info: ~p~n", [Info]),
- receive_hej()
- end
- after
- 30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE])
- end.
-
receive_data(Data) ->
receive
Info when is_binary(Info) ->
--
cgit v1.2.3
From 59ecab4221fd2b8938c2a3a65f82159626d6a273 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 31 Oct 2016 11:37:10 +0100
Subject: ssh: make test more precise in ssh_to_openssh_SUITE
---
lib/ssh/test/ssh_test_lib.erl | 44 +++++++++++++++++++++++++----------
lib/ssh/test/ssh_to_openssh_SUITE.erl | 10 ++++----
2 files changed, 37 insertions(+), 17 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl
index 7cd364a6dc..f93237f3e7 100644
--- a/lib/ssh/test/ssh_test_lib.erl
+++ b/lib/ssh/test/ssh_test_lib.erl
@@ -800,17 +800,37 @@ busy_wait(Nus, T0) ->
%% get_kex_init - helper function to get key_exchange_init_msg
get_kex_init(Conn) ->
+ Ref = make_ref(),
+ {ok,TRef} = timer:send_after(15000, {reneg_timeout,Ref}),
+ get_kex_init(Conn, Ref, TRef).
+
+get_kex_init(Conn, Ref, TRef) ->
%% First, validate the key exchange is complete (StateName == connected)
- {{connected,_},S} = sys:get_state(Conn),
- %% Next, walk through the elements of the #state record looking
- %% for the #ssh_msg_kexinit record. This method is robust against
- %% changes to either record. The KEXINIT message contains a cookie
- %% unique to each invocation of the key exchange procedure (RFC4253)
- SL = tuple_to_list(S),
- case lists:keyfind(ssh_msg_kexinit, 1, SL) of
- false ->
- throw(not_found);
- KexInit ->
- KexInit
- end.
+ case sys:get_state(Conn) of
+ {{connected,_}, S} ->
+ timer:cancel(TRef),
+ %% Next, walk through the elements of the #state record looking
+ %% for the #ssh_msg_kexinit record. This method is robust against
+ %% changes to either record. The KEXINIT message contains a cookie
+ %% unique to each invocation of the key exchange procedure (RFC4253)
+ SL = tuple_to_list(S),
+ case lists:keyfind(ssh_msg_kexinit, 1, SL) of
+ false ->
+ throw(not_found);
+ KexInit ->
+ KexInit
+ end;
+ {OtherState, S} ->
+ ct:log("Not in 'connected' state: ~p",[OtherState]),
+ receive
+ {reneg_timeout,Ref} ->
+ ct:log("S = ~p", [S]),
+ ct:fail(reneg_timeout)
+ after 0 ->
+ timer:sleep(100), % If renegotiation is complete we do not
+ % want to exit on the reneg_timeout
+ get_kex_init(Conn, Ref, TRef)
+ end
+ end.
+
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl
index 2fff097753..2c7fe7898f 100644
--- a/lib/ssh/test/ssh_to_openssh_SUITE.erl
+++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl
@@ -447,7 +447,7 @@ erlang_client_openssh_server_renegotiate(_Config) ->
Ref = make_ref(),
Parent = self(),
-%% catch ssh_dbg:messages(fun(X,_) -> ct:log(X) end),
+ catch ssh_dbg:messages(fun(X,_) -> ct:log(X) end),
Shell =
spawn_link(
fun() ->
@@ -477,12 +477,12 @@ erlang_client_openssh_server_renegotiate(_Config) ->
{error, Ref, Error} ->
ct:fail("Error=~p",[Error]);
{ok, Ref, ConnectionRef} ->
- IO ! {input, self(), "echo Hej\n"},
- receive_data("Hej"),
+ IO ! {input, self(), "echo Hej1\n"},
+ receive_data("Hej1"),
Kex1 = ssh_test_lib:get_kex_init(ConnectionRef),
ssh_connection_handler:renegotiate(ConnectionRef),
- IO ! {input, self(), "echo Hej\n"},
- receive_data("Hej"),
+ IO ! {input, self(), "echo Hej2\n"},
+ receive_data("Hej2"),
Kex2 = ssh_test_lib:get_kex_init(ConnectionRef),
IO ! {input, self(), "exit\n"},
receive_logout(),
--
cgit v1.2.3
From a5d638e4aa772f44f8ca071e1f7cf625ccc34c01 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 31 Oct 2016 11:46:09 +0100
Subject: ssh: retry in ssh_options_SUITE:ssh_connect_negtimeout_*
---
lib/ssh/test/ssh_options_SUITE.erl | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_options_SUITE.erl b/lib/ssh/test/ssh_options_SUITE.erl
index 60eae5a850..4cc12cbcbe 100644
--- a/lib/ssh/test/ssh_options_SUITE.erl
+++ b/lib/ssh/test/ssh_options_SUITE.erl
@@ -982,7 +982,14 @@ ssh_connect_negtimeout(Config, Parallel) ->
ct:sleep(round(Factor * NegTimeOut)),
case inet:sockname(Socket) of
- {ok,_} -> ct:fail("Socket not closed");
+ {ok,_} ->
+ %% Give it another chance...
+ ct:log("Sleep more...",[]),
+ ct:sleep(round(Factor * NegTimeOut)),
+ case inet:sockname(Socket) of
+ {ok,_} -> ct:fail("Socket not closed");
+ {error,_} -> ok
+ end;
{error,_} -> ok
end.
--
cgit v1.2.3
From 067d8310093620ce1139e8d8a030bce6dd22d886 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Tue, 1 Nov 2016 15:01:01 +0100
Subject: ssh: exported ssh_dbg:shrink_bin and ssh_dbg:wr_record/3 for
debugging purposes
---
lib/ssh/src/Makefile | 2 +-
lib/ssh/src/ssh_dbg.erl | 3 +++
lib/ssh/src/ssh_dbg.hrl | 27 +++++++++++++++++++++++++++
3 files changed, 31 insertions(+), 1 deletion(-)
create mode 100644 lib/ssh/src/ssh_dbg.hrl
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/Makefile b/lib/ssh/src/Makefile
index 69d5a47f83..7ab6f22424 100644
--- a/lib/ssh/src/Makefile
+++ b/lib/ssh/src/Makefile
@@ -96,7 +96,7 @@ APP_TARGET= $(EBIN)/$(APP_FILE)
APPUP_SRC= $(APPUP_FILE).src
APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
-INTERNAL_HRL_FILES = ssh_auth.hrl ssh_connect.hrl ssh_transport.hrl ssh.hrl ssh_userauth.hrl ssh_xfer.hrl
+INTERNAL_HRL_FILES = ssh_auth.hrl ssh_connect.hrl ssh_transport.hrl ssh.hrl ssh_userauth.hrl ssh_xfer.hrl ssh_dbg.hrl
# ----------------------------------------------------
# FLAGS
diff --git a/lib/ssh/src/ssh_dbg.erl b/lib/ssh/src/ssh_dbg.erl
index ce5596e0f9..dff2bae9f2 100644
--- a/lib/ssh/src/ssh_dbg.erl
+++ b/lib/ssh/src/ssh_dbg.erl
@@ -28,6 +28,9 @@
stop/0
]).
+-export([shrink_bin/1,
+ wr_record/3]).
+
-include("ssh.hrl").
-include("ssh_transport.hrl").
-include("ssh_connect.hrl").
diff --git a/lib/ssh/src/ssh_dbg.hrl b/lib/ssh/src/ssh_dbg.hrl
new file mode 100644
index 0000000000..e94664737b
--- /dev/null
+++ b/lib/ssh/src/ssh_dbg.hrl
@@ -0,0 +1,27 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-ifndef(SSH_DBG_HRL).
+-define(SSH_DBG_HRL, 1).
+
+-define(formatrec(RecName,R),
+ ssh_dbg:wr_record(R, record_info(fields,RecName), [])).
+
+-endif. % SSH_DBG_HRL defined
--
cgit v1.2.3
From a19ef3f11f400f5a79a05d06a5176561cd87cff8 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 3 Nov 2016 12:21:54 +0100
Subject: ssh: Testcase polishing
---
lib/ssh/test/ssh_connection_SUITE.erl | 97 ++++++++++++++++++++++-------------
lib/ssh/test/ssh_to_openssh_SUITE.erl | 22 +++++---
2 files changed, 75 insertions(+), 44 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_connection_SUITE.erl b/lib/ssh/test/ssh_connection_SUITE.erl
index bcf3b01824..e898d55b6f 100644
--- a/lib/ssh/test/ssh_connection_SUITE.erl
+++ b/lib/ssh/test/ssh_connection_SUITE.erl
@@ -381,13 +381,13 @@ do_interrupted_send(Config, SendSize, EchoSize) ->
{password, "morot"},
{subsystems, [{"echo_n",EchoSS_spec}]}]),
- ct:log("connect", []),
+ ct:log("~p:~p connect", [?MODULE,?LINE]),
ConnectionRef = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
{user, "foo"},
{password, "morot"},
{user_interaction, false},
{user_dir, UserDir}]),
- ct:log("connected", []),
+ ct:log("~p:~p connected", [?MODULE,?LINE]),
%% build big binary
Data = << <> || X <- lists:seq(1,SendSize div 4)>>,
@@ -399,9 +399,9 @@ do_interrupted_send(Config, SendSize, EchoSize) ->
Parent = self(),
ResultPid = spawn(
fun() ->
- ct:log("open channel",[]),
+ ct:log("~p:~p open channel",[?MODULE,?LINE]),
{ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity),
- ct:log("start subsystem", []),
+ ct:log("~p:~p start subsystem", [?MODULE,?LINE]),
case ssh_connection:subsystem(ConnectionRef, ChannelId, "echo_n", infinity) of
success ->
Parent ! {self(), channelId, ChannelId},
@@ -410,47 +410,69 @@ do_interrupted_send(Config, SendSize, EchoSize) ->
try collect_data(ConnectionRef, ChannelId)
of
ExpectedData ->
+ ct:log("~p:~p got expected data",[?MODULE,?LINE]),
ok;
- _ ->
- {fail,"unexpected result"}
+ Other ->
+ ct:log("~p:~p unexpect: ~p", [?MODULE,?LINE,Other]),
+ {fail,"unexpected result in listener"}
catch
Class:Exception ->
- {fail, io_lib:format("Exception ~p:~p",[Class,Exception])}
+ {fail, io_lib:format("Listener exception ~p:~p",[Class,Exception])}
end,
- Parent ! {self(), Result};
+ Parent ! {self(), result, Result};
Other ->
Parent ! {self(), channelId, error, Other}
end
end),
receive
+ {ResultPid, channelId, error, Other} ->
+ ct:log("~p:~p channelId error ~p", [?MODULE,?LINE,Other]),
+ ssh:close(ConnectionRef),
+ ssh:stop_daemon(Pid),
+ {fail, "ssh_connection:subsystem"};
+
{ResultPid, channelId, ChannelId} ->
- %% pre-adjust receive window so the other end doesn't block
- ct:log("adjust window", []),
- ssh_connection:adjust_window(ConnectionRef, ChannelId, size(ExpectedData) + 1),
-
- ct:log("going to send ~p bytes", [size(Data)]),
- case ssh_connection:send(ConnectionRef, ChannelId, Data, 30000) of
- {error, closed} ->
- ct:log("{error,closed} - That's what we expect :)", []),
- ok;
- Msg ->
- ct:log("Got ~p - that's bad, very bad indeed",[Msg]),
- ct:fail({expected,{error,closed}, got, Msg})
- end,
- ct:log("going to check the result (if it is available)", []),
+ ct:log("~p:~p ~p going to send ~p bytes", [?MODULE,?LINE,self(),size(Data)]),
+ SenderPid = spawn(fun() ->
+ Parent ! {self(), ssh_connection:send(ConnectionRef, ChannelId, Data, 30000)}
+ end),
receive
- {ResultPid, Result} ->
- ct:log("Got result: ~p", [Result]),
+ {ResultPid, result, {fail, Fail}} ->
+ ct:log("~p:~p Listener failed: ~p", [?MODULE,?LINE,Fail]),
+ {fail, Fail};
+
+ {ResultPid, result, Result} ->
+ ct:log("~p:~p Got result: ~p", [?MODULE,?LINE,Result]),
ssh:close(ConnectionRef),
ssh:stop_daemon(Pid),
- Result
- end;
+ ct:log("~p:~p Check sender", [?MODULE,?LINE]),
+ receive
+ {SenderPid, {error, closed}} ->
+ ct:log("~p:~p {error,closed} - That's what we expect :)",[?MODULE,?LINE]),
+ ok;
+ Msg ->
+ ct:log("~p:~p Not expected send result: ~p",[?MODULE,?LINE,Msg]),
+ {fail, "Not expected msg"}
+ end;
+
+ {SenderPid, {error, closed}} ->
+ ct:log("~p:~p {error,closed} - That's what we expect, but client channel handler has not reported yet",[?MODULE,?LINE]),
+ receive
+ {ResultPid, result, Result} ->
+ ct:log("~p:~p Now got the result: ~p", [?MODULE,?LINE,Result]),
+ ssh:close(ConnectionRef),
+ ssh:stop_daemon(Pid),
+ ok;
+ Msg ->
+ ct:log("~p:~p Got an unexpected msg ~p",[?MODULE,?LINE,Msg]),
+ {fail, "Un-expected msg"}
+ end;
- {ResultPid, channelId, error, Other} ->
- ssh:close(ConnectionRef),
- ssh:stop_daemon(Pid),
- {fail, io_lib:format("ssh_connection:subsystem: ~p",[Other])}
+ Msg ->
+ ct:log("~p:~p Got unexpected ~p",[?MODULE,?LINE,Msg]),
+ {fail, "Unexpected msg"}
+ end
end.
%%--------------------------------------------------------------------
@@ -910,34 +932,35 @@ big_cat_rx(ConnectionRef, ChannelId, Acc) ->
end.
collect_data(ConnectionRef, ChannelId) ->
- ct:log("Listener ~p running! ConnectionRef=~p, ChannelId=~p",[self(),ConnectionRef,ChannelId]),
+ ct:log("~p:~p Listener ~p running! ConnectionRef=~p, ChannelId=~p",[?MODULE,?LINE,self(),ConnectionRef,ChannelId]),
collect_data(ConnectionRef, ChannelId, [], 0).
collect_data(ConnectionRef, ChannelId, Acc, Sum) ->
TO = 5000,
receive
{ssh_cm, ConnectionRef, {data, ChannelId, 0, Data}} when is_binary(Data) ->
- ct:log("collect_data: received ~p bytes. total ~p bytes",[size(Data),Sum+size(Data)]),
+ ct:log("~p:~p collect_data: received ~p bytes. total ~p bytes",[?MODULE,?LINE,size(Data),Sum+size(Data)]),
+ ssh_connection:adjust_window(ConnectionRef, ChannelId, size(Data)),
collect_data(ConnectionRef, ChannelId, [Data | Acc], Sum+size(Data));
{ssh_cm, ConnectionRef, {eof, ChannelId}} ->
try
iolist_to_binary(lists:reverse(Acc))
of
Bin ->
- ct:log("collect_data: received eof.~nGot in total ~p bytes",[size(Bin)]),
+ ct:log("~p:~p collect_data: received eof.~nGot in total ~p bytes",[?MODULE,?LINE,size(Bin)]),
Bin
catch
C:E ->
- ct:log("collect_data: received eof.~nAcc is strange...~nException=~p:~p~nAcc=~p",
- [C,E,Acc]),
+ ct:log("~p:~p collect_data: received eof.~nAcc is strange...~nException=~p:~p~nAcc=~p",
+ [?MODULE,?LINE,C,E,Acc]),
{error,{C,E}}
end;
Msg ->
- ct:log("collect_data: ***** unexpected message *****~n~p",[Msg]),
+ ct:log("~p:~p collect_data: ***** unexpected message *****~n~p",[?MODULE,?LINE,Msg]),
collect_data(ConnectionRef, ChannelId, Acc, Sum)
after TO ->
- ct:log("collect_data: ----- Nothing received for ~p seconds -----~n",[]),
+ ct:log("~p:~p collect_data: ----- Nothing received for ~p seconds -----~n",[?MODULE,?LINE,TO]),
collect_data(ConnectionRef, ChannelId, Acc, Sum)
end.
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl
index 2c7fe7898f..86c3d5de26 100644
--- a/lib/ssh/test/ssh_to_openssh_SUITE.erl
+++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl
@@ -404,8 +404,6 @@ erlang_server_openssh_client_renegotiate(Config) ->
{Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
{public_key_alg, PubKeyAlg},
{failfun, fun ssh_test_lib:failfun/2}]),
-
-%% catch ssh_dbg:messages(fun(String,_D) -> ct:log(String) end),
ct:sleep(500),
RenegLimitK = 3,
@@ -431,13 +429,24 @@ erlang_server_openssh_client_renegotiate(Config) ->
catch
_:_ -> false
end;
+
+ ({exit_status,E}) when E=/=0 ->
+ ct:log("exit_status ~p",[E]),
+ throw({skip,"exit status"});
+
(_) ->
false
end,
-
- ssh_test_lib:rcv_expected(Expect, OpenSsh, ?TIMEOUT),
- %% Unfortunatly we can't check that there has been a renegotiation, just trust OpenSSH.
- ssh:stop_daemon(Pid).
+
+ try
+ ssh_test_lib:rcv_expected(Expect, OpenSsh, ?TIMEOUT)
+ of
+ _ ->
+ %% Unfortunatly we can't check that there has been a renegotiation, just trust OpenSSH.
+ ssh:stop_daemon(Pid)
+ catch
+ throw:{skip,R} -> {skip,R}
+ end.
%%--------------------------------------------------------------------
erlang_client_openssh_server_renegotiate(_Config) ->
@@ -447,7 +456,6 @@ erlang_client_openssh_server_renegotiate(_Config) ->
Ref = make_ref(),
Parent = self(),
- catch ssh_dbg:messages(fun(X,_) -> ct:log(X) end),
Shell =
spawn_link(
fun() ->
--
cgit v1.2.3
From d1c8c59ec8bcec6758d7a00bed1d23e0907fb3a5 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 9 Nov 2016 12:51:57 +0100
Subject: ssh: Change order on next_event actions in ssh_connection_handler
---
lib/ssh/src/ssh_connection_handler.erl | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index dd414894d4..e7c52f345e 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -1194,12 +1194,12 @@ handle_event(info, {Proto, Sock, NewData}, StateName, D0 = #data{socket = Sock,
ssh_message:decode(set_kex_overload_prefix(DecryptedBytes,D))
of
Msg = #ssh_msg_kexinit{} ->
- {keep_state, D, [{next_event, internal, {Msg,DecryptedBytes}},
- {next_event, internal, prepare_next_packet}
+ {keep_state, D, [{next_event, internal, prepare_next_packet},
+ {next_event, internal, {Msg,DecryptedBytes}}
]};
Msg ->
- {keep_state, D, [{next_event, internal, Msg},
- {next_event, internal, prepare_next_packet}
+ {keep_state, D, [{next_event, internal, prepare_next_packet},
+ {next_event, internal, Msg}
]}
catch
_C:_E ->
--
cgit v1.2.3
From d13af8b8c6a7b04ec541585d1b8945103fffb988 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 11 Nov 2016 12:56:59 +0100
Subject: ssh: Adjust inet buffers if too small
---
lib/ssh/src/ssh_connection_handler.erl | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index e7c52f345e..7451c9e6d0 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -928,6 +928,7 @@ handle_event(internal, Msg=#ssh_msg_channel_request{}, StateName, D) -
handle_connection_msg(Msg, StateName, D);
handle_event(internal, Msg=#ssh_msg_channel_success{}, StateName, D) ->
+ update_inet_buffers(D#data.socket),
handle_connection_msg(Msg, StateName, D);
handle_event(internal, Msg=#ssh_msg_channel_failure{}, StateName, D) ->
@@ -1007,6 +1008,7 @@ handle_event(cast, {reply_request,success,ChannelId}, {connected,_}, D) ->
case ssh_channel:cache_lookup(cache(D), ChannelId) of
#channel{remote_id = RemoteId} ->
Msg = ssh_connection:channel_success_msg(RemoteId),
+ update_inet_buffers(D#data.socket),
{keep_state, send_msg(Msg,D)};
undefined ->
@@ -1738,6 +1740,11 @@ send_replies(Repls, State) ->
Repls).
get_repl({connection_reply,Msg}, {CallRepls,S}) ->
+ if is_record(Msg, ssh_msg_channel_success) ->
+ update_inet_buffers(S#data.socket);
+ true ->
+ ok
+ end,
{CallRepls, send_msg(Msg,S)};
get_repl({channel_data,undefined,_Data}, Acc) ->
Acc;
@@ -1926,3 +1933,13 @@ handshake(Pid, Ref, Timeout) ->
{error, timeout}
end.
+update_inet_buffers(Socket) ->
+ {ok, BufSzs0} = inet:getopts(Socket, [sndbuf,recbuf]),
+ MinVal = 655360,
+ case
+ [{Tag,MinVal} || {Tag,Val} <- BufSzs0,
+ Val < MinVal]
+ of
+ [] -> ok;
+ NewOpts -> inet:setopts(Socket, NewOpts)
+ end.
--
cgit v1.2.3
From 7acfeb55655ed2a2f1ec2ec1ee4dbfc112fc4c54 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 14 Nov 2016 10:18:02 +0100
Subject: ssh: interrupted_send receive loop reports missing number of bytes
---
lib/ssh/test/ssh_connection_SUITE.erl | 20 +++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_connection_SUITE.erl b/lib/ssh/test/ssh_connection_SUITE.erl
index e898d55b6f..fc7ea81caf 100644
--- a/lib/ssh/test/ssh_connection_SUITE.erl
+++ b/lib/ssh/test/ssh_connection_SUITE.erl
@@ -407,7 +407,7 @@ do_interrupted_send(Config, SendSize, EchoSize) ->
Parent ! {self(), channelId, ChannelId},
Result =
- try collect_data(ConnectionRef, ChannelId)
+ try collect_data(ConnectionRef, ChannelId, EchoSize)
of
ExpectedData ->
ct:log("~p:~p got expected data",[?MODULE,?LINE]),
@@ -931,23 +931,25 @@ big_cat_rx(ConnectionRef, ChannelId, Acc) ->
timeout
end.
-collect_data(ConnectionRef, ChannelId) ->
+collect_data(ConnectionRef, ChannelId, EchoSize) ->
ct:log("~p:~p Listener ~p running! ConnectionRef=~p, ChannelId=~p",[?MODULE,?LINE,self(),ConnectionRef,ChannelId]),
- collect_data(ConnectionRef, ChannelId, [], 0).
+ collect_data(ConnectionRef, ChannelId, EchoSize, [], 0).
-collect_data(ConnectionRef, ChannelId, Acc, Sum) ->
+collect_data(ConnectionRef, ChannelId, EchoSize, Acc, Sum) ->
TO = 5000,
receive
{ssh_cm, ConnectionRef, {data, ChannelId, 0, Data}} when is_binary(Data) ->
- ct:log("~p:~p collect_data: received ~p bytes. total ~p bytes",[?MODULE,?LINE,size(Data),Sum+size(Data)]),
+ ct:log("~p:~p collect_data: received ~p bytes. total ~p bytes, want ~p more",
+ [?MODULE,?LINE,size(Data),Sum+size(Data),EchoSize-Sum]),
ssh_connection:adjust_window(ConnectionRef, ChannelId, size(Data)),
- collect_data(ConnectionRef, ChannelId, [Data | Acc], Sum+size(Data));
+ collect_data(ConnectionRef, ChannelId, EchoSize, [Data | Acc], Sum+size(Data));
{ssh_cm, ConnectionRef, {eof, ChannelId}} ->
try
iolist_to_binary(lists:reverse(Acc))
of
Bin ->
- ct:log("~p:~p collect_data: received eof.~nGot in total ~p bytes",[?MODULE,?LINE,size(Bin)]),
+ ct:log("~p:~p collect_data: received eof.~nGot in total ~p bytes, want ~p more",
+ [?MODULE,?LINE,size(Bin),EchoSize,size(Bin)]),
Bin
catch
C:E ->
@@ -957,11 +959,11 @@ collect_data(ConnectionRef, ChannelId, Acc, Sum) ->
end;
Msg ->
ct:log("~p:~p collect_data: ***** unexpected message *****~n~p",[?MODULE,?LINE,Msg]),
- collect_data(ConnectionRef, ChannelId, Acc, Sum)
+ collect_data(ConnectionRef, ChannelId, EchoSize, Acc, Sum)
after TO ->
ct:log("~p:~p collect_data: ----- Nothing received for ~p seconds -----~n",[?MODULE,?LINE,TO]),
- collect_data(ConnectionRef, ChannelId, Acc, Sum)
+ collect_data(ConnectionRef, ChannelId, EchoSize, Acc, Sum)
end.
%%%-------------------------------------------------------------------
--
cgit v1.2.3
From cd52f028687974abf62059610bd01fc8f238ec4d Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 14 Nov 2016 10:25:44 +0100
Subject: ssh: interrupted_send test suite handle 'close CHANID' msg
---
lib/ssh/test/ssh_connection_SUITE.erl | 35 +++++++++++++++++++++--------------
1 file changed, 21 insertions(+), 14 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_connection_SUITE.erl b/lib/ssh/test/ssh_connection_SUITE.erl
index fc7ea81caf..2819a4dbd9 100644
--- a/lib/ssh/test/ssh_connection_SUITE.erl
+++ b/lib/ssh/test/ssh_connection_SUITE.erl
@@ -943,20 +943,12 @@ collect_data(ConnectionRef, ChannelId, EchoSize, Acc, Sum) ->
[?MODULE,?LINE,size(Data),Sum+size(Data),EchoSize-Sum]),
ssh_connection:adjust_window(ConnectionRef, ChannelId, size(Data)),
collect_data(ConnectionRef, ChannelId, EchoSize, [Data | Acc], Sum+size(Data));
- {ssh_cm, ConnectionRef, {eof, ChannelId}} ->
- try
- iolist_to_binary(lists:reverse(Acc))
- of
- Bin ->
- ct:log("~p:~p collect_data: received eof.~nGot in total ~p bytes, want ~p more",
- [?MODULE,?LINE,size(Bin),EchoSize,size(Bin)]),
- Bin
- catch
- C:E ->
- ct:log("~p:~p collect_data: received eof.~nAcc is strange...~nException=~p:~p~nAcc=~p",
- [?MODULE,?LINE,C,E,Acc]),
- {error,{C,E}}
- end;
+ {ssh_cm, ConnectionRef, Msg={eof, ChannelId}} ->
+ collect_data_report_end(Acc, Msg, EchoSize);
+
+ {ssh_cm, ConnectionRef, Msg={closed,ChannelId}} ->
+ collect_data_report_end(Acc, Msg, EchoSize);
+
Msg ->
ct:log("~p:~p collect_data: ***** unexpected message *****~n~p",[?MODULE,?LINE,Msg]),
collect_data(ConnectionRef, ChannelId, EchoSize, Acc, Sum)
@@ -966,6 +958,21 @@ collect_data(ConnectionRef, ChannelId, EchoSize, Acc, Sum) ->
collect_data(ConnectionRef, ChannelId, EchoSize, Acc, Sum)
end.
+collect_data_report_end(Acc, Msg, EchoSize) ->
+ try
+ iolist_to_binary(lists:reverse(Acc))
+ of
+ Bin ->
+ ct:log("~p:~p collect_data: received ~p.~nGot in total ~p bytes, want ~p more",
+ [?MODULE,?LINE,Msg,size(Bin),EchoSize,size(Bin)]),
+ Bin
+ catch
+ C:E ->
+ ct:log("~p:~p collect_data: received ~p.~nAcc is strange...~nException=~p:~p~nAcc=~p",
+ [?MODULE,?LINE,Msg,C,E,Acc]),
+ {error,{C,E}}
+ end.
+
%%%-------------------------------------------------------------------
%% This is taken from the ssh example code.
start_our_shell(_User, _Peer) ->
--
cgit v1.2.3
From 8215ea28fa2f699499b64d6f2c712e068b199390 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 11 Nov 2016 16:59:08 +0100
Subject: ssh: Add fun and fingerprint to option 'silently_accept_host'
---
lib/ssh/doc/src/ssh.xml | 14 ++++++++++++--
lib/ssh/src/ssh.erl | 9 +++++++++
lib/ssh/src/ssh_transport.erl | 16 ++++++++++------
3 files changed, 31 insertions(+), 8 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index ef9f7cbd9b..6b49f89449 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -175,11 +175,21 @@
supplied with this option.
-
+
+
+ boolean()]]>
+
-
When true, hosts are added to the
file without asking the user.
- Defaults to false.
+ Defaults to false which will give a user question on stdio of whether to accept or reject a previously
+ unseen host.
+ If the option value is has an accept_fun(), that fun will called with the arguments
+ (PeerName, PeerHostKeyFingerPrint). The fingerprint is calculated on the Peer's Host Key with
+ public_key:ssh_hostkey_fingerprint/1.
+
+ If the crypto:digest_type() is present, the fingerprint is calculated with that digest type by the function
+ public_key:ssh_hostkey_fingerprint/2.
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 1d7be3547b..31e343e81b 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -617,6 +617,15 @@ handle_ssh_option({user_dir_fun, Value} = Opt) when is_function(Value) ->
Opt;
handle_ssh_option({silently_accept_hosts, Value} = Opt) when is_boolean(Value) ->
Opt;
+handle_ssh_option({silently_accept_hosts, Value} = Opt) when is_function(Value,2) ->
+ Opt;
+handle_ssh_option({silently_accept_hosts, {DigestAlg,Value}} = Opt) when is_function(Value,2) ->
+ case lists:member(DigestAlg, [md5, sha, sha224, sha256, sha384, sha512]) of
+ true ->
+ Opt;
+ false ->
+ throw({error, {eoptions, Opt}})
+ end;
handle_ssh_option({user_interaction, Value} = Opt) when is_boolean(Value) ->
Opt;
handle_ssh_option({preferred_algorithms,[_|_]} = Opt) ->
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 15b80de30a..21ba34506a 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -734,12 +734,16 @@ public_algo({#'ECPoint'{},{namedCurve,OID}}) ->
list_to_atom("ecdsa-sha2-" ++ binary_to_list(Curve)).
-accepted_host(Ssh, PeerName, Opts) ->
+accepted_host(Ssh, PeerName, Public, Opts) ->
case proplists:get_value(silently_accept_hosts, Opts, false) of
+ F when is_function(F,2) ->
+ true == (catch F(PeerName, public_key:ssh_hostkey_fingerprint(Public)));
+ {DigestAlg,F} when is_function(F,2) ->
+ true == (catch F(PeerName, public_key:ssh_hostkey_fingerprint(DigestAlg,Public)));
true ->
- yes;
+ true;
false ->
- yes_no(Ssh, "New host " ++ PeerName ++ " accept")
+ yes == yes_no(Ssh, "New host " ++ PeerName ++ " accept")
end.
known_host_key(#ssh{opts = Opts, key_cb = Mod, peer = Peer} = Ssh,
@@ -749,10 +753,10 @@ known_host_key(#ssh{opts = Opts, key_cb = Mod, peer = Peer} = Ssh,
true ->
ok;
false ->
- case accepted_host(Ssh, PeerName, Opts) of
- yes ->
+ case accepted_host(Ssh, PeerName, Public, Opts) of
+ true ->
Mod:add_host_key(PeerName, Public, Opts);
- no ->
+ false ->
{error, rejected}
end
end.
--
cgit v1.2.3
From e4a22216787f652ecf9044f89dfbbfedd3ddb317 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 14 Nov 2016 15:08:35 +0100
Subject: ssh: Removed irrelevant rfc reference in doc
The rfc 4255 is about fingerprints, but only in the context of dns. Since this is out-of-scope for the Erlang/OTP ssh, the reference is missleading.
---
lib/ssh/doc/src/introduction.xml | 2 --
lib/ssh/doc/src/ssh_protocol.xml | 2 --
2 files changed, 4 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/introduction.xml b/lib/ssh/doc/src/introduction.xml
index ca84528f3d..b7a73e2597 100644
--- a/lib/ssh/doc/src/introduction.xml
+++ b/lib/ssh/doc/src/introduction.xml
@@ -195,8 +195,6 @@
Transport Layer Protocol
- RFC 4254 -
Connection Protocol
- - RFC 4255 -
- Key Fingerprints
- RFC 4344 -
Transport Layer Encryption Modes
- RFC 4716 -
diff --git a/lib/ssh/doc/src/ssh_protocol.xml b/lib/ssh/doc/src/ssh_protocol.xml
index 7288266cf7..013823b4df 100644
--- a/lib/ssh/doc/src/ssh_protocol.xml
+++ b/lib/ssh/doc/src/ssh_protocol.xml
@@ -138,8 +138,6 @@
Transport Layer Protocol.
- RFC 4254 -
Connection Protocol.
- - RFC 4255 -
- Key Fingerprints.
- RFC 4344 -
Transport Layer Encryption Modes.
- RFC 4716 -
--
cgit v1.2.3
From 2a98b4a2c29b2e2996a2f5095a824c4ab12e2a0b Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 17 Nov 2016 18:44:53 +0100
Subject: ssh: added two test cases
---
lib/ssh/test/ssh_options_SUITE.erl | 101 ++++++++++++++++++++++++++++++++++++-
1 file changed, 100 insertions(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_options_SUITE.erl b/lib/ssh/test/ssh_options_SUITE.erl
index 4cc12cbcbe..8f060bebd8 100644
--- a/lib/ssh/test/ssh_options_SUITE.erl
+++ b/lib/ssh/test/ssh_options_SUITE.erl
@@ -61,7 +61,13 @@
unexpectedfun_option_client/1,
unexpectedfun_option_server/1,
user_dir_option/1,
- connectfun_disconnectfun_server/1
+ connectfun_disconnectfun_server/1,
+ hostkey_fingerprint_check/1,
+ hostkey_fingerprint_check_md5/1,
+ hostkey_fingerprint_check_sha/1,
+ hostkey_fingerprint_check_sha256/1,
+ hostkey_fingerprint_check_sha384/1,
+ hostkey_fingerprint_check_sha512/1
]).
%%% Common test callbacks
@@ -100,6 +106,12 @@ all() ->
disconnectfun_option_client,
unexpectedfun_option_server,
unexpectedfun_option_client,
+ hostkey_fingerprint_check,
+ hostkey_fingerprint_check_md5,
+ hostkey_fingerprint_check_sha,
+ hostkey_fingerprint_check_sha256,
+ hostkey_fingerprint_check_sha384,
+ hostkey_fingerprint_check_sha512,
id_string_no_opt_client,
id_string_own_string_client,
id_string_random_client,
@@ -781,6 +793,93 @@ unexpectedfun_option_client(Config) ->
{fail,timeout}
end.
+%%--------------------------------------------------------------------
+hostkey_fingerprint_check(Config) ->
+ do_hostkey_fingerprint_check(Config, old).
+
+hostkey_fingerprint_check_md5(Config) ->
+ do_hostkey_fingerprint_check(Config, md5).
+
+hostkey_fingerprint_check_sha(Config) ->
+ do_hostkey_fingerprint_check(Config, sha).
+
+hostkey_fingerprint_check_sha256(Config) ->
+ do_hostkey_fingerprint_check(Config, sha256).
+
+hostkey_fingerprint_check_sha384(Config) ->
+ do_hostkey_fingerprint_check(Config, sha384).
+
+hostkey_fingerprint_check_sha512(Config) ->
+ do_hostkey_fingerprint_check(Config, sha512).
+
+
+%%%----
+do_hostkey_fingerprint_check(Config, HashAlg) ->
+ case supported_hash(HashAlg) of
+ true ->
+ really_do_hostkey_fingerprint_check(Config, HashAlg);
+ false ->
+ {skip,{unsupported_hash,HashAlg}}
+ end.
+
+supported_hash(old) -> true;
+supported_hash(HashAlg) ->
+ proplists:get_value(HashAlg,
+ proplists:get_value(hashs, crypto:supports(), []),
+ false).
+
+
+really_do_hostkey_fingerprint_check(Config, HashAlg) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth
+ file:make_dir(UserDir),
+ SysDir = proplists:get_value(data_dir, Config),
+
+ %% All host key fingerprints. Trust that public_key has checked the ssh_hostkey_fingerprint
+ %% function since that function is used by the ssh client...
+ FPs = [case HashAlg of
+ old -> public_key:ssh_hostkey_fingerprint(Key);
+ _ -> public_key:ssh_hostkey_fingerprint(HashAlg, Key)
+ end
+ || FileCandidate <- begin
+ {ok,KeyFileCands} = file:list_dir(SysDir),
+ KeyFileCands
+ end,
+ nomatch =/= re:run(FileCandidate, ".*\\.pub", []),
+ {Key,_Cmnts} <- begin
+ {ok,Bin} = file:read_file(filename:join(SysDir, FileCandidate)),
+ try public_key:ssh_decode(Bin, public_key)
+ catch
+ _:_ -> []
+ end
+ end],
+ ct:log("Fingerprints(~p) = ~p",[HashAlg,FPs]),
+
+ %% Start daemon with the public keys that we got fingerprints from
+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir},
+ {user_dir, UserDir},
+ {password, "morot"}]),
+
+ FP_check_fun = fun(PeerName, FP) ->
+ ct:pal("PeerName = ~p, FP = ~p",[PeerName,FP]),
+ HostCheck = (Host == PeerName),
+ FPCheck = lists:member(FP, FPs),
+ ct:log("check ~p == ~p (~p) and ~n~p in ~p (~p)~n",
+ [PeerName,Host,HostCheck,FP,FPs,FPCheck]),
+ HostCheck and FPCheck
+ end,
+
+ ssh_test_lib:connect(Host, Port, [{silently_accept_hosts,
+ case HashAlg of
+ old -> FP_check_fun;
+ _ -> {HashAlg, FP_check_fun}
+ end},
+ {user, "foo"},
+ {password, "morot"},
+ {user_dir, UserDir},
+ {user_interaction, false}]),
+ ssh:stop_daemon(Pid).
+
%%--------------------------------------------------------------------
%%% Test connect_timeout option in ssh:connect/4
ssh_connect_timeout(_Config) ->
--
cgit v1.2.3
From a6e7c2ac6c0da6521fbe8595ac684a4e0b3e69d3 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 21 Nov 2016 17:51:09 +0100
Subject: ssh: testcase for too large packet size on client
---
lib/ssh/test/ssh_sftp_SUITE.erl | 20 +++++++++++++++++---
1 file changed, 17 insertions(+), 3 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_sftp_SUITE.erl b/lib/ssh/test/ssh_sftp_SUITE.erl
index 19ad81e7da..70662f5d93 100644
--- a/lib/ssh/test/ssh_sftp_SUITE.erl
+++ b/lib/ssh/test/ssh_sftp_SUITE.erl
@@ -60,12 +60,16 @@ end_per_suite(_onfig) ->
groups() ->
[{not_unicode, [], [{group,erlang_server},
{group,openssh_server},
+ {group,big_recvpkt_size},
sftp_nonexistent_subsystem]},
{unicode, [], [{group,erlang_server},
{group,openssh_server},
sftp_nonexistent_subsystem]},
+ {big_recvpkt_size, [], [{group,erlang_server},
+ {group,openssh_server}]},
+
{erlang_server, [], [{group,write_read_tests},
version_option,
{group,remote_tar}]},
@@ -149,6 +153,9 @@ init_per_group(unicode, Config) ->
{skip, "Not unicode file encoding"}
end;
+init_per_group(big_recvpkt_size, Config) ->
+ [{pkt_sz,123456} | Config];
+
init_per_group(erlang_server, Config) ->
ct:comment("Begin ~p",[grps(Config)]),
PrivDir = proplists:get_value(priv_dir, Config),
@@ -257,7 +264,10 @@ init_per_testcase(Case, Config00) ->
Dog = ct:timetrap(2 * ?default_timeout),
User = proplists:get_value(user, Config0),
Passwd = proplists:get_value(passwd, Config0),
-
+ PktSzOpt = case proplists:get_value(pkt_sz, Config0) of
+ undefined -> [];
+ Sz -> [{packet_size,Sz}]
+ end,
Config =
case proplists:get_value(group,Config2) of
erlang_server ->
@@ -267,7 +277,9 @@ init_per_testcase(Case, Config00) ->
[{user, User},
{password, Passwd},
{user_interaction, false},
- {silently_accept_hosts, true}]
+ {silently_accept_hosts, true}
+ | PktSzOpt
+ ]
),
Sftp = {ChannelPid, Connection},
[{sftp, Sftp}, {watchdog, Dog} | Config2];
@@ -278,7 +290,9 @@ init_per_testcase(Case, Config00) ->
{ok, ChannelPid, Connection} =
ssh_sftp:start_channel(Host,
[{user_interaction, false},
- {silently_accept_hosts, true}]),
+ {silently_accept_hosts, true}
+ | PktSzOpt
+ ]),
Sftp = {ChannelPid, Connection},
[{sftp, Sftp}, {watchdog, Dog} | Config2]
end,
--
cgit v1.2.3
From 3a519b7b74ae07f4d66989313a0c065c96bcad8c Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 21 Nov 2016 17:52:06 +0100
Subject: ssh: fix error when large client packet size and small on server
---
lib/ssh/src/ssh_connection.erl | 3 +++
1 file changed, 3 insertions(+)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl
index d0f2d54c06..1153095135 100644
--- a/lib/ssh/src/ssh_connection.erl
+++ b/lib/ssh/src/ssh_connection.erl
@@ -287,6 +287,9 @@ handle_msg(#ssh_msg_channel_open_confirmation{recipient_channel = ChannelId,
ssh_channel:cache_update(Cache, Channel#channel{
remote_id = RemoteId,
+ recv_packet_size = max(32768, % rfc4254/5.2
+ min(PacketSz, Channel#channel.recv_packet_size)
+ ),
send_window_size = WindowSz,
send_packet_size = PacketSz}),
{Reply, Connection} = reply_msg(Channel, Connection0, {open, ChannelId}),
--
cgit v1.2.3
From f3d2c8fc5695438f5566853938093e61d723a284 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 2 Dec 2016 11:40:05 +0100
Subject: ssh: excluded modules from cover spec
---
lib/ssh/test/ssh.cover | 1 +
1 file changed, 1 insertion(+)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh.cover b/lib/ssh/test/ssh.cover
index a4221fbbbe..69d2a1c4f8 100644
--- a/lib/ssh/test/ssh.cover
+++ b/lib/ssh/test/ssh.cover
@@ -1,2 +1,3 @@
{incl_app,ssh,details}.
+{excl_mods, ssh, [ssh_dbg, ssh_info, ssh_server_key_api, ssh_sftpd_file_api]}.
\ No newline at end of file
--
cgit v1.2.3
From 6b342f5c10ac5d7a5e1e71157ff1bf1a833ce99a Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 5 Dec 2016 13:14:36 +0100
Subject: ssh: update vsn.mk
---
lib/ssh/vsn.mk | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index c023429056..c6a5990f41 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,5 +1,5 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 4.3.6
+SSH_VSN = 4.4
APP_VSN = "ssh-$(SSH_VSN)"
--
cgit v1.2.3
From 3eddb0f762de248d3230b38bc9d478bfbc8e7331 Mon Sep 17 00:00:00 2001
From: Erlang/OTP
Date: Wed, 7 Dec 2016 13:15:31 +0100
Subject: Update copyright-year
---
lib/ssh/doc/src/ssh_protocol.xml | 2 +-
lib/ssh/src/ssh.appup.src | 2 +-
lib/ssh/src/ssh_acceptor.erl | 2 +-
lib/ssh/src/ssh_connection.erl | 2 +-
lib/ssh/src/ssh_info.erl | 2 +-
lib/ssh/src/ssh_sftpd.erl | 2 +-
lib/ssh/test/ssh_trpt_test_lib.erl | 2 +-
7 files changed, 7 insertions(+), 7 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/ssh_protocol.xml b/lib/ssh/doc/src/ssh_protocol.xml
index 013823b4df..a0032ab449 100644
--- a/lib/ssh/doc/src/ssh_protocol.xml
+++ b/lib/ssh/doc/src/ssh_protocol.xml
@@ -4,7 +4,7 @@
- 20132013
+ 20132016
Ericsson AB. All Rights Reserved.
diff --git a/lib/ssh/src/ssh.appup.src b/lib/ssh/src/ssh.appup.src
index 4cda8fee95..2540720c41 100644
--- a/lib/ssh/src/ssh.appup.src
+++ b/lib/ssh/src/ssh.appup.src
@@ -1,7 +1,7 @@
%% -*- erlang -*-
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_acceptor.erl b/lib/ssh/src/ssh_acceptor.erl
index 9f3e60bd62..13c9d9af4a 100644
--- a/lib/ssh/src/ssh_acceptor.erl
+++ b/lib/ssh/src/ssh_acceptor.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl
index 1153095135..c7a2c92670 100644
--- a/lib/ssh/src/ssh_connection.erl
+++ b/lib/ssh/src/ssh_connection.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_info.erl b/lib/ssh/src/ssh_info.erl
index 0c24c09887..d464def6fa 100644
--- a/lib/ssh/src/ssh_info.erl
+++ b/lib/ssh/src/ssh_info.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_sftpd.erl b/lib/ssh/src/ssh_sftpd.erl
index dca018f20f..b739955836 100644
--- a/lib/ssh/src/ssh_sftpd.erl
+++ b/lib/ssh/src/ssh_sftpd.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_trpt_test_lib.erl b/lib/ssh/test/ssh_trpt_test_lib.erl
index e34071af99..bc86000d81 100644
--- a/lib/ssh/test/ssh_trpt_test_lib.erl
+++ b/lib/ssh/test/ssh_trpt_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. 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
--
cgit v1.2.3
From fc0427be6d482182ec70f3cd87c73027cfb17ea9 Mon Sep 17 00:00:00 2001
From: Erlang/OTP
Date: Fri, 9 Dec 2016 11:45:22 +0100
Subject: Prepare release
---
lib/ssh/doc/src/notes.xml | 44 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index f5a67bc00e..1837350284 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -30,6 +30,50 @@
notes.xml
+Ssh 4.4
+
+ Fixed Bugs and Malfunctions
+
+ -
+
+ A file read with an sftp client could loose data if the
+ packet_size is set to larger than 64k. This is corrected
+ now in such a way that the packet_size is silently
+ lowered if there is a risk for data loss.
+
+ Own Id: OTP-13857 Aux Id: ERL-238, OTP-13858
+
+ -
+
+ When user defined SSH shell REPL process exits with
+ reason normal, the SSH channel callback module should
+ report successful exit status to the SSH client. This
+ provides simple way for SSH clients to check for
+ successful completion of executed commands. (Thanks to
+ isvilen)
+
+ Own Id: OTP-13905 Aux Id: PR-1173
+
+
+
+
+
+ Improvements and New Features
+
+ -
+
+ Extended the option silently_accept_hosts for
+ ssh:connect to make it possible for the client to
+ check the SSH host key fingerprint string. Se the
+ reference manual for SSH.
+
+ Own Id: OTP-13887 Aux Id: OTP-13888
+
+
+
+
+
+
Ssh 4.3.6
Fixed Bugs and Malfunctions
--
cgit v1.2.3
From 6e693e0a411eb6fe5301683a9bb2babbc2ed50c5 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 18 Nov 2016 18:24:20 +0100
Subject: ssh: [test] Extend timetrap in test case
---
lib/ssh/test/ssh_algorithms_SUITE.erl | 8 +++-----
lib/ssh/test/ssh_test_lib.erl | 30 +++++++++++++++++++-----------
2 files changed, 22 insertions(+), 16 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_algorithms_SUITE.erl b/lib/ssh/test/ssh_algorithms_SUITE.erl
index 8b2db0e1a8..14605ee44f 100644
--- a/lib/ssh/test/ssh_algorithms_SUITE.erl
+++ b/lib/ssh/test/ssh_algorithms_SUITE.erl
@@ -198,7 +198,7 @@ try_exec_simple_group(Group, Config) ->
%%--------------------------------------------------------------------
%% Testing all default groups
-simple_exec_groups() -> [{timetrap,{minutes,5}}].
+simple_exec_groups() -> [{timetrap,{minutes,8}}].
simple_exec_groups(Config) ->
Sizes = interpolate( public_key:dh_gex_group_sizes() ),
@@ -206,10 +206,8 @@ simple_exec_groups(Config) ->
fun(Sz) ->
ct:log("Try size ~p",[Sz]),
ct:comment(Sz),
- case simple_exec_group(Sz, Config) of
- expected -> ct:log("Size ~p ok",[Sz]);
- _ -> ct:log("Size ~p not ok",[Sz])
- end
+ simple_exec_group(Sz, Config),
+ ct:log("Size ~p ok",[Sz])
end, Sizes),
ct:comment("~p",[lists:map(fun({_,I,_}) -> I;
(I) -> I
diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl
index f93237f3e7..1154f18991 100644
--- a/lib/ssh/test/ssh_test_lib.erl
+++ b/lib/ssh/test/ssh_test_lib.erl
@@ -113,19 +113,27 @@ std_simple_exec(Host, Port, Config) ->
std_simple_exec(Host, Port, Config, []).
std_simple_exec(Host, Port, Config, Opts) ->
+ ct:log("~p:~p std_simple_exec",[?MODULE,?LINE]),
ConnectionRef = ssh_test_lib:std_connect(Config, Host, Port, Opts),
+ ct:log("~p:~p connected! ~p",[?MODULE,?LINE,ConnectionRef]),
{ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity),
- success = ssh_connection:exec(ConnectionRef, ChannelId, "23+21-2.", infinity),
- Data = {ssh_cm, ConnectionRef, {data, ChannelId, 0, <<"42\n">>}},
- case ssh_test_lib:receive_exec_result(Data) of
- expected ->
- ok;
- Other ->
- ct:fail(Other)
- end,
- ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId),
- ssh:close(ConnectionRef).
-
+ ct:log("~p:~p session_channel ok ~p",[?MODULE,?LINE,ChannelId]),
+ ExecResult = ssh_connection:exec(ConnectionRef, ChannelId, "23+21-2.", infinity),
+ ct:log("~p:~p exec ~p",[?MODULE,?LINE,ExecResult]),
+ case ExecResult of
+ success ->
+ Expected = {ssh_cm, ConnectionRef, {data,ChannelId,0,<<"42\n">>}},
+ case receive_exec_result(Expected) of
+ expected ->
+ ok;
+ Other ->
+ ct:fail(Other)
+ end,
+ receive_exec_end(ConnectionRef, ChannelId),
+ ssh:close(ConnectionRef);
+ _ ->
+ ct:fail(ExecResult)
+ end.
start_shell(Port, IOServer) ->
start_shell(Port, IOServer, []).
--
cgit v1.2.3
From a8ea98ef814022dc02a1917105a0572007952e52 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 28 Nov 2016 14:50:08 +0100
Subject: ssh: [test] Put tstflg values in a proplist
---
lib/ssh/src/ssh_auth.erl | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl
index ac35b70209..9b54ecb2dd 100644
--- a/lib/ssh/src/ssh_auth.erl
+++ b/lib/ssh/src/ssh_auth.erl
@@ -406,7 +406,11 @@ handle_userauth_info_response(#ssh_msg_userauth_info_response{num_responses = 1,
kb_tries_left = KbTriesLeft,
user = User,
userauth_supported_methods = Methods} = Ssh) ->
- SendOneEmpty = proplists:get_value(tstflg, Opts) == one_empty,
+ SendOneEmpty =
+ (proplists:get_value(tstflg,Opts) == one_empty)
+ orelse
+ proplists:get_value(one_empty, proplists:get_value(tstflg,Opts,[]), false),
+
case check_password(User, unicode:characters_to_list(Password), Opts, Ssh) of
{true,Ssh1} when SendOneEmpty==true ->
Msg = #ssh_msg_userauth_info_request{name = "",
--
cgit v1.2.3
From 7300d01bedaed1fbb213378d43589b4448aa5d3b Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 1 Dec 2016 13:33:15 +0100
Subject: ssh: [test] Move fn random_chars/1 to ssh_test_lib
---
lib/ssh/test/ssh_sftp_SUITE.erl | 4 +---
lib/ssh/test/ssh_test_lib.erl | 5 +++++
lib/ssh/test/ssh_upgrade_SUITE.erl | 4 +---
3 files changed, 7 insertions(+), 6 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_sftp_SUITE.erl b/lib/ssh/test/ssh_sftp_SUITE.erl
index 70662f5d93..acf76157a2 100644
--- a/lib/ssh/test/ssh_sftp_SUITE.erl
+++ b/lib/ssh/test/ssh_sftp_SUITE.erl
@@ -1038,7 +1038,7 @@ oldprep(Config) ->
prepare(Config0) ->
PrivDir = proplists:get_value(priv_dir, Config0),
- Dir = filename:join(PrivDir, random_chars(10)),
+ Dir = filename:join(PrivDir, ssh_test_lib:random_chars(10)),
file:make_dir(Dir),
Keys = [filename,
testfile,
@@ -1058,8 +1058,6 @@ prepare(Config0) ->
[{sftp_priv_dir,Dir} | Config2].
-random_chars(N) -> [crypto:rand_uniform($a,$z) || _<-lists:duplicate(N,x)].
-
foldl_keydelete(Keys, L) ->
lists:foldl(fun(K,E) -> lists:keydelete(K,1,E) end,
L,
diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl
index 1154f18991..27fc9ed6ad 100644
--- a/lib/ssh/test/ssh_test_lib.erl
+++ b/lib/ssh/test/ssh_test_lib.erl
@@ -842,3 +842,8 @@ get_kex_init(Conn, Ref, TRef) ->
end
end.
+%%%----------------------------------------------------------------
+%%% Return a string with N random characters
+%%%
+random_chars(N) -> [crypto:rand_uniform($a,$z) || _<-lists:duplicate(N,x)].
+
diff --git a/lib/ssh/test/ssh_upgrade_SUITE.erl b/lib/ssh/test/ssh_upgrade_SUITE.erl
index b5b27c369a..7b9b109fa1 100644
--- a/lib/ssh/test/ssh_upgrade_SUITE.erl
+++ b/lib/ssh/test/ssh_upgrade_SUITE.erl
@@ -199,6 +199,4 @@ close(#state{server = Server,
connection = undefined}.
-random_contents() -> list_to_binary( random_chars(3) ).
-
-random_chars(N) -> [crypto:rand_uniform($a,$z) || _<-lists:duplicate(N,x)].
+random_contents() -> list_to_binary( ssh_test_lib:random_chars(3) ).
--
cgit v1.2.3
From eec0a0751e2a7ca7e32731fcd05f0a6032e1062f Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 1 Dec 2016 15:22:41 +0100
Subject: ssh: [test] remove 'known_hosts' interference in test suite
---
lib/ssh/test/ssh_options_SUITE.erl | 11 +++++++----
lib/ssh/test/ssh_test_lib.erl | 12 ++++++++++++
2 files changed, 19 insertions(+), 4 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_options_SUITE.erl b/lib/ssh/test/ssh_options_SUITE.erl
index 8f060bebd8..86f5cb1746 100644
--- a/lib/ssh/test/ssh_options_SUITE.erl
+++ b/lib/ssh/test/ssh_options_SUITE.erl
@@ -831,10 +831,13 @@ supported_hash(HashAlg) ->
really_do_hostkey_fingerprint_check(Config, HashAlg) ->
PrivDir = proplists:get_value(priv_dir, Config),
- UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth
- file:make_dir(UserDir),
+ UserDirServer = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth
+ file:make_dir(UserDirServer),
SysDir = proplists:get_value(data_dir, Config),
+ UserDirClient =
+ ssh_test_lib:create_random_dir(Config), % Ensure no 'known_hosts' disturbs
+
%% All host key fingerprints. Trust that public_key has checked the ssh_hostkey_fingerprint
%% function since that function is used by the ssh client...
FPs = [case HashAlg of
@@ -857,7 +860,7 @@ really_do_hostkey_fingerprint_check(Config, HashAlg) ->
%% Start daemon with the public keys that we got fingerprints from
{Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir},
- {user_dir, UserDir},
+ {user_dir, UserDirServer},
{password, "morot"}]),
FP_check_fun = fun(PeerName, FP) ->
@@ -876,7 +879,7 @@ really_do_hostkey_fingerprint_check(Config, HashAlg) ->
end},
{user, "foo"},
{password, "morot"},
- {user_dir, UserDir},
+ {user_dir, UserDirClient},
{user_interaction, false}]),
ssh:stop_daemon(Pid).
diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl
index 27fc9ed6ad..286ac6e882 100644
--- a/lib/ssh/test/ssh_test_lib.erl
+++ b/lib/ssh/test/ssh_test_lib.erl
@@ -847,3 +847,15 @@ get_kex_init(Conn, Ref, TRef) ->
%%%
random_chars(N) -> [crypto:rand_uniform($a,$z) || _<-lists:duplicate(N,x)].
+
+create_random_dir(Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ Name = filename:join(PrivDir, random_chars(15)),
+ case file:make_dir(Name) of
+ ok ->
+ Name;
+ {error,eexist} ->
+ %% The Name already denotes an existing file system object, try again.
+ %% The likelyhood of always generating an existing file name is low
+ create_random_dir(Config)
+ end.
--
cgit v1.2.3
From 169d8b4143cb8ccabdda13765c7d21ab9d2c9686 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 9 Dec 2016 17:53:59 +0100
Subject: ssh: [test] property test cuddling
---
.../test/property_test/ssh_eqc_encode_decode.erl | 365 ++++++++-------------
lib/ssh/test/ssh_property_test_SUITE.erl | 3 -
2 files changed, 133 insertions(+), 235 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl b/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl
index dc3b7dc7e6..0f8a838f97 100644
--- a/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl
+++ b/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl
@@ -54,15 +54,18 @@
-endif.
-endif.
+%% Public key records:
+-include_lib("public_key/include/public_key.hrl").
%%% Properties:
prop_ssh_decode() ->
- ?FORALL(Msg, ssh_msg(),
- try ssh_message:decode(Msg)
+ ?FORALL({Msg,KexFam}, ?LET(KF, kex_family(), {ssh_msg(KF),KF} ),
+ try ssh_message:decode(decode_state(Msg,KexFam))
of
_ -> true
catch
+
C:E -> io:format('~p:~p~n',[C,E]),
false
end
@@ -71,122 +74,101 @@ prop_ssh_decode() ->
%%% This fails because ssh_message is not symmetric in encode and decode regarding data types
prop_ssh_decode_encode() ->
- ?FORALL(Msg, ssh_msg(),
- Msg == ssh_message:encode(ssh_message:decode(Msg))
+ ?FORALL({Msg,KexFam}, ?LET(KF, kex_family(), {ssh_msg(KF),KF} ),
+ Msg == ssh_message:encode(
+ fix_asym(
+ ssh_message:decode(decode_state(Msg,KexFam))))
).
-%%%================================================================
-%%%
-%%% Scripts to generate message generators
-%%%
-
-%% awk '/^( |\t)+byte( |\t)+SSH/,/^( |\t)*$/{print}' rfc425?.txt | sed 's/^\( \|\\t\)*//' > msgs.txt
-
-%% awk '/^byte( |\t)+SSH/{print $2","}' < msgs.txt
-
-%% awk 'BEGIN{print "%%%---- BEGIN GENERATED";prev=0} END{print " >>.\n%%%---- END GENERATED"} /^byte( |\t)+SSH/{if (prev==1) print " >>.\n"; prev=1; printf "%c%s%c",39,$2,39; print "()->\n <"$2;next} /^string( |\t)+\"/{print " ,"$2;next} /^string( |\t)+.*address/{print " ,(ssh_string_address())/binary %%",$2,$3,$4,$5,$6;next}/^string( |\t)+.*US-ASCII/{print " ,(ssh_string_US_ASCII())/binary %%",$2,$3,$4,$5,$6;next} /^string( |\t)+.*UTF-8/{print " ,(ssh_string_UTF_8())/binary %% ",$2,$3,$4,$5,$6;next} /^[a-z0-9]+( |\t)/{print " ,(ssh_"$1"())/binary %%",$2,$3,$4,$5,$6;next} /^byte\[16\]( |\t)+/{print" ,(ssh_byte_16())/binary %%",$2,$3,$4,$5,$6;next} /^name-list( |\t)+/{print" ,(ssh_name_list())/binary %%",$2,$3,$4,$5,$6;next} /./{print "?? %%",$0}' < msgs.txt > gen.txt
-
%%%================================================================
%%%
%%% Generators
%%%
-ssh_msg() -> ?LET(M,oneof(
-[[msg_code('SSH_MSG_CHANNEL_CLOSE'),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_DATA'),gen_uint32(),gen_string( )],
- [msg_code('SSH_MSG_CHANNEL_EOF'),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_EXTENDED_DATA'),gen_uint32(),gen_uint32(),gen_string( )],
- [msg_code('SSH_MSG_CHANNEL_FAILURE'),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_OPEN'),gen_string("direct-tcpip"),gen_uint32(),gen_uint32(),gen_uint32(),gen_string( ),gen_uint32(),gen_string( ),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_OPEN'),gen_string("forwarded-tcpip"),gen_uint32(),gen_uint32(),gen_uint32(),gen_string( ),gen_uint32(),gen_string( ),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_OPEN'),gen_string("session"),gen_uint32(),gen_uint32(),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_OPEN'),gen_string("x11"),gen_uint32(),gen_uint32(),gen_uint32(),gen_string( ),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_OPEN'),gen_string( ),gen_uint32(),gen_uint32(),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_OPEN_CONFIRMATION'),gen_uint32(),gen_uint32(),gen_uint32(),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_OPEN_FAILURE'),gen_uint32(),gen_uint32(),gen_string( ),gen_string( )],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("env"),gen_boolean(),gen_string( ),gen_string( )],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("exec"),gen_boolean(),gen_string( )],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("exit-signal"),0,gen_string( ),gen_boolean(),gen_string( ),gen_string( )],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("exit-status"),0,gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("pty-req"),gen_boolean(),gen_string( ),gen_uint32(),gen_uint32(),gen_uint32(),gen_uint32(),gen_string( )],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("shell"),gen_boolean()],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("signal"),0,gen_string( )],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("subsystem"),gen_boolean(),gen_string( )],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("window-change"),0,gen_uint32(),gen_uint32(),gen_uint32(),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("x11-req"),gen_boolean(),gen_boolean(),gen_string( ),gen_string( ),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("xon-xoff"),0,gen_boolean()],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string( ),gen_boolean()],
- [msg_code('SSH_MSG_CHANNEL_SUCCESS'),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_WINDOW_ADJUST'),gen_uint32(),gen_uint32()],
-%%Assym [msg_code('SSH_MSG_DEBUG'),gen_boolean(),gen_string( ),gen_string( )],
- [msg_code('SSH_MSG_DISCONNECT'),gen_uint32(),gen_string( ),gen_string( )],
-%%Assym [msg_code('SSH_MSG_GLOBAL_REQUEST'),gen_string("cancel-tcpip-forward"),gen_boolean(),gen_string( ),gen_uint32()],
-%%Assym [msg_code('SSH_MSG_GLOBAL_REQUEST'),gen_string("tcpip-forward"),gen_boolean(),gen_string( ),gen_uint32()],
-%%Assym [msg_code('SSH_MSG_GLOBAL_REQUEST'),gen_string( ),gen_boolean()],
- [msg_code('SSH_MSG_IGNORE'),gen_string( )],
- %% [msg_code('SSH_MSG_KEXDH_INIT'),gen_mpint()],
- %% [msg_code('SSH_MSG_KEXDH_REPLY'),gen_string( ),gen_mpint(),gen_string( )],
- %% [msg_code('SSH_MSG_KEXINIT'),gen_byte(16),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_boolean(),gen_uint32()],
- [msg_code('SSH_MSG_KEX_DH_GEX_GROUP'),gen_mpint(),gen_mpint()],
- [msg_code('SSH_MSG_NEWKEYS')],
- [msg_code('SSH_MSG_REQUEST_FAILURE')],
- [msg_code('SSH_MSG_REQUEST_SUCCESS')],
- [msg_code('SSH_MSG_REQUEST_SUCCESS'),gen_uint32()],
- [msg_code('SSH_MSG_SERVICE_ACCEPT'),gen_string( )],
- [msg_code('SSH_MSG_SERVICE_REQUEST'),gen_string( )],
- [msg_code('SSH_MSG_UNIMPLEMENTED'),gen_uint32()],
- [msg_code('SSH_MSG_USERAUTH_BANNER'),gen_string( ),gen_string( )],
- [msg_code('SSH_MSG_USERAUTH_FAILURE'),gen_name_list(),gen_boolean()],
- [msg_code('SSH_MSG_USERAUTH_PASSWD_CHANGEREQ'),gen_string( ),gen_string( )],
- [msg_code('SSH_MSG_USERAUTH_PK_OK'),gen_string( ),gen_string( )],
- [msg_code('SSH_MSG_USERAUTH_SUCCESS')]
-]
-
-), list_to_binary(M)).
-
-
-%%%================================================================
-%%%
-%%% Generator
-%%%
-
-do() ->
- io_lib:format('[~s~n]',
- [write_gen(
- files(["rfc4254.txt",
- "rfc4253.txt",
- "rfc4419.txt",
- "rfc4252.txt",
- "rfc4256.txt"]))]).
-
-
-write_gen(L) when is_list(L) ->
- string:join(lists:map(fun write_gen/1, L), ",\n ");
-write_gen({MsgName,Args}) ->
- lists:flatten(["[",generate_args([MsgName|Args]),"]"]).
-
-generate_args(As) -> string:join([generate_arg(A) || A <- As], ",").
-
-generate_arg({<<"string">>, <<"\"",B/binary>>}) ->
- S = get_string($",B),
- ["gen_string(\"",S,"\")"];
-generate_arg({<<"string">>, _}) -> "gen_string( )";
-generate_arg({<<"byte[",B/binary>>, _}) ->
- io_lib:format("gen_byte(~p)",[list_to_integer(get_string($],B))]);
-generate_arg({<<"byte">> ,_}) -> "gen_byte()";
-generate_arg({<<"uint16">>,_}) -> "gen_uint16()";
-generate_arg({<<"uint32">>,_}) -> "gen_uint32()";
-generate_arg({<<"uint64">>,_}) -> "gen_uint64()";
-generate_arg({<<"mpint">>,_}) -> "gen_mpint()";
-generate_arg({<<"name-list">>,_}) -> "gen_name_list()";
-generate_arg({<<"boolean">>,<<"FALSE">>}) -> "0";
-generate_arg({<<"boolean">>,<<"TRUE">>}) -> "1";
-generate_arg({<<"boolean">>,_}) -> "gen_boolean()";
-generate_arg({<<"....">>,_}) -> ""; %% FIXME
-generate_arg(Name) when is_binary(Name) ->
- lists:flatten(["msg_code('",binary_to_list(Name),"')"]).
-
+ssh_msg(<<"dh">>) ->
+ ?LET(M,oneof(
+ [
+ [msg_code('SSH_MSG_KEXDH_INIT'),gen_mpint()], % 30
+ [msg_code('SSH_MSG_KEXDH_REPLY'),gen_pubkey_string(rsa),gen_mpint(),gen_signature_string(rsa)] % 31
+ | rest_ssh_msgs()
+ ]),
+ list_to_binary(M));
+
+ssh_msg(<<"dh_gex">>) ->
+ ?LET(M,oneof(
+ [
+ [msg_code('SSH_MSG_KEX_DH_GEX_REQUEST_OLD'),gen_uint32()], % 30
+ [msg_code('SSH_MSG_KEX_DH_GEX_GROUP'),gen_mpint(),gen_mpint()] % 31
+ | rest_ssh_msgs()
+ ]),
+ list_to_binary(M));
+
+ ssh_msg(<<"ecdh">>) ->
+ ?LET(M,oneof(
+ [
+ [msg_code('SSH_MSG_KEX_ECDH_INIT'),gen_mpint()], % 30
+ [msg_code('SSH_MSG_KEX_ECDH_REPLY'),gen_pubkey_string(ecdsa),gen_mpint(),gen_signature_string(ecdsa)] % 31
+ | rest_ssh_msgs()
+ ]),
+ list_to_binary(M)).
+
+
+rest_ssh_msgs() ->
+ [%% SSH_MSG_USERAUTH_INFO_RESPONSE
+ %% hard args SSH_MSG_USERAUTH_INFO_REQUEST
+ %% rfc4252 p12 error SSH_MSG_USERAUTH_REQUEST
+ [msg_code('SSH_MSG_KEX_DH_GEX_REQUEST'),gen_uint32(),gen_uint32(),gen_uint32()],
+ [msg_code('SSH_MSG_KEX_DH_GEX_INIT'),gen_mpint()],
+ [msg_code('SSH_MSG_KEX_DH_GEX_REPLY'),gen_pubkey_string(rsa),gen_mpint(),gen_signature_string(rsa)],
+ [msg_code('SSH_MSG_CHANNEL_CLOSE'),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_DATA'),gen_uint32(),gen_string( )],
+ [msg_code('SSH_MSG_CHANNEL_EOF'),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_EXTENDED_DATA'),gen_uint32(),gen_uint32(),gen_string( )],
+ [msg_code('SSH_MSG_CHANNEL_FAILURE'),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_OPEN'),gen_string("direct-tcpip"),gen_uint32(),gen_uint32(),gen_uint32(),gen_string( ),gen_uint32(),gen_string( ),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_OPEN'),gen_string("forwarded-tcpip"),gen_uint32(),gen_uint32(),gen_uint32(),gen_string( ),gen_uint32(),gen_string( ),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_OPEN'),gen_string("session"),gen_uint32(),gen_uint32(),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_OPEN'),gen_string("x11"),gen_uint32(),gen_uint32(),gen_uint32(),gen_string( ),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_OPEN'),gen_string( ),gen_uint32(),gen_uint32(),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_OPEN_CONFIRMATION'),gen_uint32(),gen_uint32(),gen_uint32(),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_OPEN_FAILURE'),gen_uint32(),gen_uint32(),gen_string( ),gen_string( )],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("env"),gen_boolean(),gen_string( ),gen_string( )],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("exec"),gen_boolean(),gen_string( )],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("exit-signal"),0,gen_string( ),gen_boolean(),gen_string( ),gen_string( )],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("exit-status"),0,gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("pty-req"),gen_boolean(),gen_string( ),gen_uint32(),gen_uint32(),gen_uint32(),gen_uint32(),gen_string( )],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("shell"),gen_boolean()],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("signal"),0,gen_string( )],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("subsystem"),gen_boolean(),gen_string( )],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("window-change"),0,gen_uint32(),gen_uint32(),gen_uint32(),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("x11-req"),gen_boolean(),gen_boolean(),gen_string( ),gen_string( ),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("xon-xoff"),0,gen_boolean()],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string( ),gen_boolean()],
+ [msg_code('SSH_MSG_CHANNEL_SUCCESS'),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_WINDOW_ADJUST'),gen_uint32(),gen_uint32()],
+ [msg_code('SSH_MSG_DEBUG'),gen_boolean(),gen_string( ),gen_string( )],
+ [msg_code('SSH_MSG_DISCONNECT'),gen_uint32(),gen_string( ),gen_string( )],
+ [msg_code('SSH_MSG_GLOBAL_REQUEST'),gen_string("cancel-tcpip-forward"),gen_boolean(),gen_string( ),gen_uint32()],
+ [msg_code('SSH_MSG_GLOBAL_REQUEST'),gen_string("tcpip-forward"),gen_boolean(),gen_string( ),gen_uint32()],
+ [msg_code('SSH_MSG_GLOBAL_REQUEST'),gen_string( ),gen_boolean()],
+ [msg_code('SSH_MSG_IGNORE'),gen_string( )],
+ [msg_code('SSH_MSG_KEXINIT'),gen_byte(16),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_boolean(),gen_uint32()],
+ [msg_code('SSH_MSG_NEWKEYS')],
+ [msg_code('SSH_MSG_REQUEST_FAILURE')],
+ [msg_code('SSH_MSG_REQUEST_SUCCESS')],
+ [msg_code('SSH_MSG_REQUEST_SUCCESS'),gen_uint32()],
+ [msg_code('SSH_MSG_SERVICE_ACCEPT'),gen_string( )],
+ [msg_code('SSH_MSG_SERVICE_REQUEST'),gen_string( )],
+ [msg_code('SSH_MSG_UNIMPLEMENTED'),gen_uint32()],
+ [msg_code('SSH_MSG_USERAUTH_BANNER'),gen_string( ),gen_string( )],
+ [msg_code('SSH_MSG_USERAUTH_FAILURE'),gen_name_list(),gen_boolean()],
+ [msg_code('SSH_MSG_USERAUTH_PASSWD_CHANGEREQ'),gen_string( ),gen_string( )],
+ [msg_code('SSH_MSG_USERAUTH_PK_OK'),gen_string( ),gen_string( )],
+ [msg_code('SSH_MSG_USERAUTH_SUCCESS')]
+ ].
+
+kex_family() -> oneof([<<"dh">>, <<"dh_gex">>, <<"ecdh">>]).
gen_boolean() -> choose(0,1).
@@ -230,13 +212,22 @@ gen_name() -> gen_string().
uint32_to_list(I) -> binary_to_list(<>).
-%%%----
-get_string(Delim, B) ->
- binary_to_list( element(1, split_binary(B, count_string_chars(Delim,B,0))) ).
-
-count_string_chars(Delim, <>, Acc) -> Acc;
-count_string_chars(Delim, <<_,B/binary>>, Acc) -> count_string_chars(Delim, B, Acc+1).
+gen_pubkey_string(Type) ->
+ PubKey = case Type of
+ rsa -> #'RSAPublicKey'{modulus = 12345,publicExponent = 2};
+ ecdsa -> {#'ECPoint'{point=[1,2,3,4,5]},
+ {namedCurve,{1,2,840,10045,3,1,7}}} % 'secp256r1' nistp256
+ end,
+ gen_string(public_key:ssh_encode(PubKey, ssh2_pubkey)).
+
+gen_signature_string(Type) ->
+ Signature = <<"hejhopp">>,
+ Id = case Type of
+ rsa -> "ssh-rsa";
+ ecdsa -> "ecdsa-sha2-nistp256"
+ end,
+ gen_string(gen_string(Id) ++ gen_string(Signature)).
-define(MSG_CODE(Name,Num),
msg_code(Name) -> Num;
@@ -273,124 +264,34 @@ msg_code(Num) -> Name
?MSG_CODE('SSH_MSG_CHANNEL_FAILURE', 100);
?MSG_CODE('SSH_MSG_USERAUTH_INFO_REQUEST', 60);
?MSG_CODE('SSH_MSG_USERAUTH_INFO_RESPONSE', 61);
+?MSG_CODE('SSH_MSG_KEXDH_INIT', 30);
+?MSG_CODE('SSH_MSG_KEXDH_REPLY', 31);
?MSG_CODE('SSH_MSG_KEX_DH_GEX_REQUEST_OLD', 30);
?MSG_CODE('SSH_MSG_KEX_DH_GEX_REQUEST', 34);
?MSG_CODE('SSH_MSG_KEX_DH_GEX_GROUP', 31);
?MSG_CODE('SSH_MSG_KEX_DH_GEX_INIT', 32);
-?MSG_CODE('SSH_MSG_KEX_DH_GEX_REPLY', 33).
-
-%%%=============================================================================
-%%%=============================================================================
-%%%=============================================================================
-
-files(Fs) ->
- Defs = lists:usort(lists:flatten(lists:map(fun file/1, Fs))),
- DefinedIDs = lists:usort([binary_to_list(element(1,D)) || D <- Defs]),
- WantedIDs = lists:usort(wanted_messages()),
- Missing = WantedIDs -- DefinedIDs,
- case Missing of
- [] -> ok;
- _ -> io:format('%% Warning: missing ~p~n', [Missing])
- end,
- Defs.
-
-
-file(F) ->
- {ok,B} = file:read_file(F),
- hunt_msg_def(B).
-
-
-hunt_msg_def(<<"\n",B/binary>>) -> some_hope(skip_blanks(B));
-hunt_msg_def(<<_, B/binary>>) -> hunt_msg_def(B);
-hunt_msg_def(<<>>) -> [].
-
-some_hope(<<"byte ", B/binary>>) -> try_message(skip_blanks(B));
-some_hope(B) -> hunt_msg_def(B).
-
-try_message(B = <<"SSH_MSG_",_/binary>>) ->
- {ID,Rest} = get_id(B),
- case lists:member(binary_to_list(ID), wanted_messages()) of
- true ->
- {Lines,More} = get_def_lines(skip_blanks(Rest), []),
- [{ID,lists:reverse(Lines)} | hunt_msg_def(More)];
- false ->
- hunt_msg_def(Rest)
- end;
-try_message(B) -> hunt_msg_def(B).
-
-
-skip_blanks(<<32, B/binary>>) -> skip_blanks(B);
-skip_blanks(<< 9, B/binary>>) -> skip_blanks(B);
-skip_blanks(B) -> B.
-
-get_def_lines(B0 = <<"\n",B/binary>>, Acc) ->
- {ID,Rest} = get_id(skip_blanks(B)),
- case {size(ID), skip_blanks(Rest)} of
- {0,<<"....",More/binary>>} ->
- {Text,LineEnd} = get_to_eol(skip_blanks(More)),
- get_def_lines(LineEnd, [{<<"....">>,Text}|Acc]);
- {0,_} ->
- {Acc,B0};
- {_,Rest1} ->
- {Text,LineEnd} = get_to_eol(Rest1),
- get_def_lines(LineEnd, [{ID,Text}|Acc])
- end;
-get_def_lines(B, Acc) ->
- {Acc,B}.
-
-
-get_to_eol(B) -> split_binary(B, count_to_eol(B,0)).
-
-count_to_eol(<<"\n",_/binary>>, Acc) -> Acc;
-count_to_eol(<<>>, Acc) -> Acc;
-count_to_eol(<<_,B/binary>>, Acc) -> count_to_eol(B,Acc+1).
-
-
-get_id(B) -> split_binary(B, count_id_chars(B,0)).
-
-count_id_chars(<>, Acc) when $A= count_id_chars(B,Acc+1);
-count_id_chars(<>, Acc) when $a= count_id_chars(B,Acc+1);
-count_id_chars(<>, Acc) when $0= count_id_chars(B,Acc+1);
-count_id_chars(<<"_",B/binary>>, Acc) -> count_id_chars(B,Acc+1);
-count_id_chars(<<"-",B/binary>>, Acc) -> count_id_chars(B,Acc+1); %% e.g name-list
-count_id_chars(<<"[",B/binary>>, Acc) -> count_id_chars(B,Acc+1); %% e.g byte[16]
-count_id_chars(<<"]",B/binary>>, Acc) -> count_id_chars(B,Acc+1); %% e.g byte[16]
-count_id_chars(_, Acc) -> Acc.
-
-wanted_messages() ->
- ["SSH_MSG_CHANNEL_CLOSE",
- "SSH_MSG_CHANNEL_DATA",
- "SSH_MSG_CHANNEL_EOF",
- "SSH_MSG_CHANNEL_EXTENDED_DATA",
- "SSH_MSG_CHANNEL_FAILURE",
- "SSH_MSG_CHANNEL_OPEN",
- "SSH_MSG_CHANNEL_OPEN_CONFIRMATION",
- "SSH_MSG_CHANNEL_OPEN_FAILURE",
- "SSH_MSG_CHANNEL_REQUEST",
- "SSH_MSG_CHANNEL_SUCCESS",
- "SSH_MSG_CHANNEL_WINDOW_ADJUST",
- "SSH_MSG_DEBUG",
- "SSH_MSG_DISCONNECT",
- "SSH_MSG_GLOBAL_REQUEST",
- "SSH_MSG_IGNORE",
- "SSH_MSG_KEXDH_INIT",
- "SSH_MSG_KEXDH_REPLY",
- "SSH_MSG_KEXINIT",
- "SSH_MSG_KEX_DH_GEX_GROUP",
- "SSH_MSG_KEX_DH_GEX_REQUEST",
- "SSH_MSG_KEX_DH_GEX_REQUEST_OLD",
- "SSH_MSG_NEWKEYS",
- "SSH_MSG_REQUEST_FAILURE",
- "SSH_MSG_REQUEST_SUCCESS",
- "SSH_MSG_SERVICE_ACCEPT",
- "SSH_MSG_SERVICE_REQUEST",
- "SSH_MSG_UNIMPLEMENTED",
- "SSH_MSG_USERAUTH_BANNER",
- "SSH_MSG_USERAUTH_FAILURE",
-%% hard args "SSH_MSG_USERAUTH_INFO_REQUEST",
-%% "SSH_MSG_USERAUTH_INFO_RESPONSE",
- "SSH_MSG_USERAUTH_PASSWD_CHANGEREQ",
- "SSH_MSG_USERAUTH_PK_OK",
-%%rfc4252 p12 error "SSH_MSG_USERAUTH_REQUEST",
- "SSH_MSG_USERAUTH_SUCCESS"].
+?MSG_CODE('SSH_MSG_KEX_DH_GEX_REPLY', 33);
+?MSG_CODE('SSH_MSG_KEX_ECDH_INIT', 30);
+?MSG_CODE('SSH_MSG_KEX_ECDH_REPLY', 31).
+
+%%%====================================================
+%%%=== WARNING: Knowledge of the test object ahead! ===
+%%%====================================================
+
+%% SSH message records:
+-include_lib("ssh/src/ssh_connect.hrl").
+-include_lib("ssh/src/ssh_transport.hrl").
+
+%%% Encoding and decodeing is asymetric so out=binary in=string. Sometimes. :(
+fix_asym(#ssh_msg_global_request{name=N} = M) -> M#ssh_msg_global_request{name = binary_to_list(N)};
+fix_asym(#ssh_msg_debug{message=D,language=L} = M) -> M#ssh_msg_debug{message = binary_to_list(D),
+ language = binary_to_list(L)};
+fix_asym(#ssh_msg_kexinit{cookie=C} = M) -> M#ssh_msg_kexinit{cookie = <>};
+fix_asym(M) -> M.
+
+%%% Message codes 30 and 31 are overloaded depending on kex family so arrange the decoder
+%%% input as the test object does
+decode_state(<<30,_/binary>>=Msg, KexFam) -> <>;
+decode_state(<<31,_/binary>>=Msg, KexFam) -> <>;
+decode_state(Msg, _) -> Msg.
diff --git a/lib/ssh/test/ssh_property_test_SUITE.erl b/lib/ssh/test/ssh_property_test_SUITE.erl
index 7ba2732a88..9b2a84d8e4 100644
--- a/lib/ssh/test/ssh_property_test_SUITE.erl
+++ b/lib/ssh/test/ssh_property_test_SUITE.erl
@@ -68,9 +68,6 @@ init_per_group(_, Config) ->
end_per_group(_, Config) ->
Config.
-%%% Always skip the testcase that is not quite in phase with the
-%%% ssh_message.erl code
-init_per_testcase(decode_encode, _) -> {skip, "Fails - testcase is not ok"};
init_per_testcase(_TestCase, Config) -> Config.
end_per_testcase(_TestCase, Config) -> Config.
--
cgit v1.2.3
From 5901661b62a006a6c55d77503a7198c7c56dabe7 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Tue, 13 Dec 2016 10:35:31 +0100
Subject: ssh: Optimize handling of #ssh.shared_secret It is not necessary to
mpint-encode it every time it is used (in MAC:s), it sufficies to do it once
after key exchange
---
lib/ssh/src/ssh_transport.erl | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 21ba34506a..53e9ef485b 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -367,7 +367,7 @@ handle_kexdh_init(#ssh_msg_kexdh_init{e = E},
h_sig = H_SIG
}, Ssh0),
{ok, SshPacket, Ssh1#ssh{keyex_key = {{Private, Public}, {G, P}},
- shared_secret = K,
+ shared_secret = ssh_bits:mpint(K),
exchanged_hash = H,
session_id = sid(Ssh1, H)}};
@@ -393,7 +393,7 @@ handle_kexdh_reply(#ssh_msg_kexdh_reply{public_host_key = PeerPubHostKey,
case verify_host_key(Ssh0, PeerPubHostKey, H, H_SIG) of
ok ->
{SshPacket, Ssh} = ssh_packet(#ssh_msg_newkeys{}, Ssh0),
- {ok, SshPacket, Ssh#ssh{shared_secret = K,
+ {ok, SshPacket, Ssh#ssh{shared_secret = ssh_bits:mpint(K),
exchanged_hash = H,
session_id = sid(Ssh, H)}};
Error ->
@@ -532,7 +532,7 @@ handle_kex_dh_gex_init(#ssh_msg_kex_dh_gex_init{e = E},
ssh_packet(#ssh_msg_kex_dh_gex_reply{public_host_key = MyPubHostKey,
f = Public,
h_sig = H_SIG}, Ssh0),
- {ok, SshPacket, Ssh#ssh{shared_secret = K,
+ {ok, SshPacket, Ssh#ssh{shared_secret = ssh_bits:mpint(K),
exchanged_hash = H,
session_id = sid(Ssh, H)
}};
@@ -568,7 +568,7 @@ handle_kex_dh_gex_reply(#ssh_msg_kex_dh_gex_reply{public_host_key = PeerPubHostK
case verify_host_key(Ssh0, PeerPubHostKey, H, H_SIG) of
ok ->
{SshPacket, Ssh} = ssh_packet(#ssh_msg_newkeys{}, Ssh0),
- {ok, SshPacket, Ssh#ssh{shared_secret = K,
+ {ok, SshPacket, Ssh#ssh{shared_secret = ssh_bits:mpint(K),
exchanged_hash = H,
session_id = sid(Ssh, H)}};
_Error ->
@@ -618,7 +618,7 @@ handle_kex_ecdh_init(#ssh_msg_kex_ecdh_init{q_c = PeerPublic},
h_sig = H_SIG},
Ssh0),
{ok, SshPacket, Ssh1#ssh{keyex_key = {{MyPublic,MyPrivate},Curve},
- shared_secret = K,
+ shared_secret = ssh_bits:mpint(K),
exchanged_hash = H,
session_id = sid(Ssh1, H)}}
catch
@@ -644,7 +644,7 @@ handle_kex_ecdh_reply(#ssh_msg_kex_ecdh_reply{public_host_key = PeerPubHostKey,
case verify_host_key(Ssh0, PeerPubHostKey, H, H_SIG) of
ok ->
{SshPacket, Ssh} = ssh_packet(#ssh_msg_newkeys{}, Ssh0),
- {ok, SshPacket, Ssh#ssh{shared_secret = K,
+ {ok, SshPacket, Ssh#ssh{shared_secret = ssh_bits:mpint(K),
exchanged_hash = H,
session_id = sid(Ssh, H)}};
Error ->
@@ -1577,7 +1577,7 @@ hash(SSH, Char, Bits) ->
hash(_SSH, _Char, 0, _HASH) ->
<<>>;
hash(SSH, Char, N, HASH) ->
- K = ssh_bits:mpint(SSH#ssh.shared_secret),
+K = SSH#ssh.shared_secret, % K = ssh_bits:mpint(SSH#ssh.shared_secret),
H = SSH#ssh.exchanged_hash,
SessionID = SSH#ssh.session_id,
K1 = HASH([K, H, Char, SessionID]),
--
cgit v1.2.3
From 2b36238bc2a2444b97a3d01fa35ab1ceecfe1c4d Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Tue, 13 Dec 2016 10:38:27 +0100
Subject: ssh: Optimize ssh_bits:name_list It is better (=faster) to use
built-in functions and library functions.
---
lib/ssh/src/ssh_bits.erl | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_bits.erl b/lib/ssh/src/ssh_bits.erl
index 8bedaaf0c5..cc2e7e2be5 100644
--- a/lib/ssh/src/ssh_bits.erl
+++ b/lib/ssh/src/ssh_bits.erl
@@ -30,13 +30,7 @@
-export([random/1]).
%%%----------------------------------------------------------------
-name_list([Name]) -> to_bin(Name);
-name_list([Name|Ns]) -> <<(to_bin(Name))/binary, ",", (name_list(Ns))/binary>>;
-name_list([]) -> <<>>.
-
-to_bin(A) when is_atom(A) -> list_to_binary(atom_to_list(A));
-to_bin(S) when is_list(S) -> list_to_binary(S);
-to_bin(B) when is_binary(B) -> B.
+name_list(NamesList) -> list_to_binary(lists:join($,, NamesList)).
%%%----------------------------------------------------------------
%%% Multi Precision Integer encoding
--
cgit v1.2.3
From 767234a17378db0985ca49415ae5b9d3423ed754 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Tue, 13 Dec 2016 10:40:31 +0100
Subject: ssh: Optimze ssh_bits:mpint/1 By using binary constructors we push
the hard work down into the emulator
---
lib/ssh/src/ssh_bits.erl | 38 ++++++++++++++++++--------------------
1 file changed, 18 insertions(+), 20 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_bits.erl b/lib/ssh/src/ssh_bits.erl
index cc2e7e2be5..3ce7758447 100644
--- a/lib/ssh/src/ssh_bits.erl
+++ b/lib/ssh/src/ssh_bits.erl
@@ -36,27 +36,25 @@ name_list(NamesList) -> list_to_binary(lists:join($,, NamesList)).
%%% Multi Precision Integer encoding
mpint(-1) -> <<0,0,0,1,16#ff>>;
mpint(0) -> <<0,0,0,0>>;
-mpint(X) when X < 0 -> mpint_neg(X,0,[]);
-mpint(X) -> mpint_pos(X,0,[]).
-
-mpint_neg(-1,I,Ds=[MSB|_]) ->
- if MSB band 16#80 =/= 16#80 ->
- <>;
- true ->
- <>
+mpint(I) when I>0 ->
+ <> = binary:encode_unsigned(I),
+ case B1 band 16#80 of
+ 16#80 ->
+ <<(size(V)+2):32/unsigned-big-integer, 0,B1,V/binary >>;
+ _ ->
+ <<(size(V)+1):32/unsigned-big-integer, B1,V/binary >>
end;
-mpint_neg(X,I,Ds) ->
- mpint_neg(X bsr 8,I+1,[(X band 255)|Ds]).
-
-mpint_pos(0,I,Ds=[MSB|_]) ->
- if MSB band 16#80 == 16#80 ->
- <>;
- true ->
- <>
- end;
-mpint_pos(X,I,Ds) ->
- mpint_pos(X bsr 8,I+1,[(X band 255)|Ds]).
-
+mpint(N) when N<0 ->
+ Sxn = 8*size(binary:encode_unsigned(-N)),
+ Sxn1 = Sxn+8,
+ <> = <<1, 0:Sxn>>,
+ <> = binary:encode_unsigned(W+N),
+ case B1 band 16#80 of
+ 16#80 ->
+ <<(size(V)+1):32/unsigned-big-integer, B1,V/binary >>;
+ _ ->
+ <<(size(V)+2):32/unsigned-big-integer, 255,B1,V/binary >>
+ end.
%%%----------------------------------------------------------------
%% random/1
--
cgit v1.2.3
From 6d393493ded1462dd5469cb4bfc36db97134f5f3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?=
Date: Fri, 16 Dec 2016 18:48:42 +0100
Subject: ssh: Remove whitespace errors in ssh_sftp.erl
---
lib/ssh/src/ssh_sftp.erl | 128 +++++++++++++++++++++++------------------------
1 file changed, 64 insertions(+), 64 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_sftp.erl b/lib/ssh/src/ssh_sftp.erl
index afc2fb88ff..a648247ef9 100644
--- a/lib/ssh/src/ssh_sftp.erl
+++ b/lib/ssh/src/ssh_sftp.erl
@@ -37,7 +37,7 @@
-export([open/3, open_tar/3, opendir/2, close/2, readdir/2, pread/4, read/3,
open/4, open_tar/4, opendir/3, close/3, readdir/3, pread/5, read/4,
apread/4, aread/3, pwrite/4, write/3, apwrite/4, awrite/3,
- pwrite/5, write/4,
+ pwrite/5, write/4,
position/3, real_path/2, read_file_info/2, get_file_info/2,
position/4, real_path/3, read_file_info/3, get_file_info/3,
write_file_info/3, read_link_info/2, read_link/2, make_symlink/3,
@@ -52,7 +52,7 @@
%% TODO: Should be placed elsewhere ssh_sftpd should not call functions in ssh_sftp!
-export([info_to_attr/1, attr_to_info/1]).
--record(state,
+-record(state,
{
xf,
rep_buf = <<>>,
@@ -64,7 +64,7 @@
-record(fileinf,
{
- handle,
+ handle,
offset,
size,
mode
@@ -81,7 +81,7 @@
enc_text_buf = <<>>, % Encrypted text
plain_text_buf = <<>> % Decrypted text
}).
-
+
-define(FILEOP_TIMEOUT, infinity).
-define(NEXT_REQID(S),
@@ -98,7 +98,7 @@ start_channel(Cm) when is_pid(Cm) ->
start_channel(Socket) when is_port(Socket) ->
start_channel(Socket, []);
start_channel(Host) when is_list(Host) ->
- start_channel(Host, []).
+ start_channel(Host, []).
start_channel(Socket, Options) when is_port(Socket) ->
Timeout =
@@ -110,7 +110,7 @@ start_channel(Socket, Options) when is_port(Socket) ->
TO
end,
case ssh:connect(Socket, Options, Timeout) of
- {ok,Cm} ->
+ {ok,Cm} ->
case start_channel(Cm, Options) of
{ok, Pid} ->
{ok, Pid, Cm};
@@ -124,13 +124,13 @@ start_channel(Cm, Opts) when is_pid(Cm) ->
Timeout = proplists:get_value(timeout, Opts, infinity),
{_, ChanOpts, SftpOpts} = handle_options(Opts, [], [], []),
case ssh_xfer:attach(Cm, [], ChanOpts) of
- {ok, ChannelId, Cm} ->
- case ssh_channel:start(Cm, ChannelId,
+ {ok, ChannelId, Cm} ->
+ case ssh_channel:start(Cm, ChannelId,
?MODULE, [Cm, ChannelId, SftpOpts]) of
{ok, Pid} ->
case wait_for_version_negotiation(Pid, Timeout) of
ok ->
- {ok, Pid};
+ {ok, Pid};
TimeOut ->
TimeOut
end;
@@ -150,7 +150,7 @@ start_channel(Host, Port, Opts) ->
Timeout = proplists:get_value(timeout, SftpOpts, infinity),
case ssh_xfer:connect(Host, Port, SshOpts, ChanOpts, Timeout) of
{ok, ChannelId, Cm} ->
- case ssh_channel:start(Cm, ChannelId, ?MODULE, [Cm,
+ case ssh_channel:start(Cm, ChannelId, ?MODULE, [Cm,
ChannelId, SftpOpts]) of
{ok, Pid} ->
case wait_for_version_negotiation(Pid, Timeout) of
@@ -165,7 +165,7 @@ start_channel(Host, Port, Opts) ->
{error, ignore}
end;
Error ->
- Error
+ Error
end.
stop_channel(Pid) ->
@@ -174,12 +174,12 @@ stop_channel(Pid) ->
OldValue = process_flag(trap_exit, true),
link(Pid),
exit(Pid, ssh_sftp_stop_channel),
- receive
+ receive
{'EXIT', Pid, normal} ->
ok
after 5000 ->
exit(Pid, kill),
- receive
+ receive
{'EXIT', Pid, killed} ->
ok
end
@@ -209,9 +209,9 @@ open_tar(Pid, File, Mode, FileOpTimeout) ->
erl_tar:init(Pid, write,
fun(write, {_,Data}) ->
write_to_remote_tar(Pid, Handle, to_bin(Data), FileOpTimeout);
- (position, {_,Pos}) ->
+ (position, {_,Pos}) ->
position(Pid, Handle, Pos, FileOpTimeout);
- (close, _) ->
+ (close, _) ->
close(Pid, Handle, FileOpTimeout)
end);
{true,false,[{crypto,{CryptoInitFun,CryptoEncryptFun,CryptoEndFun}}]} ->
@@ -245,9 +245,9 @@ open_tar(Pid, File, Mode, FileOpTimeout) ->
erl_tar:init(Pid, read,
fun(read2, {_,Len}) ->
read_repeat(Pid, Handle, Len, FileOpTimeout);
- (position, {_,Pos}) ->
+ (position, {_,Pos}) ->
position(Pid, Handle, Pos, FileOpTimeout);
- (close, _) ->
+ (close, _) ->
close(Pid, Handle, FileOpTimeout)
end);
{false,true,[{crypto,{CryptoInitFun,CryptoDecryptFun}}]} ->
@@ -258,9 +258,9 @@ open_tar(Pid, File, Mode, FileOpTimeout) ->
erl_tar:init(Pid, read,
fun(read2, {_,Len}) ->
read_buf(Pid, SftpHandle, BufHandle, Len, FileOpTimeout);
- (position, {_,Pos}) ->
+ (position, {_,Pos}) ->
position_buf(Pid, SftpHandle, BufHandle, Pos, FileOpTimeout);
- (close, _) ->
+ (close, _) ->
call(Pid, {erase_bufinf,BufHandle}, FileOpTimeout),
close(Pid, SftpHandle, FileOpTimeout)
end);
@@ -292,7 +292,7 @@ pread(Pid, Handle, Offset, Len, FileOpTimeout) ->
read(Pid, Handle, Len) ->
read(Pid, Handle, Len, ?FILEOP_TIMEOUT).
read(Pid, Handle, Len, FileOpTimeout) ->
- call(Pid, {read,false,Handle, Len}, FileOpTimeout).
+ call(Pid, {read,false,Handle, Len}, FileOpTimeout).
%% TODO this ought to be a cast! Is so in all practial meaning
%% even if it is obscure!
@@ -301,7 +301,7 @@ apread(Pid, Handle, Offset, Len) ->
%% TODO this ought to be a cast!
aread(Pid, Handle, Len) ->
- call(Pid, {read,true,Handle, Len}, infinity).
+ call(Pid, {read,true,Handle, Len}, infinity).
pwrite(Pid, Handle, Offset, Data) ->
pwrite(Pid, Handle, Offset, Data, ?FILEOP_TIMEOUT).
@@ -367,7 +367,7 @@ make_symlink(Pid, Name, Target) ->
make_symlink(Pid, Name, Target, ?FILEOP_TIMEOUT).
make_symlink(Pid, Name, Target, FileOpTimeout) ->
call(Pid, {make_symlink,false, Name, Target}, FileOpTimeout).
-
+
rename(Pid, FromFile, ToFile) ->
rename(Pid, FromFile, ToFile, ?FILEOP_TIMEOUT).
rename(Pid, FromFile, ToFile, FileOpTimeout) ->
@@ -411,8 +411,8 @@ list_dir(Pid, Name, FileOpTimeout) ->
close(Pid, Handle, FileOpTimeout),
case Res of
{ok, List} ->
- NList = lists:foldl(fun({Nm, _Info},Acc) ->
- [Nm|Acc] end,
+ NList = lists:foldl(fun({Nm, _Info},Acc) ->
+ [Nm|Acc] end,
[], List),
{ok,NList};
Error -> Error
@@ -482,7 +482,7 @@ write_file_loop(Pid, Handle, Pos, Bin, Remain, PacketSz, FileOpTimeout) ->
<<_:Pos/binary, Data:PacketSz/binary, _/binary>> = Bin,
case write(Pid, Handle, Data, FileOpTimeout) of
ok ->
- write_file_loop(Pid, Handle,
+ write_file_loop(Pid, Handle,
Pos+PacketSz, Bin, Remain-PacketSz,
PacketSz, FileOpTimeout);
Error ->
@@ -510,7 +510,7 @@ init([Cm, ChannelId, Options]) ->
Xf = #ssh_xfer{cm = Cm,
channel = ChannelId},
{ok, #state{xf = Xf,
- req_id = 0,
+ req_id = 0,
rep_buf = <<>>,
inf = new_inf(),
opts = Options}};
@@ -519,7 +519,7 @@ init([Cm, ChannelId, Options]) ->
Error ->
{stop, {shutdown, Error}}
end.
-
+
%%--------------------------------------------------------------------
%% Function: handle_call/3
%% Description: Handling call messages
@@ -541,7 +541,7 @@ handle_call({{timeout, Timeout}, wait_for_version_negotiation}, From,
handle_call({_, wait_for_version_negotiation}, _, State) ->
{reply, ok, State};
-
+
handle_call({{timeout, infinity}, Msg}, From, State) ->
do_handle_call(Msg, From, State);
handle_call({{timeout, Timeout}, Msg}, From, #state{req_id = Id} = State) ->
@@ -636,7 +636,7 @@ do_handle_call({pread,Async,Handle,At,Length}, From, State) ->
binary -> {{ok,Data}, State2};
text -> {{ok,binary_to_list(Data)}, State2}
end;
- (Rep, State2) ->
+ (Rep, State2) ->
{Rep, State2}
end);
Error ->
@@ -777,7 +777,7 @@ do_handle_call(recv_window, _From, State) ->
do_handle_call(stop, _From, State) ->
{stop, shutdown, ok, State};
-do_handle_call(Call, _From, State) ->
+do_handle_call(Call, _From, State) ->
{reply, {error, bad_call, Call, State}, State}.
%%--------------------------------------------------------------------
@@ -785,13 +785,13 @@ do_handle_call(Call, _From, State) ->
%%
%% Description: Handles channel messages
%%--------------------------------------------------------------------
-handle_ssh_msg({ssh_cm, _ConnectionManager,
- {data, _ChannelId, 0, Data}}, #state{rep_buf = Data0} =
+handle_ssh_msg({ssh_cm, _ConnectionManager,
+ {data, _ChannelId, 0, Data}}, #state{rep_buf = Data0} =
State0) ->
State = handle_reply(State0, <>),
{ok, State};
-handle_ssh_msg({ssh_cm, _ConnectionManager,
+handle_ssh_msg({ssh_cm, _ConnectionManager,
{data, _ChannelId, 1, Data}}, State) ->
error_logger:format("ssh: STDERR: ~s\n", [binary_to_list(Data)]),
{ok, State};
@@ -803,7 +803,7 @@ handle_ssh_msg({ssh_cm, _, {signal, _, _}}, State) ->
%% Ignore signals according to RFC 4254 section 6.9.
{ok, State};
-handle_ssh_msg({ssh_cm, _, {exit_signal, ChannelId, _, Error, _}},
+handle_ssh_msg({ssh_cm, _, {exit_signal, ChannelId, _, Error, _}},
State0) ->
State = reply_all(State0, {error, Error}),
{stop, ChannelId, State};
@@ -823,7 +823,7 @@ handle_msg({ssh_channel_up, _, _}, #state{opts = Options, xf = Xf} = State) ->
{ok, State};
%% Version negotiation timed out
-handle_msg({timeout, undefined, From},
+handle_msg({timeout, undefined, From},
#state{xf = #ssh_xfer{channel = ChannelId}} = State) ->
ssh_channel:reply(From, {error, timeout}),
{stop, ChannelId, State};
@@ -839,12 +839,12 @@ handle_msg({timeout, Id, From}, #state{req_list = ReqList0} = State) ->
end;
%% Connection manager goes down
-handle_msg({'DOWN', _Ref, _Type, _Process, _},
+handle_msg({'DOWN', _Ref, _Type, _Process, _},
#state{xf = #ssh_xfer{channel = ChannelId}} = State) ->
{stop, ChannelId, State};
-
+
%% Stopped by user
-handle_msg({'EXIT', _, ssh_sftp_stop_channel},
+handle_msg({'EXIT', _, ssh_sftp_stop_channel},
#state{xf = #ssh_xfer{channel = ChannelId}} = State) ->
{stop, ChannelId, State};
@@ -883,10 +883,10 @@ call(Pid, Msg, TimeOut) ->
handle_reply(State, <>) ->
do_handle_reply(State, Reply, Rest);
-handle_reply(State, Data) ->
+handle_reply(State, Data) ->
State#state{rep_buf = Data}.
-do_handle_reply(#state{xf = Xf} = State,
+do_handle_reply(#state{xf = Xf} = State,
<>, Rest) ->
Ext = ssh_xfer:decode_ext(BinExt),
case Xf#ssh_xfer.vsn of
@@ -899,7 +899,7 @@ do_handle_reply(#state{xf = Xf} = State,
ok
end,
ssh_channel:reply(From, ok)
- end,
+ end,
State#state{xf = Xf#ssh_xfer{vsn = Version, ext = Ext}, rep_buf = Rest};
do_handle_reply(State0, Data, Rest) ->
@@ -919,9 +919,9 @@ handle_req_reply(State0, {_, ReqID, _} = XfReply) ->
List = lists:keydelete(ReqID, 1, State0#state.req_list),
State1 = State0#state { req_list = List },
case catch Fun(xreply(XfReply),State1) of
- {'EXIT', _} ->
+ {'EXIT', _} ->
State1;
- State ->
+ State ->
State
end
end.
@@ -998,15 +998,15 @@ reply_all(State, Reply) ->
make_reply(ReqID, true, From, State) ->
{reply, {async, ReqID},
update_request_info(ReqID, State,
- fun(Reply,State1) ->
+ fun(Reply,State1) ->
async_reply(ReqID,Reply,From,State1)
end)};
make_reply(ReqID, false, From, State) ->
{noreply,
update_request_info(ReqID, State,
- fun(Reply,State1) ->
- sync_reply(Reply, From, State1)
+ fun(Reply,State1) ->
+ sync_reply(Reply, From, State1)
end)}.
make_reply_post(ReqID, true, From, State, PostFun) ->
@@ -1074,13 +1074,13 @@ attr_to_info(A) when is_record(A, ssh_xfer_attr) ->
unix_to_datetime(undefined) ->
undefined;
unix_to_datetime(UTCSecs) ->
- UTCDateTime =
+ UTCDateTime =
calendar:gregorian_seconds_to_datetime(UTCSecs + 62167219200),
erlang:universaltime_to_localtime(UTCDateTime).
datetime_to_unix(undefined) ->
undefined;
-datetime_to_unix(LocalDateTime) ->
+datetime_to_unix(LocalDateTime) ->
UTCDateTime = erlang:localtime_to_universaltime(LocalDateTime),
calendar:datetime_to_gregorian_seconds(UTCDateTime) - 62167219200.
@@ -1229,7 +1229,7 @@ lseek_pos({cur, Offset}, CurOffset, _CurSize)
true ->
{ok, NewOffset}
end;
-lseek_pos({eof, Offset}, _CurOffset, CurSize)
+lseek_pos({eof, Offset}, _CurOffset, CurSize)
when is_integer(Offset) andalso -(?SSH_FILEXFER_LARGEFILESIZE) =< Offset andalso
Offset < ?SSH_FILEXFER_LARGEFILESIZE ->
NewOffset = CurSize + Offset,
@@ -1239,7 +1239,7 @@ lseek_pos({eof, Offset}, _CurOffset, CurSize)
{ok, NewOffset}
end;
lseek_pos(_, _, _) ->
- {error, einval}.
+ {error, einval}.
%%%================================================================
%%%
@@ -1277,13 +1277,13 @@ position_buf(Pid, SftpHandle, BufHandle, Pos, FileOpTimeout) ->
case Pos of
{cur,0} when Mode==write ->
{ok,Size+size(Buf0)};
-
+
{cur,0} when Mode==read ->
{ok,Size};
-
+
_ when Mode==read, is_integer(Pos) ->
Skip = Pos-Size,
- if
+ if
Skip < 0 ->
{error, cannot_rewind};
Skip == 0 ->
@@ -1318,7 +1318,7 @@ read_buf(Pid, SftpHandle, BufHandle, WantedLen, FileOpTimeout) ->
eof
end.
-do_the_read_buf(_Pid, _SftpHandle, WantedLen, _Packet, _FileOpTimeout,
+do_the_read_buf(_Pid, _SftpHandle, WantedLen, _Packet, _FileOpTimeout,
B=#bufinf{plain_text_buf=PlainBuf0,
size = Size})
when size(PlainBuf0) >= WantedLen ->
@@ -1327,7 +1327,7 @@ do_the_read_buf(_Pid, _SftpHandle, WantedLen, _Packet, _FileOpTimeout,
{ok,ResultBin,B#bufinf{plain_text_buf=PlainBuf,
size = Size + WantedLen}};
-do_the_read_buf(Pid, SftpHandle, WantedLen, Packet, FileOpTimeout,
+do_the_read_buf(Pid, SftpHandle, WantedLen, Packet, FileOpTimeout,
B0=#bufinf{plain_text_buf = PlainBuf0,
enc_text_buf = EncBuf0,
chunksize = undefined
@@ -1335,12 +1335,12 @@ do_the_read_buf(Pid, SftpHandle, WantedLen, Packet, FileOpTimeout,
when size(EncBuf0) > 0 ->
%% We have (at least) one decodable byte waiting for decodeing.
{ok,DecodedBin,B} = apply_crypto(EncBuf0, B0),
- do_the_read_buf(Pid, SftpHandle, WantedLen, Packet, FileOpTimeout,
+ do_the_read_buf(Pid, SftpHandle, WantedLen, Packet, FileOpTimeout,
B#bufinf{plain_text_buf = <>,
enc_text_buf = <<>>
});
-
-do_the_read_buf(Pid, SftpHandle, WantedLen, Packet, FileOpTimeout,
+
+do_the_read_buf(Pid, SftpHandle, WantedLen, Packet, FileOpTimeout,
B0=#bufinf{plain_text_buf = PlainBuf0,
enc_text_buf = EncBuf0,
chunksize = ChunkSize0
@@ -1349,11 +1349,11 @@ do_the_read_buf(Pid, SftpHandle, WantedLen, Packet, FileOpTimeout,
%% We have (at least) one chunk of decodable bytes waiting for decodeing.
<> = EncBuf0,
{ok,DecodedBin,B} = apply_crypto(ToDecode, B0),
- do_the_read_buf(Pid, SftpHandle, WantedLen, Packet, FileOpTimeout,
+ do_the_read_buf(Pid, SftpHandle, WantedLen, Packet, FileOpTimeout,
B#bufinf{plain_text_buf = <>,
enc_text_buf = EncBuf
});
-
+
do_the_read_buf(Pid, SftpHandle, WantedLen, Packet, FileOpTimeout, B=#bufinf{enc_text_buf = EncBuf0}) ->
%% We must read more bytes and append to the buffer of encoded bytes.
case read(Pid, SftpHandle, Packet, FileOpTimeout) of
@@ -1370,7 +1370,7 @@ do_the_read_buf(Pid, SftpHandle, WantedLen, Packet, FileOpTimeout, B=#bufinf{enc
write_buf(Pid, SftpHandle, BufHandle, PlainBin, FileOpTimeout) ->
{ok,{_Window,Packet}} = send_window(Pid, FileOpTimeout),
{ok,B0=#bufinf{plain_text_buf=PTB}} = call(Pid, {get_bufinf,BufHandle}, FileOpTimeout),
- case do_the_write_buf(Pid, SftpHandle, Packet, FileOpTimeout,
+ case do_the_write_buf(Pid, SftpHandle, Packet, FileOpTimeout,
B0#bufinf{plain_text_buf = <>}) of
{ok, B} ->
call(Pid, {put_bufinf,BufHandle,B}, FileOpTimeout),
@@ -1379,7 +1379,7 @@ write_buf(Pid, SftpHandle, BufHandle, PlainBin, FileOpTimeout) ->
{error,Error}
end.
-do_the_write_buf(Pid, SftpHandle, Packet, FileOpTimeout,
+do_the_write_buf(Pid, SftpHandle, Packet, FileOpTimeout,
B=#bufinf{enc_text_buf = EncBuf0,
size = Size})
when size(EncBuf0) >= Packet ->
@@ -1421,9 +1421,9 @@ do_the_write_buf(_Pid, _SftpHandle, _Packet, _FileOpTimeout, B) ->
apply_crypto(In, B=#bufinf{crypto_state = CState0,
crypto_fun = F}) ->
case F(In,CState0) of
- {ok,EncodedBin,CState} ->
+ {ok,EncodedBin,CState} ->
{ok, EncodedBin, B#bufinf{crypto_state=CState}};
- {ok,EncodedBin,CState,ChunkSize} ->
+ {ok,EncodedBin,CState,ChunkSize} ->
{ok, EncodedBin, B#bufinf{crypto_state=CState,
chunksize=ChunkSize}}
end.
--
cgit v1.2.3
From 4161f80e0197ec5447f9a48ef3a0c9c6cfcfa5d5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?=
Date: Fri, 16 Dec 2016 18:55:40 +0100
Subject: ssh: Use maps instead of dict in ssh_sftp
---
lib/ssh/src/ssh_sftp.erl | 37 +++++++++++++++++--------------------
1 file changed, 17 insertions(+), 20 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_sftp.erl b/lib/ssh/src/ssh_sftp.erl
index a648247ef9..b937f0412d 100644
--- a/lib/ssh/src/ssh_sftp.erl
+++ b/lib/ssh/src/ssh_sftp.erl
@@ -555,13 +555,13 @@ code_change(_OldVsn, State, _Extra) ->
{ok, State}.
do_handle_call({get_bufinf,BufHandle}, _From, S=#state{inf=I0}) ->
- {reply, dict:find(BufHandle,I0), S};
+ {reply, maps:find(BufHandle,I0), S};
do_handle_call({put_bufinf,BufHandle,B}, _From, S=#state{inf=I0}) ->
- {reply, ok, S#state{inf=dict:store(BufHandle,B,I0)}};
+ {reply, ok, S#state{inf=maps:put(BufHandle,B,I0)}};
do_handle_call({erase_bufinf,BufHandle}, _From, S=#state{inf=I0}) ->
- {reply, ok, S#state{inf=dict:erase(BufHandle,I0)}};
+ {reply, ok, S#state{inf=maps:remove(BufHandle,I0)}};
do_handle_call({open, Async,FileName,Mode}, From, #state{xf = XF} = State) ->
{Access,Flags,Attrs} = open_mode(XF#ssh_xfer.vsn, Mode),
@@ -1128,11 +1128,11 @@ open_mode3(Modes) ->
end,
{[], Fl, A}.
-%% accessors for inf dict
-new_inf() -> dict:new().
+%% accessors for inf map
+new_inf() -> #{}.
add_new_handle(Handle, FileMode, Inf) ->
- dict:store(Handle, #fileinf{offset=0, size=0, mode=FileMode}, Inf).
+ maps:put(Handle, #fileinf{offset=0, size=0, mode=FileMode}, Inf).
update_size(Handle, NewSize, State) ->
OldSize = get_size(Handle, State),
@@ -1152,27 +1152,24 @@ update_offset(Handle, NewOffset, State0) ->
%% access size and offset for handle
put_size(Handle, Size, State) ->
Inf0 = State#state.inf,
- case dict:find(Handle, Inf0) of
+ case maps:find(Handle, Inf0) of
{ok, FI} ->
- State#state{inf=dict:store(Handle, FI#fileinf{size=Size}, Inf0)};
+ State#state{inf=maps:put(Handle, FI#fileinf{size=Size}, Inf0)};
_ ->
- State#state{inf=dict:store(Handle, #fileinf{size=Size,offset=0},
- Inf0)}
+ State#state{inf=maps:put(Handle, #fileinf{size=Size,offset=0}, Inf0)}
end.
put_offset(Handle, Offset, State) ->
Inf0 = State#state.inf,
- case dict:find(Handle, Inf0) of
+ case maps:find(Handle, Inf0) of
{ok, FI} ->
- State#state{inf=dict:store(Handle, FI#fileinf{offset=Offset},
- Inf0)};
+ State#state{inf=maps:put(Handle, FI#fileinf{offset=Offset}, Inf0)};
_ ->
- State#state{inf=dict:store(Handle, #fileinf{size=Offset,
- offset=Offset}, Inf0)}
+ State#state{inf=maps:put(Handle, #fileinf{size=Offset, offset=Offset}, Inf0)}
end.
get_size(Handle, State) ->
- case dict:find(Handle, State#state.inf) of
+ case maps:find(Handle, State#state.inf) of
{ok, FI} ->
FI#fileinf.size;
_ ->
@@ -1180,11 +1177,11 @@ get_size(Handle, State) ->
end.
%% get_offset(Handle, State) ->
-%% {ok, FI} = dict:find(Handle, State#state.inf),
+%% {ok, FI} = maps:find(Handle, State#state.inf),
%% FI#fileinf.offset.
get_mode(Handle, State) ->
- case dict:find(Handle, State#state.inf) of
+ case maps:find(Handle, State#state.inf) of
{ok, FI} ->
FI#fileinf.mode;
_ ->
@@ -1192,14 +1189,14 @@ get_mode(Handle, State) ->
end.
erase_handle(Handle, State) ->
- FI = dict:erase(Handle, State#state.inf),
+ FI = maps:remove(Handle, State#state.inf),
State#state{inf = FI}.
%%
%% Caluclate a integer offset
%%
lseek_position(Handle, Pos, State) ->
- case dict:find(Handle, State#state.inf) of
+ case maps:find(Handle, State#state.inf) of
{ok, #fileinf{offset=O, size=S}} ->
lseek_pos(Pos, O, S);
_ ->
--
cgit v1.2.3
From 3c5c1d70ec006e5b0b87dad0bf97a09e62e1e7c6 Mon Sep 17 00:00:00 2001
From: Philip Cristiano
Date: Wed, 11 Jan 2017 06:13:49 -0500
Subject: ssh: Correct ssh_sftpd_file_api dialzyer spec
The `State` seems to have been included twice in 91acfc.
---
lib/ssh/src/ssh_sftpd_file_api.erl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_sftpd_file_api.erl b/lib/ssh/src/ssh_sftpd_file_api.erl
index 78f452df67..e444e52ac0 100644
--- a/lib/ssh/src/ssh_sftpd_file_api.erl
+++ b/lib/ssh/src/ssh_sftpd_file_api.erl
@@ -36,7 +36,7 @@
-callback list_dir(file:name(), State::term()) ->
{{ok, Filenames::term()}, State::term()} | {{error, Reason::term()}, State::term()}.
-callback make_dir(Dir::term(), State::term()) ->
- {{ok, State::term()},State::term()} | {{error, Reason::term()}, State::term()}.
+ {ok, State::term()} | {{error, Reason::term()}, State::term()}.
-callback make_symlink(Path2::term(), Path::term(), State::term()) ->
{ok, State::term()} | {{error, Reason::term()}, State::term()}.
-callback open(Path::term(), Flags::term(), State::term()) ->
--
cgit v1.2.3
From 9ff231ba932dded5d712bb34fffe1f396d975a2c Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 18 Jan 2017 16:08:01 +0100
Subject: ssh: Reduce info leakage on decrypt errors
Use same message when there are packet errors like too long length, MAC, decrypt or decode errors.
This is regarded as good practise to prevent some attacks
---
lib/ssh/src/ssh_connection_handler.erl | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 7451c9e6d0..8718e92fa2 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -1206,7 +1206,7 @@ handle_event(info, {Proto, Sock, NewData}, StateName, D0 = #data{socket = Sock,
catch
_C:_E ->
disconnect(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_PROTOCOL_ERROR,
- description = "Encountered unexpected input"},
+ description = "Bad packet"},
StateName, D)
end;
@@ -1221,13 +1221,12 @@ handle_event(info, {Proto, Sock, NewData}, StateName, D0 = #data{socket = Sock,
{bad_mac, Ssh1} ->
disconnect(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_PROTOCOL_ERROR,
- description = "Bad mac"},
+ description = "Bad packet"},
StateName, D0#data{ssh_params=Ssh1});
- {error, {exceeds_max_size,PacketLen}} ->
+ {error, {exceeds_max_size,_PacketLen}} ->
disconnect(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_PROTOCOL_ERROR,
- description = "Bad packet length "
- ++ integer_to_list(PacketLen)},
+ description = "Bad packet"},
StateName, D0)
catch
_C:_E ->
--
cgit v1.2.3
From 37d66ba5ae92a37ce0199025b4af697216ea802d Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 18 Jan 2017 18:51:16 +0100
Subject: ssh: fixed benchmark bug for gcm-modes
The bug has not affected existing results because no gcm-modes has been measured.
---
lib/ssh/test/ssh_benchmark_SUITE.erl | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_benchmark_SUITE.erl b/lib/ssh/test/ssh_benchmark_SUITE.erl
index c2bfc48449..2098d59995 100644
--- a/lib/ssh/test/ssh_benchmark_SUITE.erl
+++ b/lib/ssh/test/ssh_benchmark_SUITE.erl
@@ -70,9 +70,12 @@ init_per_group(opensshc_erld, Config) ->
ssh_test_lib:setup_dsa(DataDir, UserDir),
ssh_test_lib:setup_rsa(DataDir, UserDir),
ssh_test_lib:setup_ecdsa("256", DataDir, UserDir),
+ AlgsD = ssh:default_algorithms(),
+ AlgsC = ssh_test_lib:default_algorithms(sshc),
Common = ssh_test_lib:intersect_bi_dir(
- ssh_test_lib:intersection(ssh:default_algorithms(),
- ssh_test_lib:default_algorithms(sshc))),
+ ssh_test_lib:intersection(AlgsD, AlgsC)),
+ ct:pal("~p~n~nErld:~n~p~n~nOpenSSHc:~n~p~n~nCommon:~n~p",
+ [inet:gethostname(), AlgsD, AlgsC, Common]),
[{c_kexs, ssh_test_lib:sshc(kex)},
{c_ciphers, ssh_test_lib:sshc(cipher)},
{common_algs, Common}
@@ -427,13 +430,20 @@ function_algs_times_sizes(EncDecs, L) ->
|| {Alg,Size,Time} <- lists:foldl(fun increment/2, [], Raw)].
function_ats_result({ssh_transport,encrypt,2}, #call{args=[S,Data]}) ->
- {{encrypt,S#ssh.encrypt}, size(Data)};
+ {{encrypt,S#ssh.encrypt}, binsize(Data)};
function_ats_result({ssh_transport,decrypt,2}, #call{args=[S,Data]}) ->
- {{decrypt,S#ssh.decrypt}, size(Data)};
+ {{decrypt,S#ssh.decrypt}, binsize(Data)};
function_ats_result({ssh_message,encode,1}, #call{result=Data}) ->
{encode, size(Data)};
function_ats_result({ssh_message,decode,1}, #call{args=[Data]}) ->
{decode, size(Data)}.
+
+binsize(B) when is_binary(B) -> size(B);
+binsize({B1,B2}) when is_binary(B1), is_binary(B2) -> size(B1) + size(B2);
+binsize({B1,B2,_}) when is_binary(B1), is_binary(B2) -> size(B1) + size(B2).
+
+
+
increment({Alg,Sz,T}, [{Alg,SumSz,SumT}|Acc]) ->
--
cgit v1.2.3
From 69637f4d94c77da23cb8f84b8a6942c28483c2a4 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 18 Jan 2017 19:33:26 +0100
Subject: ssh: increased benchmark suite timetrap
---
lib/ssh/test/ssh_benchmark_SUITE.erl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_benchmark_SUITE.erl b/lib/ssh/test/ssh_benchmark_SUITE.erl
index 2098d59995..85750f8fbd 100644
--- a/lib/ssh/test/ssh_benchmark_SUITE.erl
+++ b/lib/ssh/test/ssh_benchmark_SUITE.erl
@@ -30,7 +30,7 @@
suite() -> [{ct_hooks,[{ts_install_cth,[{nodenames,2}]}]},
- {timetrap,{minutes,3}}
+ {timetrap,{minutes,6}}
].
%%suite() -> [{ct_hooks,[ts_install_cth]}].
--
cgit v1.2.3
From d4f04425dbf98ee6ef97b4cbfaea0d62bd2fd28d Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 19 Jan 2017 19:56:55 +0100
Subject: ssh: fix mpint-bug in property tests
---
lib/ssh/test/property_test/ssh_eqc_encode_decode.erl | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl b/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl
index 0f8a838f97..8ca29b9399 100644
--- a/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl
+++ b/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl
@@ -184,10 +184,7 @@ gen_byte(N) when N>0 -> [gen_byte() || _ <- lists:seq(1,N)].
gen_char() -> choose($a,$z).
-gen_mpint() -> ?LET(Size, choose(1,20),
- ?LET(Str, vector(Size, gen_byte()),
- gen_string( strip_0s(Str) )
- )).
+gen_mpint() -> ?LET(I, largeint(), ssh_bits:mpint(I)).
strip_0s([0|T]) -> strip_0s(T);
strip_0s(X) -> X.
--
cgit v1.2.3
From 69feb8bed6118e9a955d71c8d55faa6bc5dec1b1 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 20 Jan 2017 14:57:00 +0100
Subject: ssh: ssh_dbg now reports HELLO msgs and timestamps
---
lib/ssh/src/ssh_dbg.erl | 66 ++++++++++++++++++++++++++++++-------------------
1 file changed, 41 insertions(+), 25 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_dbg.erl b/lib/ssh/src/ssh_dbg.erl
index dff2bae9f2..0345bbdea7 100644
--- a/lib/ssh/src/ssh_dbg.erl
+++ b/lib/ssh/src/ssh_dbg.erl
@@ -50,50 +50,61 @@ messages(Write, MangleArg) when is_function(Write,2),
is_function(MangleArg,1) ->
catch dbg:start(),
setup_tracer(Write, MangleArg),
- dbg:p(new,c),
+ dbg:p(new,[c,timestamp]),
dbg_ssh_messages().
dbg_ssh_messages() ->
dbg:tp(ssh_message,encode,1, x),
dbg:tp(ssh_message,decode,1, x),
- dbg:tpl(ssh_transport,select_algorithm,3, x).
-
+ dbg:tpl(ssh_transport,select_algorithm,3, x),
+ dbg:tp(ssh_transport,hello_version_msg,1, x),
+ dbg:tp(ssh_transport,handle_hello_version,1, x).
+
%%%----------------------------------------------------------------
stop() ->
dbg:stop().
%%%================================================================
-msg_formater({trace,Pid,call,{ssh_message,encode,[Msg]}}, D) ->
- fmt("~nSEND ~p ~s~n", [Pid,wr_record(shrink_bin(Msg))], D);
-msg_formater({trace,_Pid,return_from,{ssh_message,encode,1},_Res}, D) ->
+msg_formater({trace_ts,Pid,call,{ssh_message,encode,[Msg]},TS}, D) ->
+ fmt("~n~s SEND ~p ~s~n", [ts(TS),Pid,wr_record(shrink_bin(Msg))], D);
+msg_formater({trace_ts,_Pid,return_from,{ssh_message,encode,1},_Res,_TS}, D) ->
D;
-msg_formater({trace,_Pid,call,{ssh_message,decode,_}}, D) ->
+msg_formater({trace_ts,_Pid,call,{ssh_message,decode,_},_TS}, D) ->
D;
-msg_formater({trace,Pid,return_from,{ssh_message,decode,1},Msg}, D) ->
- fmt("~n~p RECV ~s~n", [Pid,wr_record(shrink_bin(Msg))], D);
+msg_formater({trace_ts,Pid,return_from,{ssh_message,decode,1},Msg,TS}, D) ->
+ fmt("~n~s ~p RECV ~s~n", [ts(TS),Pid,wr_record(shrink_bin(Msg))], D);
-msg_formater({trace,_Pid,call,{ssh_transport,select_algorithm,_}}, D) ->
+msg_formater({trace_ts,_Pid,call,{ssh_transport,select_algorithm,_},_TS}, D) ->
+ D;
+msg_formater({trace_ts,Pid,return_from,{ssh_transport,select_algorithm,3},{ok,Alg},TS}, D) ->
+ fmt("~n~s ~p ALGORITHMS~n~s~n", [ts(TS),Pid, wr_record(Alg)], D);
+
+msg_formater({trace_ts,_Pid,call,{ssh_transport,hello_version_msg,_},_TS}, D) ->
D;
-msg_formater({trace,Pid,return_from,{ssh_transport,select_algorithm,3},{ok,Alg}}, D) ->
- fmt("~n~p ALGORITHMS~n~s~n", [Pid, wr_record(Alg)], D);
+msg_formater({trace_ts,Pid,return_from,{ssh_transport,hello_version_msg,1},Hello,TS}, D) ->
+ fmt("~n~s ~p TCP SEND HELLO~n ~p~n", [ts(TS),Pid,lists:flatten(Hello)], D);
+msg_formater({trace_ts,Pid,call,{ssh_transport,handle_hello_version,[Hello]},TS}, D) ->
+ fmt("~n~s ~p RECV HELLO~n ~p~n", [ts(TS),Pid,lists:flatten(Hello)], D);
+msg_formater({trace_ts,_Pid,return_from,{ssh_transport,handle_hello_version,1},_,_TS}, D) ->
+ D;
-msg_formater({trace,Pid,send,{tcp,Sock,Bytes},Pid}, D) ->
- fmt("~n~p TCP SEND on ~p~n ~p~n", [Pid,Sock, shrink_bin(Bytes)], D);
+msg_formater({trace_ts,Pid,send,{tcp,Sock,Bytes},Pid,TS}, D) ->
+ fmt("~n~s ~p TCP SEND on ~p~n ~p~n", [ts(TS),Pid,Sock, shrink_bin(Bytes)], D);
-msg_formater({trace,Pid,send,{tcp,Sock,Bytes},Dest}, D) ->
- fmt("~n~p TCP SEND from ~p TO ~p~n ~p~n", [Pid,Sock,Dest, shrink_bin(Bytes)], D);
+msg_formater({trace_ts,Pid,send,{tcp,Sock,Bytes},Dest,TS}, D) ->
+ fmt("~n~s ~p TCP SEND from ~p TO ~p~n ~p~n", [ts(TS),Pid,Sock,Dest, shrink_bin(Bytes)], D);
-msg_formater({trace,Pid,send,ErlangMsg,Dest}, D) ->
- fmt("~n~p ERL MSG SEND TO ~p~n ~p~n", [Pid,Dest, shrink_bin(ErlangMsg)], D);
+msg_formater({trace_ts,Pid,send,ErlangMsg,Dest,TS}, D) ->
+ fmt("~n~s ~p ERL MSG SEND TO ~p~n ~p~n", [ts(TS),Pid,Dest, shrink_bin(ErlangMsg)], D);
-msg_formater({trace,Pid,'receive',{tcp,Sock,Bytes}}, D) ->
- fmt("~n~p TCP RECEIVE on ~p~n ~p~n", [Pid,Sock,shrink_bin(Bytes)], D);
+msg_formater({trace_ts,Pid,'receive',{tcp,Sock,Bytes},TS}, D) ->
+ fmt("~n~s ~p TCP RECEIVE on ~p~n ~p~n", [ts(TS),Pid,Sock,shrink_bin(Bytes)], D);
-msg_formater({trace,Pid,'receive',ErlangMsg}, D) ->
- fmt("~n~p ERL MSG RECEIVE~n ~p~n", [Pid,shrink_bin(ErlangMsg)], D);
+msg_formater({trace_ts,Pid,'receive',ErlangMsg,TS}, D) ->
+ fmt("~n~s ~p ERL MSG RECEIVE~n ~p~n", [ts(TS),Pid,shrink_bin(ErlangMsg)], D);
msg_formater(M, D) ->
@@ -106,6 +117,11 @@ msg_formater(M, D) ->
fmt(Fmt, Args, D=#data{writer=Write,acc=Acc}) ->
D#data{acc = Write(io_lib:format(Fmt, Args), Acc)}.
+ts({_,_,Usec}=Now) ->
+ {_Date,{HH,MM,SS}} = calendar:now_to_local_time(Now),
+ io_lib:format("~.2.0w:~.2.0w:~.2.0w.~.6.0w",[HH,MM,SS,Usec]);
+ts(_) ->
+ "-".
%%%----------------------------------------------------------------
setup_tracer(Write, MangleArg) ->
Handler = fun(Arg, D) ->
@@ -116,11 +132,11 @@ setup_tracer(Write, MangleArg) ->
ok.
%%%----------------------------------------------------------------
-shrink_bin(B) when is_binary(B), size(B)>100 -> {'*** SHRINKED BIN',
+shrink_bin(B) when is_binary(B), size(B)>256 -> {'*** SHRINKED BIN',
size(B),
- element(1,split_binary(B,20)),
+ element(1,split_binary(B,64)),
'...',
- element(2,split_binary(B,size(B)-20))
+ element(2,split_binary(B,size(B)-64))
};
shrink_bin(L) when is_list(L) -> lists:map(fun shrink_bin/1, L);
shrink_bin(T) when is_tuple(T) -> list_to_tuple(shrink_bin(tuple_to_list(T)));
--
cgit v1.2.3
From e0b2554dcfae4a8a20adbb3ebf226f7ebe4f89ab Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 25 Jan 2017 16:36:38 +0100
Subject: ssh: correct host key signature calculation
---
lib/ssh/src/ssh_transport.erl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 21ba34506a..5e8efa2af7 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -432,7 +432,7 @@ handle_kex_dh_gex_request(#ssh_msg_kex_dh_gex_request{min = Min0,
ssh_packet(#ssh_msg_kex_dh_gex_group{p = P, g = G}, Ssh0),
{ok, SshPacket,
Ssh#ssh{keyex_key = {{Private, Public}, {G, P}},
- keyex_info = {Min, Max, NBits}
+ keyex_info = {Min0, Max0, NBits}
}};
{error,_} ->
ssh_connection_handler:disconnect(
--
cgit v1.2.3
From 80a162cdf59f6a3826fba0cc0d3b861451a6b102 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 26 Jan 2017 22:48:13 +0100
Subject: ssh: optimize kex dh_gex using new crypto functionality
---
lib/ssh/src/ssh_connection_handler.erl | 6 +-
lib/ssh/src/ssh_transport.erl | 123 ++++++++++++++++++++++++++-------
2 files changed, 102 insertions(+), 27 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 8718e92fa2..4496c657c3 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -609,13 +609,15 @@ handle_event(_, #ssh_msg_kexdh_reply{} = Msg, {key_exchange,client,ReNeg}, D) ->
%%%---- diffie-hellman group exchange
handle_event(_, #ssh_msg_kex_dh_gex_request{} = Msg, {key_exchange,server,ReNeg}, D) ->
- {ok, GexGroup, Ssh} = ssh_transport:handle_kex_dh_gex_request(Msg, D#data.ssh_params),
+ {ok, GexGroup, Ssh1} = ssh_transport:handle_kex_dh_gex_request(Msg, D#data.ssh_params),
send_bytes(GexGroup, D),
+ Ssh = ssh_transport:parallell_gen_key(Ssh1),
{next_state, {key_exchange_dh_gex_init,server,ReNeg}, D#data{ssh_params=Ssh}};
handle_event(_, #ssh_msg_kex_dh_gex_request_old{} = Msg, {key_exchange,server,ReNeg}, D) ->
- {ok, GexGroup, Ssh} = ssh_transport:handle_kex_dh_gex_request(Msg, D#data.ssh_params),
+ {ok, GexGroup, Ssh1} = ssh_transport:handle_kex_dh_gex_request(Msg, D#data.ssh_params),
send_bytes(GexGroup, D),
+ Ssh = ssh_transport:parallell_gen_key(Ssh1),
{next_state, {key_exchange_dh_gex_init,server,ReNeg}, D#data{ssh_params=Ssh}};
handle_event(_, #ssh_msg_kex_dh_gex_group{} = Msg, {key_exchange,client,ReNeg}, D) ->
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 5e8efa2af7..a7cc4cd52c 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -44,6 +44,7 @@
handle_kexdh_reply/2,
handle_kex_ecdh_init/2,
handle_kex_ecdh_reply/2,
+ parallell_gen_key/1,
extract_public_key/1,
ssh_packet/2, pack/2,
sha/1, sign/3, verify/4]).
@@ -296,9 +297,6 @@ handle_kexinit_msg(#ssh_msg_kexinit{} = CounterPart, #ssh_msg_kexinit{} = Own,
end.
-%% TODO: diffie-hellman-group14-sha1 should also be supported.
-%% Maybe check more things ...
-
verify_algorithm(#alg{kex = undefined}) -> false;
verify_algorithm(#alg{hkey = undefined}) -> false;
verify_algorithm(#alg{send_mac = undefined}) -> false;
@@ -316,17 +314,29 @@ verify_algorithm(#alg{kex = Kex}) -> lists:member(Kex, supported_algorithms(kex)
key_exchange_first_msg(Kex, Ssh0) when Kex == 'diffie-hellman-group1-sha1' ;
Kex == 'diffie-hellman-group14-sha1' ->
{G, P} = dh_group(Kex),
- {Public, Private} = generate_key(dh, [P,G]),
+ Sz = dh_bits(Ssh0#ssh.algorithms),
+ {Public, Private} = generate_key(dh, [P,G,2*Sz]),
{SshPacket, Ssh1} = ssh_packet(#ssh_msg_kexdh_init{e = Public}, Ssh0),
{ok, SshPacket,
Ssh1#ssh{keyex_key = {{Private, Public}, {G, P}}}};
key_exchange_first_msg(Kex, Ssh0=#ssh{opts=Opts}) when Kex == 'diffie-hellman-group-exchange-sha1' ;
Kex == 'diffie-hellman-group-exchange-sha256' ->
- {Min,NBits,Max} =
+ {Min,NBits0,Max} =
proplists:get_value(dh_gex_limits, Opts, {?DEFAULT_DH_GROUP_MIN,
?DEFAULT_DH_GROUP_NBITS,
?DEFAULT_DH_GROUP_MAX}),
+ DhBits = dh_bits(Ssh0#ssh.algorithms),
+ NBits1 =
+ %% NIST Special Publication 800-57 Part 1 Revision 4: Recommendation for Key Management
+ if
+ DhBits =< 112 -> 2048;
+ DhBits =< 128 -> 3072;
+ DhBits =< 192 -> 7680;
+ true -> 8192
+ end,
+ NBits = min(max(max(NBits0,NBits1),Min), Max),
+
{SshPacket, Ssh1} =
ssh_packet(#ssh_msg_kex_dh_gex_request{min = Min,
n = NBits,
@@ -350,12 +360,13 @@ key_exchange_first_msg(Kex, Ssh0) when Kex == 'ecdh-sha2-nistp256' ;
%%% diffie-hellman-group14-sha1
%%%
handle_kexdh_init(#ssh_msg_kexdh_init{e = E},
- Ssh0 = #ssh{algorithms = #alg{kex=Kex}}) ->
+ Ssh0 = #ssh{algorithms = #alg{kex=Kex} = Algs}) ->
%% server
{G, P} = dh_group(Kex),
if
1=
- {Public, Private} = generate_key(dh, [P,G]),
+ Sz = dh_bits(Algs),
+ {Public, Private} = generate_key(dh, [P,G,2*Sz]),
K = compute_key(dh, E, Private, [P,G]),
MyPrivHostKey = get_host_key(Ssh0),
MyPubHostKey = extract_public_key(MyPrivHostKey),
@@ -426,12 +437,11 @@ handle_kex_dh_gex_request(#ssh_msg_kex_dh_gex_request{min = Min0,
{Min, Max} = adjust_gex_min_max(Min0, Max0, Opts),
case public_key:dh_gex_group(Min, NBits, Max,
proplists:get_value(dh_gex_groups,Opts)) of
- {ok, {_Sz, {G,P}}} ->
- {Public, Private} = generate_key(dh, [P,G]),
+ {ok, {_, {G,P}}} ->
{SshPacket, Ssh} =
ssh_packet(#ssh_msg_kex_dh_gex_group{p = P, g = G}, Ssh0),
{ok, SshPacket,
- Ssh#ssh{keyex_key = {{Private, Public}, {G, P}},
+ Ssh#ssh{keyex_key = {x, {G, P}},
keyex_info = {Min0, Max0, NBits}
}};
{error,_} ->
@@ -461,12 +471,11 @@ handle_kex_dh_gex_request(#ssh_msg_kex_dh_gex_request_old{n = NBits},
{Min, Max} = adjust_gex_min_max(Min0, Max0, Opts),
case public_key:dh_gex_group(Min, NBits, Max,
proplists:get_value(dh_gex_groups,Opts)) of
- {ok, {_Sz, {G,P}}} ->
- {Public, Private} = generate_key(dh, [P,G]),
+ {ok, {_, {G,P}}} ->
{SshPacket, Ssh} =
ssh_packet(#ssh_msg_kex_dh_gex_group{p = P, g = G}, Ssh0),
{ok, SshPacket,
- Ssh#ssh{keyex_key = {{Private, Public}, {G, P}},
+ Ssh#ssh{keyex_key = {x, {G, P}},
keyex_info = {-1, -1, NBits} % flag for kex_h hash calc
}};
{error,_} ->
@@ -507,7 +516,8 @@ adjust_gex_min_max(Min0, Max0, Opts) ->
handle_kex_dh_gex_group(#ssh_msg_kex_dh_gex_group{p = P, g = G}, Ssh0) ->
%% client
- {Public, Private} = generate_key(dh, [P,G]),
+ Sz = dh_bits(Ssh0#ssh.algorithms),
+ {Public, Private} = generate_key(dh, [P,G,2*Sz]),
{SshPacket, Ssh1} =
ssh_packet(#ssh_msg_kex_dh_gex_init{e = Public}, Ssh0), % Pub = G^Priv mod P (def)
@@ -1117,6 +1127,51 @@ verify(PlainText, Hash, Sig, Key) ->
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%% Unit: bytes
+
+-record(cipher_data, {
+ key_bytes,
+ iv_bytes,
+ block_bytes
+ }).
+
+%%% Start of a more parameterized crypto handling.
+cipher('AEAD_AES_128_GCM') ->
+ #cipher_data{key_bytes = 16,
+ iv_bytes = 12,
+ block_bytes = 16};
+
+cipher('AEAD_AES_256_GCM') ->
+ #cipher_data{key_bytes = 32,
+ iv_bytes = 12,
+ block_bytes = 16};
+
+cipher('3des-cbc') ->
+ #cipher_data{key_bytes = 24,
+ iv_bytes = 8,
+ block_bytes = 8};
+
+cipher('aes128-cbc') ->
+ #cipher_data{key_bytes = 16,
+ iv_bytes = 16,
+ block_bytes = 16};
+
+cipher('aes128-ctr') ->
+ #cipher_data{key_bytes = 16,
+ iv_bytes = 16,
+ block_bytes = 16};
+
+cipher('aes192-ctr') ->
+ #cipher_data{key_bytes = 24,
+ iv_bytes = 16,
+ block_bytes = 16};
+
+cipher('aes256-ctr') ->
+ #cipher_data{key_bytes = 32,
+ iv_bytes = 16,
+ block_bytes = 16}.
+
+
encrypt_init(#ssh{encrypt = none} = Ssh) ->
{ok, Ssh};
encrypt_init(#ssh{encrypt = 'AEAD_AES_128_GCM', role = client} = Ssh) ->
@@ -1497,11 +1552,11 @@ send_mac_init(SSH) ->
common ->
case SSH#ssh.role of
client ->
- KeySize = mac_key_size(SSH#ssh.send_mac),
+ KeySize = 8*mac_key_bytes(SSH#ssh.send_mac),
Key = hash(SSH, "E", KeySize),
{ok, SSH#ssh { send_mac_key = Key }};
server ->
- KeySize = mac_key_size(SSH#ssh.send_mac),
+ KeySize = 8*mac_key_bytes(SSH#ssh.send_mac),
Key = hash(SSH, "F", KeySize),
{ok, SSH#ssh { send_mac_key = Key }}
end;
@@ -1520,10 +1575,10 @@ recv_mac_init(SSH) ->
common ->
case SSH#ssh.role of
client ->
- Key = hash(SSH, "F", mac_key_size(SSH#ssh.recv_mac)),
+ Key = hash(SSH, "F", 8*mac_key_bytes(SSH#ssh.recv_mac)),
{ok, SSH#ssh { recv_mac_key = Key }};
server ->
- Key = hash(SSH, "E", mac_key_size(SSH#ssh.recv_mac)),
+ Key = hash(SSH, "E", 8*mac_key_bytes(SSH#ssh.recv_mac)),
{ok, SSH#ssh { recv_mac_key = Key }}
end;
aead ->
@@ -1640,13 +1695,15 @@ sha(?'secp384r1') -> sha(secp384r1);
sha(?'secp521r1') -> sha(secp521r1).
-mac_key_size('hmac-sha1') -> 20*8;
-mac_key_size('hmac-sha1-96') -> 20*8;
-mac_key_size('hmac-md5') -> 16*8;
-mac_key_size('hmac-md5-96') -> 16*8;
-mac_key_size('hmac-sha2-256')-> 32*8;
-mac_key_size('hmac-sha2-512')-> 512;
-mac_key_size(none) -> 0.
+mac_key_bytes('hmac-sha1') -> 20;
+mac_key_bytes('hmac-sha1-96') -> 20;
+mac_key_bytes('hmac-md5') -> 16;
+mac_key_bytes('hmac-md5-96') -> 16;
+mac_key_bytes('hmac-sha2-256')-> 32;
+mac_key_bytes('hmac-sha2-512')-> 64;
+mac_key_bytes('AEAD_AES_128_GCM') -> 0;
+mac_key_bytes('AEAD_AES_256_GCM') -> 0;
+mac_key_bytes(none) -> 0.
mac_digest_size('hmac-sha1') -> 20;
mac_digest_size('hmac-sha1-96') -> 12;
@@ -1671,6 +1728,13 @@ dh_group('diffie-hellman-group1-sha1') -> ?dh_group1;
dh_group('diffie-hellman-group14-sha1') -> ?dh_group14.
%%%----------------------------------------------------------------
+parallell_gen_key(Ssh = #ssh{keyex_key = {x, {G, P}},
+ algorithms = Algs}) ->
+ Sz = dh_bits(Algs),
+ {Public, Private} = generate_key(dh, [P,G,2*Sz]),
+ Ssh#ssh{keyex_key = {{Private, Public}, {G, P}}}.
+
+
generate_key(Algorithm, Args) ->
{Public,Private} = crypto:generate_key(Algorithm, Args),
{crypto:bytes_to_integer(Public), crypto:bytes_to_integer(Private)}.
@@ -1681,6 +1745,15 @@ compute_key(Algorithm, OthersPublic, MyPrivate, Args) ->
crypto:bytes_to_integer(Shared).
+dh_bits(#alg{encrypt = Encrypt,
+ send_mac = SendMac}) ->
+ C = cipher(Encrypt),
+ 8 * lists:max([C#cipher_data.key_bytes,
+ C#cipher_data.block_bytes,
+ C#cipher_data.iv_bytes,
+ mac_key_bytes(SendMac)
+ ]).
+
ecdh_curve('ecdh-sha2-nistp256') -> secp256r1;
ecdh_curve('ecdh-sha2-nistp384') -> secp384r1;
ecdh_curve('ecdh-sha2-nistp521') -> secp521r1.
--
cgit v1.2.3
From ebd654fb170c5ddfb8828e7a3d42814561d5f566 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 30 Jan 2017 14:44:06 +0100
Subject: ssh: increase timetrap for ssh_benchmark_SUITE
---
lib/ssh/test/ssh_benchmark_SUITE.erl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_benchmark_SUITE.erl b/lib/ssh/test/ssh_benchmark_SUITE.erl
index c2bfc48449..c5a6447839 100644
--- a/lib/ssh/test/ssh_benchmark_SUITE.erl
+++ b/lib/ssh/test/ssh_benchmark_SUITE.erl
@@ -30,7 +30,7 @@
suite() -> [{ct_hooks,[{ts_install_cth,[{nodenames,2}]}]},
- {timetrap,{minutes,3}}
+ {timetrap,{minutes,6}}
].
%%suite() -> [{ct_hooks,[ts_install_cth]}].
--
cgit v1.2.3
From 61501c3d0fa0744b107576070eaf3062ae23ac82 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 18 Jan 2017 19:49:57 +0100
Subject: ssh: reordered default algorithms list
---
lib/ssh/src/ssh_transport.erl | 22 ++++++++++++----------
1 file changed, 12 insertions(+), 10 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 4012ae3914..73e5952972 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -95,19 +95,20 @@ supported_algorithms() -> [{K,supported_algorithms(K)} || K <- algo_classes()].
supported_algorithms(kex) ->
select_crypto_supported(
[
- {'ecdh-sha2-nistp256', [{public_keys,ecdh}, {ec_curve,secp256r1}, {hashs,sha256}]},
{'ecdh-sha2-nistp384', [{public_keys,ecdh}, {ec_curve,secp384r1}, {hashs,sha384}]},
- {'diffie-hellman-group14-sha1', [{public_keys,dh}, {hashs,sha}]},
+ {'ecdh-sha2-nistp521', [{public_keys,ecdh}, {ec_curve,secp521r1}, {hashs,sha512}]},
+ {'ecdh-sha2-nistp256', [{public_keys,ecdh}, {ec_curve,secp256r1}, {hashs,sha256}]},
{'diffie-hellman-group-exchange-sha256', [{public_keys,dh}, {hashs,sha256}]},
{'diffie-hellman-group-exchange-sha1', [{public_keys,dh}, {hashs,sha}]},
- {'ecdh-sha2-nistp521', [{public_keys,ecdh}, {ec_curve,secp521r1}, {hashs,sha512}]},
+ {'diffie-hellman-group14-sha1', [{public_keys,dh}, {hashs,sha}]},
{'diffie-hellman-group1-sha1', [{public_keys,dh}, {hashs,sha}]}
]);
supported_algorithms(public_key) ->
select_crypto_supported(
- [{'ecdsa-sha2-nistp256', [{public_keys,ecdsa}, {hashs,sha256}, {ec_curve,secp256r1}]},
+ [
{'ecdsa-sha2-nistp384', [{public_keys,ecdsa}, {hashs,sha384}, {ec_curve,secp384r1}]},
{'ecdsa-sha2-nistp521', [{public_keys,ecdsa}, {hashs,sha512}, {ec_curve,secp521r1}]},
+ {'ecdsa-sha2-nistp256', [{public_keys,ecdsa}, {hashs,sha256}, {ec_curve,secp256r1}]},
{'ssh-rsa', [{public_keys,rsa}, {hashs,sha} ]},
{'ssh-dss', [{public_keys,dss}, {hashs,sha} ]}
]);
@@ -115,14 +116,15 @@ supported_algorithms(public_key) ->
supported_algorithms(cipher) ->
same(
select_crypto_supported(
- [{'aes256-ctr', [{ciphers,{aes_ctr,256}}]},
- {'aes192-ctr', [{ciphers,{aes_ctr,192}}]},
- {'aes128-ctr', [{ciphers,{aes_ctr,128}}]},
- {'aes128-cbc', [{ciphers,aes_cbc128}]},
+ [
+ {'aes256-gcm@openssh.com', [{ciphers,{aes_gcm,256}}]},
+ {'aes256-ctr', [{ciphers,{aes_ctr,256}}]},
+ {'aes192-ctr', [{ciphers,{aes_ctr,192}}]},
{'aes128-gcm@openssh.com', [{ciphers,{aes_gcm,128}}]},
- {'aes256-gcm@openssh.com', [{ciphers,{aes_gcm,256}}]},
- {'AEAD_AES_128_GCM', [{ciphers,{aes_gcm,128}}]},
+ {'aes128-ctr', [{ciphers,{aes_ctr,128}}]},
{'AEAD_AES_256_GCM', [{ciphers,{aes_gcm,256}}]},
+ {'AEAD_AES_128_GCM', [{ciphers,{aes_gcm,128}}]},
+ {'aes128-cbc', [{ciphers,aes_cbc128}]},
{'3des-cbc', [{ciphers,des3_cbc}]}
]
));
--
cgit v1.2.3
From ef2aa76fbd0867a2901148edfedbcc8f1bf51809 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 18 Jan 2017 20:34:27 +0100
Subject: ssh: added stronger diffie-hellman groups
diffie-hellman-group16-sha512
diffie-hellman-group18-sha512
diffie-hellman-group14-sha256
---
lib/ssh/src/ssh_transport.erl | 32 +++++++++++++++++++++++++++-----
lib/ssh/src/ssh_transport.hrl | 13 ++++++++++++-
2 files changed, 39 insertions(+), 6 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 73e5952972..693691f835 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -99,9 +99,12 @@ supported_algorithms(kex) ->
{'ecdh-sha2-nistp521', [{public_keys,ecdh}, {ec_curve,secp521r1}, {hashs,sha512}]},
{'ecdh-sha2-nistp256', [{public_keys,ecdh}, {ec_curve,secp256r1}, {hashs,sha256}]},
{'diffie-hellman-group-exchange-sha256', [{public_keys,dh}, {hashs,sha256}]},
- {'diffie-hellman-group-exchange-sha1', [{public_keys,dh}, {hashs,sha}]},
+ {'diffie-hellman-group16-sha512', [{public_keys,dh}, {hashs,sha512}]}, % In OpenSSH 7.3.p1
+ {'diffie-hellman-group18-sha512', [{public_keys,dh}, {hashs,sha512}]}, % In OpenSSH 7.3.p1
+ {'diffie-hellman-group14-sha256', [{public_keys,dh}, {hashs,sha256}]}, % In OpenSSH 7.3.p1
{'diffie-hellman-group14-sha1', [{public_keys,dh}, {hashs,sha}]},
- {'diffie-hellman-group1-sha1', [{public_keys,dh}, {hashs,sha}]}
+ {'diffie-hellman-group-exchange-sha1', [{public_keys,dh}, {hashs,sha}]},
+ {'diffie-hellman-group1-sha1', [{public_keys,dh}, {hashs,sha}]} % Gone in OpenSSH 7.3.p1
]);
supported_algorithms(public_key) ->
select_crypto_supported(
@@ -110,7 +113,7 @@ supported_algorithms(public_key) ->
{'ecdsa-sha2-nistp521', [{public_keys,ecdsa}, {hashs,sha512}, {ec_curve,secp521r1}]},
{'ecdsa-sha2-nistp256', [{public_keys,ecdsa}, {hashs,sha256}, {ec_curve,secp256r1}]},
{'ssh-rsa', [{public_keys,rsa}, {hashs,sha} ]},
- {'ssh-dss', [{public_keys,dss}, {hashs,sha} ]}
+ {'ssh-dss', [{public_keys,dss}, {hashs,sha} ]} % Gone in OpenSSH 7.3.p1
]);
supported_algorithms(cipher) ->
@@ -314,7 +317,11 @@ verify_algorithm(#alg{kex = Kex}) -> lists:member(Kex, supported_algorithms(kex)
%%% Key exchange initialization
%%%
key_exchange_first_msg(Kex, Ssh0) when Kex == 'diffie-hellman-group1-sha1' ;
- Kex == 'diffie-hellman-group14-sha1' ->
+ Kex == 'diffie-hellman-group14-sha1' ;
+ Kex == 'diffie-hellman-group14-sha256' ;
+ Kex == 'diffie-hellman-group16-sha512' ;
+ Kex == 'diffie-hellman-group18-sha512'
+ ->
{G, P} = dh_group(Kex),
Sz = dh_bits(Ssh0#ssh.algorithms),
{Public, Private} = generate_key(dh, [P,G,2*Sz]),
@@ -360,6 +367,9 @@ key_exchange_first_msg(Kex, Ssh0) when Kex == 'ecdh-sha2-nistp256' ;
%%%
%%% diffie-hellman-group1-sha1
%%% diffie-hellman-group14-sha1
+%%% diffie-hellman-group14-sha256
+%%% diffie-hellman-group16-sha512
+%%% diffie-hellman-group18-sha512
%%%
handle_kexdh_init(#ssh_msg_kexdh_init{e = E},
Ssh0 = #ssh{algorithms = #alg{kex=Kex} = Algs}) ->
@@ -1614,6 +1624,12 @@ hash(SSH, Char, Bits) ->
fun(Data) -> crypto:hash(sha, Data) end;
'diffie-hellman-group14-sha1' ->
fun(Data) -> crypto:hash(sha, Data) end;
+ 'diffie-hellman-group14-sha256' ->
+ fun(Data) -> crypto:hash(sha256, Data) end;
+ 'diffie-hellman-group16-sha512' ->
+ fun(Data) -> crypto:hash(sha512, Data) end;
+ 'diffie-hellman-group18-sha512' ->
+ fun(Data) -> crypto:hash(sha512, Data) end;
'diffie-hellman-group-exchange-sha1' ->
fun(Data) -> crypto:hash(sha, Data) end;
@@ -1690,6 +1706,9 @@ sha(secp384r1) -> sha384;
sha(secp521r1) -> sha512;
sha('diffie-hellman-group1-sha1') -> sha;
sha('diffie-hellman-group14-sha1') -> sha;
+sha('diffie-hellman-group14-sha256') -> sha256;
+sha('diffie-hellman-group16-sha512') -> sha512;
+sha('diffie-hellman-group18-sha512') -> sha512;
sha('diffie-hellman-group-exchange-sha1') -> sha;
sha('diffie-hellman-group-exchange-sha256') -> sha256;
sha(?'secp256r1') -> sha(secp256r1);
@@ -1727,7 +1746,10 @@ peer_name({Host, _}) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
dh_group('diffie-hellman-group1-sha1') -> ?dh_group1;
-dh_group('diffie-hellman-group14-sha1') -> ?dh_group14.
+dh_group('diffie-hellman-group14-sha1') -> ?dh_group14;
+dh_group('diffie-hellman-group14-sha256') -> ?dh_group14;
+dh_group('diffie-hellman-group16-sha512') -> ?dh_group16;
+dh_group('diffie-hellman-group18-sha512') -> ?dh_group18.
%%%----------------------------------------------------------------
parallell_gen_key(Ssh = #ssh{keyex_key = {x, {G, P}},
diff --git a/lib/ssh/src/ssh_transport.hrl b/lib/ssh/src/ssh_transport.hrl
index f91cb1dd63..19b3f5c437 100644
--- a/lib/ssh/src/ssh_transport.hrl
+++ b/lib/ssh/src/ssh_transport.hrl
@@ -112,7 +112,7 @@
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% diffie-hellman-group1-sha1 | diffie-hellman-group14-sha1
+%% diffie-hellman-group*-sha*
-define(SSH_MSG_KEXDH_INIT, 30).
-define(SSH_MSG_KEXDH_REPLY, 31).
@@ -238,4 +238,15 @@
-define(dh_group14,
{2, 16#FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF}).
+%%% rfc 3526, ch5
+%%% Size 4096-bit
+-define(dh_group16,
+ {2, 16#FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF}).
+
+%%% rfc 3526, ch7
+%%% Size 8192-bit
+-define(dh_group18,
+ {2, 16#FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AACC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E438777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F5683423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD922222E04A4037C0713EB57A81A23F0C73473FC646CEA306B4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC50846851DF9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F924009438B481C6CD7889A002ED5EE382BC9190DA6FC026E479558E4475677E9AA9E3050E2765694DFC81F56E880B96E7160C980DD98EDD3DFFFFFFFFFFFFFFFFF}).
+
+
-endif. % -ifdef(ssh_transport).
--
cgit v1.2.3
From d08006aaec92873c8cca6b7aeb57dcd2786fa330 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 18 Jan 2017 20:44:31 +0100
Subject: ssh: removed 'diffie-hellman-group1-sha1' from default list
Reason: very insecure
---
lib/ssh/src/ssh_transport.erl | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 693691f835..d172005a85 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -79,6 +79,10 @@ default_algorithms() -> [{K,default_algorithms(K)} || K <- algo_classes()].
algo_classes() -> [kex, public_key, cipher, mac, compression].
+default_algorithms(kex) ->
+ supported_algorithms(kex, [
+ 'diffie-hellman-group1-sha1' % Gone in OpenSSH 7.3.p1
+ ]);
default_algorithms(cipher) ->
supported_algorithms(cipher, same(['AEAD_AES_128_GCM',
@@ -104,7 +108,7 @@ supported_algorithms(kex) ->
{'diffie-hellman-group14-sha256', [{public_keys,dh}, {hashs,sha256}]}, % In OpenSSH 7.3.p1
{'diffie-hellman-group14-sha1', [{public_keys,dh}, {hashs,sha}]},
{'diffie-hellman-group-exchange-sha1', [{public_keys,dh}, {hashs,sha}]},
- {'diffie-hellman-group1-sha1', [{public_keys,dh}, {hashs,sha}]} % Gone in OpenSSH 7.3.p1
+ {'diffie-hellman-group1-sha1', [{public_keys,dh}, {hashs,sha}]}
]);
supported_algorithms(public_key) ->
select_crypto_supported(
--
cgit v1.2.3
From 6847d9223420fb86cdf72f0e608a5f41a2673053 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 19 Jan 2017 17:19:37 +0100
Subject: ssh: removed 'ssh-dss' from default list
Reason: insecure
---
lib/ssh/src/ssh_transport.erl | 5 +++++
1 file changed, 5 insertions(+)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index d172005a85..7a01f9926c 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -84,6 +84,11 @@ default_algorithms(kex) ->
'diffie-hellman-group1-sha1' % Gone in OpenSSH 7.3.p1
]);
+default_algorithms(public_key) ->
+ supported_algorithms(public_key, [
+ 'ssh-dss' % Gone in OpenSSH 7.3.p1
+ ]);
+
default_algorithms(cipher) ->
supported_algorithms(cipher, same(['AEAD_AES_128_GCM',
'AEAD_AES_256_GCM']));
--
cgit v1.2.3
From d89206ccb3df4fc4fff4549f561085611febb22a Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 19 Jan 2017 10:50:01 +0100
Subject: ssh: better error msg at kex failure
---
lib/ssh/src/ssh_transport.erl | 32 +++++++++++++++++++-------------
lib/ssh/test/ssh_basic_SUITE.erl | 2 +-
2 files changed, 20 insertions(+), 14 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 7a01f9926c..b43bcff363 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -289,11 +289,12 @@ handle_kexinit_msg(#ssh_msg_kexinit{} = CounterPart, #ssh_msg_kexinit{} = Own,
true ->
key_exchange_first_msg(Algoritms#alg.kex,
Ssh0#ssh{algorithms = Algoritms});
- _ ->
+ {false,Alg} ->
%% TODO: Correct code?
ssh_connection_handler:disconnect(
#ssh_msg_disconnect{code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
- description = "Selection of key exchange algorithm failed"
+ description = "Selection of key exchange algorithm failed: "
+ ++ Alg
})
end;
@@ -303,23 +304,28 @@ handle_kexinit_msg(#ssh_msg_kexinit{} = CounterPart, #ssh_msg_kexinit{} = Own,
case verify_algorithm(Algoritms) of
true ->
{ok, Ssh#ssh{algorithms = Algoritms}};
- _ ->
+ {false,Alg} ->
ssh_connection_handler:disconnect(
#ssh_msg_disconnect{code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
- description = "Selection of key exchange algorithm failed"
+ description = "Selection of key exchange algorithm failed: "
+ ++ Alg
})
end.
-verify_algorithm(#alg{kex = undefined}) -> false;
-verify_algorithm(#alg{hkey = undefined}) -> false;
-verify_algorithm(#alg{send_mac = undefined}) -> false;
-verify_algorithm(#alg{recv_mac = undefined}) -> false;
-verify_algorithm(#alg{encrypt = undefined}) -> false;
-verify_algorithm(#alg{decrypt = undefined}) -> false;
-verify_algorithm(#alg{compress = undefined}) -> false;
-verify_algorithm(#alg{decompress = undefined}) -> false;
-verify_algorithm(#alg{kex = Kex}) -> lists:member(Kex, supported_algorithms(kex)).
+verify_algorithm(#alg{kex = undefined}) -> {false, "kex"};
+verify_algorithm(#alg{hkey = undefined}) -> {false, "hkey"};
+verify_algorithm(#alg{send_mac = undefined}) -> {false, "send_mac"};
+verify_algorithm(#alg{recv_mac = undefined}) -> {false, "recv_mac"};
+verify_algorithm(#alg{encrypt = undefined}) -> {false, "encrypt"};
+verify_algorithm(#alg{decrypt = undefined}) -> {false, "decrypt"};
+verify_algorithm(#alg{compress = undefined}) -> {false, "compress"};
+verify_algorithm(#alg{decompress = undefined}) -> {false, "decompress"};
+verify_algorithm(#alg{kex = Kex}) ->
+ case lists:member(Kex, supported_algorithms(kex)) of
+ true -> true;
+ false -> {false, "kex"}
+ end.
%%%----------------------------------------------------------------
%%%
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index 0a0ab5cdf7..fb3342ac32 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -1206,7 +1206,7 @@ check_error("Invalid state") ->
ok;
check_error("Connection closed") ->
ok;
-check_error("Selection of key exchange algorithm failed") ->
+check_error("Selection of key exchange algorithm failed"++_) ->
ok;
check_error(Error) ->
ct:fail(Error).
--
cgit v1.2.3
From 497fc8de10bfee9eb693d393c270d8e06dbd15be Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 30 Jan 2017 13:12:06 +0100
Subject: ssh,crypto: prepare for release
---
lib/ssh/src/ssh.app.src | 2 +-
lib/ssh/vsn.mk | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh.app.src b/lib/ssh/src/ssh.app.src
index 4a76fd9cd3..cb0f087cfb 100644
--- a/lib/ssh/src/ssh.app.src
+++ b/lib/ssh/src/ssh.app.src
@@ -40,6 +40,6 @@
{env, []},
{mod, {ssh_app, []}},
{runtime_dependencies, ["stdlib-2.3","public_key-0.22","kernel-3.0",
- "erts-6.0","crypto-3.3"]}]}.
+ "erts-6.0","crypto-3.6.3.1"]}]}.
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index c62faf8357..bfe2fcbc0b 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,5 +1,5 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 4.2.2.2
+SSH_VSN = 4.2.2.3
APP_VSN = "ssh-$(SSH_VSN)"
--
cgit v1.2.3
From 62f9bd09023da0b318e57b6454bd4b346816a27b Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 26 Jan 2017 22:48:13 +0100
Subject: ssh: optimize kex dh_gex using new crypto functionality
Conflicts:
lib/ssh/src/ssh_connection_handler.erl
lib/ssh/src/ssh_transport.erl
---
lib/ssh/src/ssh_connection_handler.erl | 6 +-
lib/ssh/src/ssh_transport.erl | 125 ++++++++++++++++++++++++++-------
2 files changed, 103 insertions(+), 28 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index b73f8b23d2..8c73bb8946 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -429,14 +429,16 @@ key_exchange(#ssh_msg_kexdh_reply{} = Msg,
key_exchange(#ssh_msg_kex_dh_gex_request{} = Msg,
#state{ssh_params = #ssh{role = server} = Ssh0} = State) ->
- {ok, GexGroup, Ssh} = ssh_transport:handle_kex_dh_gex_request(Msg, Ssh0),
+ {ok, GexGroup, Ssh1} = ssh_transport:handle_kex_dh_gex_request(Msg, Ssh0),
send_msg(GexGroup, State),
+ Ssh = ssh_transport:parallell_gen_key(Ssh1),
{next_state, key_exchange_dh_gex_init, next_packet(State#state{ssh_params = Ssh})};
key_exchange(#ssh_msg_kex_dh_gex_request_old{} = Msg,
#state{ssh_params = #ssh{role = server} = Ssh0} = State) ->
- {ok, GexGroup, Ssh} = ssh_transport:handle_kex_dh_gex_request(Msg, Ssh0),
+ {ok, GexGroup, Ssh1} = ssh_transport:handle_kex_dh_gex_request(Msg, Ssh0),
send_msg(GexGroup, State),
+ Ssh = ssh_transport:parallell_gen_key(Ssh1),
{next_state, key_exchange_dh_gex_init, next_packet(State#state{ssh_params = Ssh})};
key_exchange(#ssh_msg_kex_dh_gex_group{} = Msg,
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 18037b8461..5391df723c 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -44,6 +44,7 @@
handle_kexdh_reply/2,
handle_kex_ecdh_init/2,
handle_kex_ecdh_reply/2,
+ parallell_gen_key/1,
extract_public_key/1,
ssh_packet/2, pack/2,
sign/3, verify/4]).
@@ -287,9 +288,6 @@ handle_kexinit_msg(#ssh_msg_kexinit{} = CounterPart, #ssh_msg_kexinit{} = Own,
end.
-%% TODO: diffie-hellman-group14-sha1 should also be supported.
-%% Maybe check more things ...
-
verify_algorithm(#alg{kex = undefined}) -> false;
verify_algorithm(#alg{hkey = undefined}) -> false;
verify_algorithm(#alg{send_mac = undefined}) -> false;
@@ -307,17 +305,29 @@ verify_algorithm(#alg{kex = Kex}) -> lists:member(Kex, supported_algorithms(kex)
key_exchange_first_msg(Kex, Ssh0) when Kex == 'diffie-hellman-group1-sha1' ;
Kex == 'diffie-hellman-group14-sha1' ->
{G, P} = dh_group(Kex),
- {Public, Private} = generate_key(dh, [P,G]),
+ Sz = dh_bits(Ssh0#ssh.algorithms),
+ {Public, Private} = generate_key(dh, [P,G,2*Sz]),
{SshPacket, Ssh1} = ssh_packet(#ssh_msg_kexdh_init{e = Public}, Ssh0),
{ok, SshPacket,
Ssh1#ssh{keyex_key = {{Private, Public}, {G, P}}}};
key_exchange_first_msg(Kex, Ssh0=#ssh{opts=Opts}) when Kex == 'diffie-hellman-group-exchange-sha1' ;
Kex == 'diffie-hellman-group-exchange-sha256' ->
- {Min,NBits,Max} =
+ {Min,NBits0,Max} =
proplists:get_value(dh_gex_limits, Opts, {?DEFAULT_DH_GROUP_MIN,
?DEFAULT_DH_GROUP_NBITS,
?DEFAULT_DH_GROUP_MAX}),
+ DhBits = dh_bits(Ssh0#ssh.algorithms),
+ NBits1 =
+ %% NIST Special Publication 800-57 Part 1 Revision 4: Recommendation for Key Management
+ if
+ DhBits =< 112 -> 2048;
+ DhBits =< 128 -> 3072;
+ DhBits =< 192 -> 7680;
+ true -> 8192
+ end,
+ NBits = min(max(max(NBits0,NBits1),Min), Max),
+
{SshPacket, Ssh1} =
ssh_packet(#ssh_msg_kex_dh_gex_request{min = Min,
n = NBits,
@@ -341,12 +351,13 @@ key_exchange_first_msg(Kex, Ssh0) when Kex == 'ecdh-sha2-nistp256' ;
%%% diffie-hellman-group14-sha1
%%%
handle_kexdh_init(#ssh_msg_kexdh_init{e = E},
- Ssh0 = #ssh{algorithms = #alg{kex=Kex}}) ->
+ Ssh0 = #ssh{algorithms = #alg{kex=Kex} = Algs}) ->
%% server
{G, P} = dh_group(Kex),
if
1=
- {Public, Private} = generate_key(dh, [P,G]),
+ Sz = dh_bits(Algs),
+ {Public, Private} = generate_key(dh, [P,G,2*Sz]),
K = compute_key(dh, E, Private, [P,G]),
MyPrivHostKey = get_host_key(Ssh0),
MyPubHostKey = extract_public_key(MyPrivHostKey),
@@ -418,13 +429,12 @@ handle_kex_dh_gex_request(#ssh_msg_kex_dh_gex_request{min = Min0,
{Min, Max} = adjust_gex_min_max(Min0, Max0, Opts),
case public_key:dh_gex_group(Min, NBits, Max,
proplists:get_value(dh_gex_groups,Opts)) of
- {ok, {_Sz, {G,P}}} ->
- {Public, Private} = generate_key(dh, [P,G]),
+ {ok, {_, {G,P}}} ->
{SshPacket, Ssh} =
ssh_packet(#ssh_msg_kex_dh_gex_group{p = P, g = G}, Ssh0),
{ok, SshPacket,
- Ssh#ssh{keyex_key = {{Private, Public}, {G, P}},
- keyex_info = {Min, Max, NBits}
+ Ssh#ssh{keyex_key = {x, {G, P}},
+ keyex_info = {Min0, Max0, NBits}
}};
{error,_} ->
throw(#ssh_msg_disconnect{
@@ -452,12 +462,11 @@ handle_kex_dh_gex_request(#ssh_msg_kex_dh_gex_request_old{n = NBits},
{Min, Max} = adjust_gex_min_max(Min0, Max0, Opts),
case public_key:dh_gex_group(Min, NBits, Max,
proplists:get_value(dh_gex_groups,Opts)) of
- {ok, {_Sz, {G,P}}} ->
- {Public, Private} = generate_key(dh, [P,G]),
+ {ok, {_, {G,P}}} ->
{SshPacket, Ssh} =
ssh_packet(#ssh_msg_kex_dh_gex_group{p = P, g = G}, Ssh0),
{ok, SshPacket,
- Ssh#ssh{keyex_key = {{Private, Public}, {G, P}},
+ Ssh#ssh{keyex_key = {x, {G, P}},
keyex_info = {-1, -1, NBits} % flag for kex_h hash calc
}};
{error,_} ->
@@ -497,7 +506,8 @@ adjust_gex_min_max(Min0, Max0, Opts) ->
handle_kex_dh_gex_group(#ssh_msg_kex_dh_gex_group{p = P, g = G}, Ssh0) ->
%% client
- {Public, Private} = generate_key(dh, [P,G]),
+ Sz = dh_bits(Ssh0#ssh.algorithms),
+ {Public, Private} = generate_key(dh, [P,G,2*Sz]),
{SshPacket, Ssh1} =
ssh_packet(#ssh_msg_kex_dh_gex_init{e = Public}, Ssh0), % Pub = G^Priv mod P (def)
@@ -1108,6 +1118,51 @@ verify(PlainText, Hash, Sig, Key) ->
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%% Unit: bytes
+
+-record(cipher_data, {
+ key_bytes,
+ iv_bytes,
+ block_bytes
+ }).
+
+%%% Start of a more parameterized crypto handling.
+cipher('AEAD_AES_128_GCM') ->
+ #cipher_data{key_bytes = 16,
+ iv_bytes = 12,
+ block_bytes = 16};
+
+cipher('AEAD_AES_256_GCM') ->
+ #cipher_data{key_bytes = 32,
+ iv_bytes = 12,
+ block_bytes = 16};
+
+cipher('3des-cbc') ->
+ #cipher_data{key_bytes = 24,
+ iv_bytes = 8,
+ block_bytes = 8};
+
+cipher('aes128-cbc') ->
+ #cipher_data{key_bytes = 16,
+ iv_bytes = 16,
+ block_bytes = 16};
+
+cipher('aes128-ctr') ->
+ #cipher_data{key_bytes = 16,
+ iv_bytes = 16,
+ block_bytes = 16};
+
+cipher('aes192-ctr') ->
+ #cipher_data{key_bytes = 24,
+ iv_bytes = 16,
+ block_bytes = 16};
+
+cipher('aes256-ctr') ->
+ #cipher_data{key_bytes = 32,
+ iv_bytes = 16,
+ block_bytes = 16}.
+
+
encrypt_init(#ssh{encrypt = none} = Ssh) ->
{ok, Ssh};
encrypt_init(#ssh{encrypt = 'AEAD_AES_128_GCM', role = client} = Ssh) ->
@@ -1488,11 +1543,11 @@ send_mac_init(SSH) ->
common ->
case SSH#ssh.role of
client ->
- KeySize = mac_key_size(SSH#ssh.send_mac),
+ KeySize = 8*mac_key_bytes(SSH#ssh.send_mac),
Key = hash(SSH, "E", KeySize),
{ok, SSH#ssh { send_mac_key = Key }};
server ->
- KeySize = mac_key_size(SSH#ssh.send_mac),
+ KeySize = 8*mac_key_bytes(SSH#ssh.send_mac),
Key = hash(SSH, "F", KeySize),
{ok, SSH#ssh { send_mac_key = Key }}
end;
@@ -1511,10 +1566,10 @@ recv_mac_init(SSH) ->
common ->
case SSH#ssh.role of
client ->
- Key = hash(SSH, "F", mac_key_size(SSH#ssh.recv_mac)),
+ Key = hash(SSH, "F", 8*mac_key_bytes(SSH#ssh.recv_mac)),
{ok, SSH#ssh { recv_mac_key = Key }};
server ->
- Key = hash(SSH, "E", mac_key_size(SSH#ssh.recv_mac)),
+ Key = hash(SSH, "E", 8*mac_key_bytes(SSH#ssh.recv_mac)),
{ok, SSH#ssh { recv_mac_key = Key }}
end;
aead ->
@@ -1638,13 +1693,15 @@ sha(?'secp384r1') -> sha(secp384r1);
sha(?'secp521r1') -> sha(secp521r1).
-mac_key_size('hmac-sha1') -> 20*8;
-mac_key_size('hmac-sha1-96') -> 20*8;
-mac_key_size('hmac-md5') -> 16*8;
-mac_key_size('hmac-md5-96') -> 16*8;
-mac_key_size('hmac-sha2-256')-> 32*8;
-mac_key_size('hmac-sha2-512')-> 512;
-mac_key_size(none) -> 0.
+mac_key_bytes('hmac-sha1') -> 20;
+mac_key_bytes('hmac-sha1-96') -> 20;
+mac_key_bytes('hmac-md5') -> 16;
+mac_key_bytes('hmac-md5-96') -> 16;
+mac_key_bytes('hmac-sha2-256')-> 32;
+mac_key_bytes('hmac-sha2-512')-> 64;
+mac_key_bytes('AEAD_AES_128_GCM') -> 0;
+mac_key_bytes('AEAD_AES_256_GCM') -> 0;
+mac_key_bytes(none) -> 0.
mac_digest_size('hmac-sha1') -> 20;
mac_digest_size('hmac-sha1-96') -> 12;
@@ -1669,6 +1726,13 @@ dh_group('diffie-hellman-group1-sha1') -> ?dh_group1;
dh_group('diffie-hellman-group14-sha1') -> ?dh_group14.
%%%----------------------------------------------------------------
+parallell_gen_key(Ssh = #ssh{keyex_key = {x, {G, P}},
+ algorithms = Algs}) ->
+ Sz = dh_bits(Algs),
+ {Public, Private} = generate_key(dh, [P,G,2*Sz]),
+ Ssh#ssh{keyex_key = {{Private, Public}, {G, P}}}.
+
+
generate_key(Algorithm, Args) ->
{Public,Private} = crypto:generate_key(Algorithm, Args),
{crypto:bytes_to_integer(Public), crypto:bytes_to_integer(Private)}.
@@ -1679,6 +1743,15 @@ compute_key(Algorithm, OthersPublic, MyPrivate, Args) ->
crypto:bytes_to_integer(Shared).
+dh_bits(#alg{encrypt = Encrypt,
+ send_mac = SendMac}) ->
+ C = cipher(Encrypt),
+ 8 * lists:max([C#cipher_data.key_bytes,
+ C#cipher_data.block_bytes,
+ C#cipher_data.iv_bytes,
+ mac_key_bytes(SendMac)
+ ]).
+
ecdh_curve('ecdh-sha2-nistp256') -> secp256r1;
ecdh_curve('ecdh-sha2-nistp384') -> secp384r1;
ecdh_curve('ecdh-sha2-nistp521') -> secp521r1.
--
cgit v1.2.3
From c18032539bcaf172416c55b415a4aba449365f7d Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 1 Feb 2017 12:15:55 +0100
Subject: ssh: remove test timetrap for ssh_kex_group_exchange This kex
algorithm is now optimized so a long timetrap is not needed
---
lib/ssh/test/ssh_algorithms_SUITE.erl | 2 --
1 file changed, 2 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_algorithms_SUITE.erl b/lib/ssh/test/ssh_algorithms_SUITE.erl
index 14605ee44f..4327068b7b 100644
--- a/lib/ssh/test/ssh_algorithms_SUITE.erl
+++ b/lib/ssh/test/ssh_algorithms_SUITE.erl
@@ -198,8 +198,6 @@ try_exec_simple_group(Group, Config) ->
%%--------------------------------------------------------------------
%% Testing all default groups
-simple_exec_groups() -> [{timetrap,{minutes,8}}].
-
simple_exec_groups(Config) ->
Sizes = interpolate( public_key:dh_gex_group_sizes() ),
lists:foreach(
--
cgit v1.2.3
From 666f78baa02345058e71021b1560c42c5bb1aff5 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 19 Jan 2017 15:10:58 +0100
Subject: ssh: update tests for removed algorithms
---
lib/ssh/test/ssh_basic_SUITE.erl | 74 +++++++++++++++-------
lib/ssh/test/ssh_key_cb.erl | 4 +-
lib/ssh/test/ssh_key_cb_options.erl | 2 +-
lib/ssh/test/ssh_options_SUITE.erl | 1 +
lib/ssh/test/ssh_protocol_SUITE.erl | 45 ++++++++++---
lib/ssh/test/ssh_sftp_SUITE_data/ssh_host_rsa_key | 16 +++++
.../test/ssh_sftp_SUITE_data/ssh_host_rsa_key.pub | 5 ++
lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl | 2 +
lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/id_rsa | 15 +++++
.../ssh_host_rsa_key | 16 +++++
.../ssh_host_rsa_key.pub | 5 ++
lib/ssh/test/ssh_trpt_test_lib.erl | 5 +-
12 files changed, 154 insertions(+), 36 deletions(-)
create mode 100644 lib/ssh/test/ssh_sftp_SUITE_data/ssh_host_rsa_key
create mode 100644 lib/ssh/test/ssh_sftp_SUITE_data/ssh_host_rsa_key.pub
create mode 100644 lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/id_rsa
create mode 100644 lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_rsa_key
create mode 100644 lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_rsa_key.pub
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index fb3342ac32..cdf6cf9ae1 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -152,15 +152,27 @@ end_per_suite(_Config) ->
%%--------------------------------------------------------------------
init_per_group(dsa_key, Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- PrivDir = proplists:get_value(priv_dir, Config),
- ssh_test_lib:setup_dsa(DataDir, PrivDir),
- Config;
+ case lists:member('ssh-dss',
+ ssh_transport:default_algorithms(public_key)) of
+ true ->
+ DataDir = proplists:get_value(data_dir, Config),
+ PrivDir = proplists:get_value(priv_dir, Config),
+ ssh_test_lib:setup_dsa(DataDir, PrivDir),
+ Config;
+ false ->
+ {skip, unsupported_pub_key}
+ end;
init_per_group(rsa_key, Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- PrivDir = proplists:get_value(priv_dir, Config),
- ssh_test_lib:setup_rsa(DataDir, PrivDir),
- Config;
+ case lists:member('ssh-rsa',
+ ssh_transport:default_algorithms(public_key)) of
+ true ->
+ DataDir = proplists:get_value(data_dir, Config),
+ PrivDir = proplists:get_value(priv_dir, Config),
+ ssh_test_lib:setup_rsa(DataDir, PrivDir),
+ Config;
+ false ->
+ {skip, unsupported_pub_key}
+ end;
init_per_group(ecdsa_sha2_nistp256_key, Config) ->
case lists:member('ecdsa-sha2-nistp256',
ssh_transport:default_algorithms(public_key)) of
@@ -195,15 +207,27 @@ init_per_group(ecdsa_sha2_nistp521_key, Config) ->
{skip, unsupported_pub_key}
end;
init_per_group(rsa_pass_key, Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- PrivDir = proplists:get_value(priv_dir, Config),
- ssh_test_lib:setup_rsa_pass_pharse(DataDir, PrivDir, "Password"),
- [{pass_phrase, {rsa_pass_phrase, "Password"}}| Config];
+ case lists:member('ssh-rsa',
+ ssh_transport:default_algorithms(public_key)) of
+ true ->
+ DataDir = proplists:get_value(data_dir, Config),
+ PrivDir = proplists:get_value(priv_dir, Config),
+ ssh_test_lib:setup_rsa_pass_pharse(DataDir, PrivDir, "Password"),
+ [{pass_phrase, {rsa_pass_phrase, "Password"}}| Config];
+ false ->
+ {skip, unsupported_pub_key}
+ end;
init_per_group(dsa_pass_key, Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- PrivDir = proplists:get_value(priv_dir, Config),
- ssh_test_lib:setup_dsa_pass_pharse(DataDir, PrivDir, "Password"),
- [{pass_phrase, {dsa_pass_phrase, "Password"}}| Config];
+ case lists:member('ssh-dss',
+ ssh_transport:default_algorithms(public_key)) of
+ true ->
+ DataDir = proplists:get_value(data_dir, Config),
+ PrivDir = proplists:get_value(priv_dir, Config),
+ ssh_test_lib:setup_dsa_pass_pharse(DataDir, PrivDir, "Password"),
+ [{pass_phrase, {dsa_pass_phrase, "Password"}}| Config];
+ false ->
+ {skip, unsupported_pub_key}
+ end;
init_per_group(host_user_key_differs, Config) ->
Data = proplists:get_value(data_dir, Config),
Sys = filename:join(proplists:get_value(priv_dir, Config), system_rsa),
@@ -220,10 +244,16 @@ init_per_group(host_user_key_differs, Config) ->
ssh_test_lib:setup_rsa_known_host(Sys, Usr),
Config;
init_per_group(key_cb, Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- PrivDir = proplists:get_value(priv_dir, Config),
- ssh_test_lib:setup_dsa(DataDir, PrivDir),
- Config;
+ case lists:member('ssh-rsa',
+ ssh_transport:default_algorithms(public_key)) of
+ true ->
+ DataDir = proplists:get_value(data_dir, Config),
+ PrivDir = proplists:get_value(priv_dir, Config),
+ ssh_test_lib:setup_rsa(DataDir, PrivDir),
+ Config;
+ false ->
+ {skip, unsupported_pub_key}
+ end;
init_per_group(internal_error, Config) ->
DataDir = proplists:get_value(data_dir, Config),
PrivDir = proplists:get_value(priv_dir, Config),
@@ -293,7 +323,7 @@ end_per_group(rsa_pass_key, Config) ->
Config;
end_per_group(key_cb, Config) ->
PrivDir = proplists:get_value(priv_dir, Config),
- ssh_test_lib:clean_dsa(PrivDir),
+ ssh_test_lib:clean_rsa(PrivDir),
Config;
end_per_group(internal_error, Config) ->
PrivDir = proplists:get_value(priv_dir, Config),
@@ -750,7 +780,7 @@ key_callback_options(Config) when is_list(Config) ->
{user_dir, UserDir},
{failfun, fun ssh_test_lib:failfun/2}]),
- {ok, PrivKey} = file:read_file(filename:join(UserDir, "id_dsa")),
+ {ok, PrivKey} = file:read_file(filename:join(UserDir, "id_rsa")),
ConnectOpts = [{silently_accept_hosts, true},
{user_dir, NoPubKeyDir},
diff --git a/lib/ssh/test/ssh_key_cb.erl b/lib/ssh/test/ssh_key_cb.erl
index 388ec2ecc1..12ff79efcd 100644
--- a/lib/ssh/test/ssh_key_cb.erl
+++ b/lib/ssh/test/ssh_key_cb.erl
@@ -33,9 +33,9 @@ add_host_key(_, _, _) ->
is_host_key(_, _, _, _) ->
true.
-user_key('ssh-dss', Opts) ->
+user_key('ssh-rsa', Opts) ->
UserDir = proplists:get_value(user_dir, Opts),
- KeyFile = filename:join(filename:dirname(UserDir), "id_dsa"),
+ KeyFile = filename:join(filename:dirname(UserDir), "id_rsa"),
{ok, KeyBin} = file:read_file(KeyFile),
[Entry] = public_key:pem_decode(KeyBin),
Key = public_key:pem_entry_decode(Entry),
diff --git a/lib/ssh/test/ssh_key_cb_options.erl b/lib/ssh/test/ssh_key_cb_options.erl
index afccb34f0f..946a1254d0 100644
--- a/lib/ssh/test/ssh_key_cb_options.erl
+++ b/lib/ssh/test/ssh_key_cb_options.erl
@@ -33,7 +33,7 @@ add_host_key(_, _, _) ->
is_host_key(_, _, _, _) ->
true.
-user_key('ssh-dss', Opts) ->
+user_key('ssh-rsa', Opts) ->
KeyCbOpts = proplists:get_value(key_cb_private, Opts),
KeyBin = proplists:get_value(priv_key, KeyCbOpts),
[Entry] = public_key:pem_decode(KeyBin),
diff --git a/lib/ssh/test/ssh_options_SUITE.erl b/lib/ssh/test/ssh_options_SUITE.erl
index 86f5cb1746..bd2d72c36c 100644
--- a/lib/ssh/test/ssh_options_SUITE.erl
+++ b/lib/ssh/test/ssh_options_SUITE.erl
@@ -148,6 +148,7 @@ init_per_group(hardening_tests, Config) ->
DataDir = proplists:get_value(data_dir, Config),
PrivDir = proplists:get_value(priv_dir, Config),
ssh_test_lib:setup_dsa(DataDir, PrivDir),
+ ssh_test_lib:setup_rsa(DataDir, PrivDir),
Config;
init_per_group(dir_options, Config) ->
PrivDir = proplists:get_value(priv_dir, Config),
diff --git a/lib/ssh/test/ssh_protocol_SUITE.erl b/lib/ssh/test/ssh_protocol_SUITE.erl
index 93d0bc2eb0..84290c7ffd 100644
--- a/lib/ssh/test/ssh_protocol_SUITE.erl
+++ b/lib/ssh/test/ssh_protocol_SUITE.erl
@@ -34,6 +34,12 @@
-define(NEWLINE, <<"\r\n">>).
-define(REKEY_DATA_TMO, 65000).
+%%-define(DEFAULT_KEX, 'diffie-hellman-group1-sha1').
+-define(DEFAULT_KEX, 'diffie-hellman-group14-sha256').
+
+-define(CIPHERS, ['aes256-ctr','aes192-ctr','aes128-ctr','aes128-cbc','3des-cbc']).
+-define(DEFAULT_CIPHERS, [{client2server,?CIPHERS}, {server2client,?CIPHERS}]).
+
-define(v(Key, Config), proplists:get_value(Key, Config)).
-define(v(Key, Config, Default), proplists:get_value(Key, Config, Default)).
@@ -97,7 +103,9 @@ end_per_suite(Config) ->
init_per_testcase(no_common_alg_server_disconnects, Config) ->
- start_std_daemon(Config, [{preferred_algorithms,[{public_key,['ssh-rsa']}]}]);
+ start_std_daemon(Config, [{preferred_algorithms,[{public_key,['ssh-rsa']},
+ {cipher,?DEFAULT_CIPHERS}
+ ]}]);
init_per_testcase(TC, Config) when TC == gex_client_init_option_groups ;
TC == gex_client_init_option_groups_moduli_file ;
@@ -128,7 +136,8 @@ init_per_testcase(TC, Config) when TC == gex_client_init_option_groups ;
[]
end,
start_std_daemon(Config,
- [{preferred_algorithms, ssh:default_algorithms()}
+ [{preferred_algorithms,[{cipher,?DEFAULT_CIPHERS}
+ ]}
| Opts]);
init_per_testcase(_TestCase, Config) ->
check_std_daemon_works(Config, ?LINE).
@@ -237,7 +246,10 @@ lib_works_as_server(Config) ->
%% and finally connect to it with a regular Erlang SSH client:
{ok,_} = std_connect(HostPort, Config,
- [{preferred_algorithms,[{kex,['diffie-hellman-group1-sha1']}]}]
+ [{preferred_algorithms,[{kex,[?DEFAULT_KEX]},
+ {cipher,?DEFAULT_CIPHERS}
+ ]}
+ ]
).
%%--------------------------------------------------------------------
@@ -277,7 +289,9 @@ no_common_alg_server_disconnects(Config) ->
[{silently_accept_hosts, true},
{user_dir, user_dir(Config)},
{user_interaction, false},
- {preferred_algorithms,[{public_key,['ssh-dss']}]}
+ {preferred_algorithms,[{public_key,['ssh-dss']},
+ {cipher,?DEFAULT_CIPHERS}
+ ]}
]},
receive_hello,
{send, hello},
@@ -311,7 +325,7 @@ no_common_alg_client_disconnects(Config) ->
{match, #ssh_msg_kexinit{_='_'}, receive_msg},
{send, #ssh_msg_kexinit{ % with unsupported "SOME-UNSUPPORTED"
cookie = <<80,158,95,51,174,35,73,130,246,141,200,49,180,190,82,234>>,
- kex_algorithms = ["diffie-hellman-group1-sha1"],
+ kex_algorithms = [atom_to_list(?DEFAULT_KEX)],
server_host_key_algorithms = ["SOME-UNSUPPORTED"], % SIC!
encryption_algorithms_client_to_server = ["aes128-ctr"],
encryption_algorithms_server_to_client = ["aes128-ctr"],
@@ -332,7 +346,9 @@ no_common_alg_client_disconnects(Config) ->
%% and finally connect to it with a regular Erlang SSH client
%% which of course does not support SOME-UNSUPPORTED as pub key algo:
- Result = std_connect(HostPort, Config, [{preferred_algorithms,[{public_key,['ssh-dss']}]}]),
+ Result = std_connect(HostPort, Config, [{preferred_algorithms,[{public_key,['ssh-dss']},
+ {cipher,?DEFAULT_CIPHERS}
+ ]}]),
ct:log("Result of connect is ~p",[Result]),
receive
@@ -376,7 +392,9 @@ do_gex_client_init(Config, {Min,N,Max}, {G,P}) ->
[{silently_accept_hosts, true},
{user_dir, user_dir(Config)},
{user_interaction, false},
- {preferred_algorithms,[{kex,['diffie-hellman-group-exchange-sha1']}]}
+ {preferred_algorithms,[{kex,['diffie-hellman-group-exchange-sha1']},
+ {cipher,?DEFAULT_CIPHERS}
+ ]}
]},
receive_hello,
{send, hello},
@@ -402,7 +420,9 @@ do_gex_client_init_old(Config, N, {G,P}) ->
[{silently_accept_hosts, true},
{user_dir, user_dir(Config)},
{user_interaction, false},
- {preferred_algorithms,[{kex,['diffie-hellman-group-exchange-sha1']}]}
+ {preferred_algorithms,[{kex,['diffie-hellman-group-exchange-sha1']},
+ {cipher,?DEFAULT_CIPHERS}
+ ]}
]},
receive_hello,
{send, hello},
@@ -572,7 +592,9 @@ client_handles_keyboard_interactive_0_pwds(Config) ->
%% and finally connect to it with a regular Erlang SSH client:
{ok,_} = std_connect(HostPort, Config,
- [{preferred_algorithms,[{kex,['diffie-hellman-group1-sha1']}]}]
+ [{preferred_algorithms,[{kex,[?DEFAULT_KEX]},
+ {cipher,?DEFAULT_CIPHERS}
+ ]}]
).
@@ -623,6 +645,7 @@ stop_apps(_Config) ->
setup_dirs(Config) ->
DataDir = proplists:get_value(data_dir, Config),
PrivDir = proplists:get_value(priv_dir, Config),
+ ssh_test_lib:setup_dsa(DataDir, PrivDir),
ssh_test_lib:setup_rsa(DataDir, PrivDir),
Config.
@@ -708,7 +731,9 @@ connect_and_kex(Config, InitialState) ->
ssh_trpt_test_lib:exec(
[{connect,
server_host(Config),server_port(Config),
- [{preferred_algorithms,[{kex,['diffie-hellman-group1-sha1']}]},
+ [{preferred_algorithms,[{kex,[?DEFAULT_KEX]},
+ {cipher,?DEFAULT_CIPHERS}
+ ]},
{silently_accept_hosts, true},
{user_dir, user_dir(Config)},
{user_interaction, false}]},
diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/ssh_host_rsa_key b/lib/ssh/test/ssh_sftp_SUITE_data/ssh_host_rsa_key
new file mode 100644
index 0000000000..79968bdd7d
--- /dev/null
+++ b/lib/ssh/test/ssh_sftp_SUITE_data/ssh_host_rsa_key
@@ -0,0 +1,16 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8semM4q843337
+zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RWRWzjaxSB
+6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4QIDAQAB
+AoGANmvJzJO5hkLuvyDZHKfAnGTtpifcR1wtSa9DjdKUyn8vhKF0mIimnbnYQEmW
+NUUb3gXCZLi9PvkpRSVRrASDOZwcjoU/Kvww163vBUVb2cOZfFhyn6o2Sk88Tt++
+udH3hdjpf9i7jTtUkUe+QYPsia+wgvvrmn4QrahLAH86+kECQQDx5gFeXTME3cnW
+WMpFz3PPumduzjqgqMMWEccX4FtQkMX/gyGa5UC7OHFyh0N/gSWvPbRHa8A6YgIt
+n8DO+fh5AkEAzbqX4DOn8NY6xJIi42q7l/2jIA0RkB6P7YugW5NblhqBZ0XDnpA5
+sMt+rz+K07u9XZtxgh1xi7mNfwY6lEAMqQJBAJBEauCKmRj35Z6OyeQku59SPsnY
++SJEREVvSNw2lH9SOKQQ4wPsYlTGbvKtNVZgAcen91L5MmYfeckYE/fdIZECQQCt
+64zxsTnM1I8iFxj/gP/OYlJBikrKt8udWmjaghzvLMEw+T2DExJyb9ZNeT53+UMB
+m6O+B/4xzU/djvp+0hbhAkAemIt+rA5kTmYlFndhpvzkSSM8a2EXsO4XIPgGWCTT
+tQKS/tTly0ADMjN/TVy11+9d6zcqadNVuHXHGtR4W0GR
+-----END RSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/ssh_host_rsa_key.pub b/lib/ssh/test/ssh_sftp_SUITE_data/ssh_host_rsa_key.pub
new file mode 100644
index 0000000000..75d2025c71
--- /dev/null
+++ b/lib/ssh/test/ssh_sftp_SUITE_data/ssh_host_rsa_key.pub
@@ -0,0 +1,5 @@
+---- BEGIN SSH2 PUBLIC KEY ----
+AAAAB3NzaC1yc2EAAAADAQABAAAAgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8
+semM4q843337zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RW
+RWzjaxSB6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4Q==
+---- END SSH2 PUBLIC KEY ----
diff --git a/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl b/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl
index 56a33d6349..fd5157d603 100644
--- a/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl
+++ b/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl
@@ -65,6 +65,7 @@ init_per_suite(Config) ->
{ok, FileInfo} = file:read_file_info(FileName),
ok = file:write_file_info(FileName,
FileInfo#file_info{mode = 8#400}),
+ ssh_test_lib:setup_rsa(DataDir, PrivDir),
ssh_test_lib:setup_dsa(DataDir, PrivDir),
Config
end).
@@ -73,6 +74,7 @@ end_per_suite(Config) ->
UserDir = filename:join(proplists:get_value(priv_dir, Config), nopubkey),
file:del_dir(UserDir),
SysDir = proplists:get_value(priv_dir, Config),
+ ssh_test_lib:clean_rsa(SysDir),
ssh_test_lib:clean_dsa(SysDir),
ok.
diff --git a/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/id_rsa b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/id_rsa
new file mode 100644
index 0000000000..9d7e0dd5fb
--- /dev/null
+++ b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/id_rsa
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQD1OET+3O/Bvj/dtjxDTXmj1oiJt4sIph5kGy0RfjoPrZfaS+CU
+DhakCmS6t2ivxWFgtpKWaoGMZMJqWj6F6ZsumyFl3FPBtujwY/35cgifrI9Ns4Tl
+zR1uuengNBmV+WRQ5cd9F2qS6Z8aDQihzt0r8JUqLcK+VQbrmNzboCCQQwIDAQAB
+AoGAPQEyqPTt8JUT7mRXuaacjFXiweAXhp9NEDpyi9eLOjtFe9lElZCrsUOkq47V
+TGUeRKEm9qSodfTbKPoqc8YaBJGJPhUaTAcha+7QcDdfHBvIsgxvU7ePVnlpXRp3
+CCUEMPhlnx6xBoTYP+fRU0e3+xJIPVyVCqX1jAdUMkzfRoECQQD6ux7B1QJAIWyK
+SGkbDUbBilNmzCFNgIpOP6PA+bwfi5d16diTpra5AX09keQABAo/KaP1PdV8Vg0p
+z4P3A7G3AkEA+l+AKG6m0kQTTBMJDqOdVPYwe+5GxunMaqmhokpEbuGsrZBl5Dvd
+WpcBjR7jmenrhKZRIuA+Fz5HPo/UQJPl1QJBAKxstDkeED8j/S2XoFhPKAJ+6t39
+sUVICVTIZQeXdmzHJXCcUSkw8+WEhakqw/3SyW0oaK2FSWQJFWJUZ+8eJj8CQEh3
+xeduB5kKnS9CvzdeghZqX6QvVosSdtlUmfUYW/BgH5PpHKTP8wTaeld3XldZTpMJ
+dKiMkUw2+XYROVUrubUCQD+Na1LhULlpn4ISEtIEfqpdlUhxDgO15Wg8USmsng+x
+ICliVOSQtwaZjm8kwaFt0W7XnpnDxbRs37vIEbIMWak=
+-----END RSA PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_rsa_key b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_rsa_key
new file mode 100644
index 0000000000..79968bdd7d
--- /dev/null
+++ b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_rsa_key
@@ -0,0 +1,16 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8semM4q843337
+zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RWRWzjaxSB
+6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4QIDAQAB
+AoGANmvJzJO5hkLuvyDZHKfAnGTtpifcR1wtSa9DjdKUyn8vhKF0mIimnbnYQEmW
+NUUb3gXCZLi9PvkpRSVRrASDOZwcjoU/Kvww163vBUVb2cOZfFhyn6o2Sk88Tt++
+udH3hdjpf9i7jTtUkUe+QYPsia+wgvvrmn4QrahLAH86+kECQQDx5gFeXTME3cnW
+WMpFz3PPumduzjqgqMMWEccX4FtQkMX/gyGa5UC7OHFyh0N/gSWvPbRHa8A6YgIt
+n8DO+fh5AkEAzbqX4DOn8NY6xJIi42q7l/2jIA0RkB6P7YugW5NblhqBZ0XDnpA5
+sMt+rz+K07u9XZtxgh1xi7mNfwY6lEAMqQJBAJBEauCKmRj35Z6OyeQku59SPsnY
++SJEREVvSNw2lH9SOKQQ4wPsYlTGbvKtNVZgAcen91L5MmYfeckYE/fdIZECQQCt
+64zxsTnM1I8iFxj/gP/OYlJBikrKt8udWmjaghzvLMEw+T2DExJyb9ZNeT53+UMB
+m6O+B/4xzU/djvp+0hbhAkAemIt+rA5kTmYlFndhpvzkSSM8a2EXsO4XIPgGWCTT
+tQKS/tTly0ADMjN/TVy11+9d6zcqadNVuHXHGtR4W0GR
+-----END RSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_rsa_key.pub b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_rsa_key.pub
new file mode 100644
index 0000000000..75d2025c71
--- /dev/null
+++ b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_rsa_key.pub
@@ -0,0 +1,5 @@
+---- BEGIN SSH2 PUBLIC KEY ----
+AAAAB3NzaC1yc2EAAAADAQABAAAAgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8
+semM4q843337zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RW
+RWzjaxSB6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4Q==
+---- END SSH2 PUBLIC KEY ----
diff --git a/lib/ssh/test/ssh_trpt_test_lib.erl b/lib/ssh/test/ssh_trpt_test_lib.erl
index bc86000d81..0fa0f0c0e4 100644
--- a/lib/ssh/test/ssh_trpt_test_lib.erl
+++ b/lib/ssh/test/ssh_trpt_test_lib.erl
@@ -93,7 +93,10 @@ exec(Op, S0=#s{}) ->
exit:Exit ->
report_trace(exit, Exit, S1),
- exit(Exit)
+ exit(Exit);
+ Cls:Err ->
+ ct:pal("Class=~p, Error=~p", [Cls,Err]),
+ error("fooooooO")
end;
exec(Op, {ok,S=#s{}}) -> exec(Op, S);
exec(_, Error) -> Error.
--
cgit v1.2.3
From c0b7998760959b02293013cc9e00599303212458 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 19 Jan 2017 20:59:19 +0100
Subject: ssh: clearer hash calculation
---
lib/ssh/src/ssh_transport.erl | 56 ++++++++++++-------------------------------
1 file changed, 15 insertions(+), 41 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index b43bcff363..85ee88ce5f 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -1632,52 +1632,23 @@ mac('hmac-sha2-512', Key, SeqNum, Data) ->
crypto:hmac(sha512, Key, [<>, Data]).
%% return N hash bytes (HASH)
-hash(SSH, Char, Bits) ->
- HASH =
- case SSH#ssh.kex of
- 'diffie-hellman-group1-sha1' ->
- fun(Data) -> crypto:hash(sha, Data) end;
- 'diffie-hellman-group14-sha1' ->
- fun(Data) -> crypto:hash(sha, Data) end;
- 'diffie-hellman-group14-sha256' ->
- fun(Data) -> crypto:hash(sha256, Data) end;
- 'diffie-hellman-group16-sha512' ->
- fun(Data) -> crypto:hash(sha512, Data) end;
- 'diffie-hellman-group18-sha512' ->
- fun(Data) -> crypto:hash(sha512, Data) end;
-
- 'diffie-hellman-group-exchange-sha1' ->
- fun(Data) -> crypto:hash(sha, Data) end;
- 'diffie-hellman-group-exchange-sha256' ->
- fun(Data) -> crypto:hash(sha256, Data) end;
-
- 'ecdh-sha2-nistp256' ->
- fun(Data) -> crypto:hash(sha256,Data) end;
- 'ecdh-sha2-nistp384' ->
- fun(Data) -> crypto:hash(sha384,Data) end;
- 'ecdh-sha2-nistp521' ->
- fun(Data) -> crypto:hash(sha512,Data) end;
- _ ->
- exit({bad_algorithm,SSH#ssh.kex})
- end,
- hash(SSH, Char, Bits, HASH).
-
-hash(_SSH, _Char, 0, _HASH) ->
+hash(_SSH, _Char, 0) ->
<<>>;
-hash(SSH, Char, N, HASH) ->
-K = SSH#ssh.shared_secret, % K = ssh_bits:mpint(SSH#ssh.shared_secret),
+hash(SSH, Char, N) ->
+ HashAlg = sha(SSH#ssh.kex),
+ K = SSH#ssh.shared_secret,
H = SSH#ssh.exchanged_hash,
- SessionID = SSH#ssh.session_id,
- K1 = HASH([K, H, Char, SessionID]),
+ K1 = crypto:hash(HashAlg, [K, H, Char, SSH#ssh.session_id]),
Sz = N div 8,
- <> = hash(K, H, K1, N-128, HASH),
+ <> = hash(K, H, K1, N-128, HashAlg),
Key.
-hash(_K, _H, Ki, N, _HASH) when N =< 0 ->
+hash(_K, _H, Ki, N, _HashAlg) when N =< 0 ->
Ki;
-hash(K, H, Ki, N, HASH) ->
- Kj = HASH([K, H, Ki]),
- hash(K, H, <>, N-128, HASH).
+hash(K, H, Ki, N, HashAlg) ->
+ Kj = crypto:hash(HashAlg, [K, H, Ki]),
+ hash(K, H, <>, N-128, HashAlg).
+
kex_h(SSH, Key, E, F, K) ->
KeyBin = public_key:ssh_encode(Key, ssh2_pubkey),
@@ -1728,7 +1699,10 @@ sha('diffie-hellman-group-exchange-sha1') -> sha;
sha('diffie-hellman-group-exchange-sha256') -> sha256;
sha(?'secp256r1') -> sha(secp256r1);
sha(?'secp384r1') -> sha(secp384r1);
-sha(?'secp521r1') -> sha(secp521r1).
+sha(?'secp521r1') -> sha(secp521r1);
+sha('ecdh-sha2-nistp256') -> sha(secp256r1);
+sha('ecdh-sha2-nistp384') -> sha(secp384r1);
+sha('ecdh-sha2-nistp521') -> sha(secp521r1).
mac_key_bytes('hmac-sha1') -> 20;
--
cgit v1.2.3
From 05473252a740ae40894fbd2e5ee4349db6db087c Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 19 Jan 2017 21:51:59 +0100
Subject: ssh: minor code unfolding
---
lib/ssh/src/ssh_transport.erl | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 85ee88ce5f..02209d5dfd 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -783,9 +783,8 @@ accepted_host(Ssh, PeerName, Public, Opts) ->
yes == yes_no(Ssh, "New host " ++ PeerName ++ " accept")
end.
-known_host_key(#ssh{opts = Opts, key_cb = Mod, peer = Peer} = Ssh,
+known_host_key(#ssh{opts = Opts, key_cb = Mod, peer = {PeerName,_}} = Ssh,
Public, Alg) ->
- PeerName = peer_name(Peer),
case Mod:is_host_key(Public, PeerName, Alg, Opts) of
true ->
ok;
@@ -1631,6 +1630,8 @@ mac('hmac-sha2-256', Key, SeqNum, Data) ->
mac('hmac-sha2-512', Key, SeqNum, Data) ->
crypto:hmac(sha512, Key, [<>, Data]).
+
+%%%----------------------------------------------------------------
%% return N hash bytes (HASH)
hash(_SSH, _Char, 0) ->
<<>>;
@@ -1649,7 +1650,7 @@ hash(K, H, Ki, N, HashAlg) ->
Kj = crypto:hash(HashAlg, [K, H, Ki]),
hash(K, H, <>, N-128, HashAlg).
-
+%%%----------------------------------------------------------------
kex_h(SSH, Key, E, F, K) ->
KeyBin = public_key:ssh_encode(Key, ssh2_pubkey),
L = < 16;
mac_digest_size('AEAD_AES_256_GCM') -> 16;
mac_digest_size(none) -> 0.
-peer_name({Host, _}) ->
- Host.
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Diffie-Hellman utils
--
cgit v1.2.3
From 99a6fe8c485af3024731bbb6a5af9afac7a0045f Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 20 Jan 2017 15:52:57 +0100
Subject: ssh: Enable usage of supported but not default host key algorithms
---
lib/ssh/src/ssh_connection_handler.erl | 33 +++++++++++++++++++--------------
1 file changed, 19 insertions(+), 14 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 4496c657c3..dcf509ca09 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -1481,31 +1481,36 @@ renegotiation(_) -> false.
%%--------------------------------------------------------------------
supported_host_keys(client, _, Options) ->
try
- case proplists:get_value(public_key,
- proplists:get_value(preferred_algorithms,Options,[])
- ) of
- undefined ->
- ssh_transport:default_algorithms(public_key);
- L ->
- L -- (L--ssh_transport:default_algorithms(public_key))
- end
+ find_sup_hkeys(Options)
of
[] ->
- {stop, {shutdown, "No public key algs"}};
+ error({shutdown, "No public key algs"});
Algs ->
[atom_to_list(A) || A<-Algs]
catch
exit:Reason ->
- {stop, {shutdown, Reason}}
+ error({shutdown, Reason})
end;
supported_host_keys(server, KeyCb, Options) ->
- [atom_to_list(A) || A <- proplists:get_value(public_key,
- proplists:get_value(preferred_algorithms,Options,[]),
- ssh_transport:default_algorithms(public_key)
- ),
+ [atom_to_list(A) || A <- find_sup_hkeys(Options),
available_host_key(KeyCb, A, Options)
].
+
+find_sup_hkeys(Options) ->
+ case proplists:get_value(public_key,
+ proplists:get_value(preferred_algorithms,Options,[])
+ )
+ of
+ undefined ->
+ ssh_transport:default_algorithms(public_key);
+ L ->
+ NonSupported = L--ssh_transport:supported_algorithms(public_key),
+ L -- NonSupported
+ end.
+
+
+
%% Alg :: atom()
available_host_key(KeyCb, Alg, Opts) ->
element(1, catch KeyCb:host_key(Alg, Opts)) == ok.
--
cgit v1.2.3
From 4751ac228fc09c6421f521b9e5a1a0f2b2eebade Mon Sep 17 00:00:00 2001
From: Erlang/OTP
Date: Wed, 1 Feb 2017 18:32:57 +0100
Subject: Prepare release
---
lib/ssh/doc/src/notes.xml | 37 +++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index 4764d9ffe6..b0c8bfa62c 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -30,6 +30,43 @@
notes.xml
+Ssh 4.2.2.3
+
+ Fixed Bugs and Malfunctions
+
+ -
+
+ The key exchange algorithm
+ diffie-hellman-group-exchange-sha* has a server-option
+ {dh_gex_limits,{Min,Max}}. There was a hostkey
+ signature validation error on the client side if the
+ option was used and the Min or the Max
+ differed from the corresponding values obtained from the
+ client.
+
+ This bug is now corrected.
+
+ Own Id: OTP-14166
+
+
+
+
+
+ Improvements and New Features
+
+ -
+
+ Key exchange algorithms
+ diffie-hellman-group-exchange-sha* optimized, up to a
+ factor of 11 for the slowest ( = biggest and safest) one.
+
+ Own Id: OTP-14169 Aux Id: seq-13261
+
+
+
+
+
+
Ssh 4.2.2.2
Fixed Bugs and Malfunctions
--
cgit v1.2.3
From 2e25e7890af04d9001fa777d848ebce6d059edf2 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 2 Feb 2017 16:52:37 +0100
Subject: ssh: document new and retired algorithms
---
lib/ssh/doc/src/ssh_app.xml | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/ssh_app.xml b/lib/ssh/doc/src/ssh_app.xml
index 5cc4c24889..5f710decc1 100644
--- a/lib/ssh/doc/src/ssh_app.xml
+++ b/lib/ssh/doc/src/ssh_app.xml
@@ -146,7 +146,10 @@
- diffie-hellman-group-exchange-sha1
- diffie-hellman-group-exchange-sha256
- diffie-hellman-group14-sha1
- - diffie-hellman-group1-sha1
+ - diffie-hellman-group14-sha256
+ - diffie-hellman-group16-sha512
+ - diffie-hellman-group18-sha512
+ - (diffie-hellman-group1-sha1, retired: can be enabled with the preferred_algorithms option)
@@ -157,7 +160,7 @@
- ecdsa-sha2-nistp384
- ecdsa-sha2-nistp521
- ssh-rsa
- - ssh-dss
+ - (ssh-dss, retired: can be enabled with the preferred_algorithms option)
@@ -306,6 +309,8 @@
Comment: Defines hmac-sha2-256 and hmac-sha2-512
+
+ - Work in progress: https://tools.ietf.org/html/draft-ietf-curdle-ssh-kex-sha2-05, Key Exchange (KEX) Method Updates and Recommendations for Secure Shell (SSH)
--
cgit v1.2.3
From c1ab024ba3bd3f66f291d9a88a4e8af3e0244eb2 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 3 Feb 2017 14:33:47 +0100
Subject: ssh: logging in test lib for ssh tests
---
lib/ssh/test/ssh_test_lib.erl | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl
index 286ac6e882..1673f52821 100644
--- a/lib/ssh/test/ssh_test_lib.erl
+++ b/lib/ssh/test/ssh_test_lib.erl
@@ -690,13 +690,16 @@ ssh_type() ->
ssh_type1() ->
try
+ ct:log("~p:~p os:find_executable(\"ssh\")",[?MODULE,?LINE]),
case os:find_executable("ssh") of
false ->
ct:log("~p:~p Executable \"ssh\" not found",[?MODULE,?LINE]),
not_found;
- _ ->
+ Path ->
+ ct:log("~p:~p Found \"ssh\" at ~p",[?MODULE,?LINE,Path]),
case os:cmd("ssh -V") of
- "OpenSSH" ++ _ ->
+ Version = "OpenSSH" ++ _ ->
+ ct:log("~p:~p Found OpenSSH ~p",[?MODULE,?LINE,Version]),
openSSH;
Str ->
ct:log("ssh client ~p is unknown",[Str]),
--
cgit v1.2.3
From fc7a709d0898ea302376b3dece24d562fbed610d Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 3 Feb 2017 16:34:31 +0100
Subject: ssh: use real groups in kex_gex test suite
---
lib/ssh/test/ssh_protocol_SUITE.erl | 41 +++++++++++++++-------
lib/ssh/test/ssh_protocol_SUITE_data/dh_group_test | 4 +--
.../ssh_protocol_SUITE_data/dh_group_test.moduli | 5 ++-
3 files changed, 33 insertions(+), 17 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_protocol_SUITE.erl b/lib/ssh/test/ssh_protocol_SUITE.erl
index 93d0bc2eb0..f9edc5bfc2 100644
--- a/lib/ssh/test/ssh_protocol_SUITE.erl
+++ b/lib/ssh/test/ssh_protocol_SUITE.erl
@@ -107,7 +107,10 @@ init_per_testcase(TC, Config) when TC == gex_client_init_option_groups ;
TC == gex_client_old_request_noexact ->
Opts = case TC of
gex_client_init_option_groups ->
- [{dh_gex_groups, [{2345, 3, 41}]}];
+ [{dh_gex_groups,
+ [{1023, 5,
+ 16#D9277DAA27DB131C03B108D41A76B4DA8ACEECCCAE73D2E48CEDAAA70B09EF9F04FB020DCF36C51B8E485B26FABE0337E24232BE4F4E693548310244937433FB1A5758195DC73B84ADEF8237472C46747D79DC0A2CF8A57CE8DBD8F466A20F8551E7B1B824B2E4987A8816D9BC0741C2798F3EBAD3ADEBCC78FCE6A770E2EC9F
+ }]}];
gex_client_init_option_groups_file ->
DataDir = proplists:get_value(data_dir, Config),
F = filename:join(DataDir, "dh_group_test"),
@@ -119,10 +122,12 @@ init_per_testcase(TC, Config) when TC == gex_client_init_option_groups ;
_ when TC == gex_server_gex_limit ;
TC == gex_client_old_request_exact ;
TC == gex_client_old_request_noexact ->
- [{dh_gex_groups, [{ 500, 3, 17},
- {1000, 7, 91},
- {3000, 5, 61}]},
- {dh_gex_limits,{500,1500}}
+ [{dh_gex_groups,
+ [{1023, 2, 16#D9277DAA27DB131C03B108D41A76B4DA8ACEECCCAE73D2E48CEDAAA70B09EF9F04FB020DCF36C51B8E485B26FABE0337E24232BE4F4E693548310244937433FB1A5758195DC73B84ADEF8237472C46747D79DC0A2CF8A57CE8DBD8F466A20F8551E7B1B824B2E4987A8816D9BC0741C2798F3EBAD3ADEBCC78FCE6A771225323},
+ {1535, 5, 16#D1391174233D315398FE2830AC6B2B66BCCD01B0A634899F339B7879F1DB85712E9DC4E4B1C6C8355570C1D2DCB53493DF18175A9C53D1128B592B4C72D97136F5542FEB981CBFE8012FDD30361F288A42BD5EBB08BAB0A5640E1AC48763B2ABD1945FEE36B2D55E1D50A1C86CED9DD141C4E7BE2D32D9B562A0F8E2E927020E91F58B57EB9ACDDA106A59302D7E92AD5F6E851A45FA1CFE86029A0F727F65A8F475F33572E2FDAB6073F0C21B8B54C3823DB2EF068927E5D747498F96E1E827},
+ {3071, 2, 16#DFAA35D35531E0F524F0099877A482D2AC8D589F374394A262A8E81A8A4FB2F65FADBAB395E05D147B29D486DFAA41F41597A256DA82A8B6F76401AED53D0253F956CEC610D417E42E3B287F7938FC24D8821B40BFA218A956EB7401BED6C96C68C7FD64F8170A8A76B953DD2F05420118F6B144D8FE48060A2BCB85056B478EDEF96DBC70427053ECD2958C074169E9550DD877779A3CF17C5AC850598C7586BEEA9DCFE9DD2A5FB62DF5F33EA7BC00CDA31B9D2DD721F979EA85B6E63F0C4E30BDDCD3A335522F9004C4ED50B15DC537F55324DD4FA119FB3F101467C6D7E1699DE4B3E3C478A8679B8EB3FA5C9B826B44530FD3BE9AD3063B240B0C853EBDDBD68DD940332D98F148D5D9E1DC977D60A0D23D0CA1198637FEAE4E7FAAC173AF2B84313A666CFB4EE6972811921D0AD867CE57F3BBC8D6CB057E3B66757BB46C9F72662624D44E14528327E3A7100E81A12C43C4E236118318CD90C8AA185BBB0C764826DAEAEE8DD245C5B451B4944E6122CC522D1C335C2EEF9429825A2B}
+ ]},
+ {dh_gex_limits, {1023,2000}}
];
_ ->
[]
@@ -351,20 +356,25 @@ no_common_alg_client_disconnects(Config) ->
%%%--------------------------------------------------------------------
gex_client_init_option_groups(Config) ->
- do_gex_client_init(Config, {2000, 2048, 4000},
- {3,41}).
+ do_gex_client_init(Config, {512, 2048, 4000},
+ {5,16#D9277DAA27DB131C03B108D41A76B4DA8ACEECCCAE73D2E48CEDAAA70B09EF9F04FB020DCF36C51B8E485B26FABE0337E24232BE4F4E693548310244937433FB1A5758195DC73B84ADEF8237472C46747D79DC0A2CF8A57CE8DBD8F466A20F8551E7B1B824B2E4987A8816D9BC0741C2798F3EBAD3ADEBCC78FCE6A770E2EC9F}
+ ).
gex_client_init_option_groups_file(Config) ->
do_gex_client_init(Config, {2000, 2048, 4000},
- {5,61}).
+ {5, 16#DFAA35D35531E0F524F0099877A482D2AC8D589F374394A262A8E81A8A4FB2F65FADBAB395E05D147B29D486DFAA41F41597A256DA82A8B6F76401AED53D0253F956CEC610D417E42E3B287F7938FC24D8821B40BFA218A956EB7401BED6C96C68C7FD64F8170A8A76B953DD2F05420118F6B144D8FE48060A2BCB85056B478EDEF96DBC70427053ECD2958C074169E9550DD877779A3CF17C5AC850598C7586BEEA9DCFE9DD2A5FB62DF5F33EA7BC00CDA31B9D2DD721F979EA85B6E63F0C4E30BDDCD3A335522F9004C4ED50B15DC537F55324DD4FA119FB3F101467C6D7E1699DE4B3E3C478A8679B8EB3FA5C9B826B44530FD3BE9AD3063B240B0C853EBDDBD68DD940332D98F148D5D9E1DC977D60A0D23D0CA1198637FEAE4E7FAAC173AF2B84313A666CFB4EE6972811921D0AD867CE57F3BBC8D6CB057E3B66757BB46C9F72662624D44E14528327E3A7100E81A12C43C4E236118318CD90C8AA185BBB0C764826DAEAEE8DD245C5B451B4944E6122CC522D1C335C2EEF9424273F1F}
+ ).
gex_client_init_option_groups_moduli_file(Config) ->
do_gex_client_init(Config, {2000, 2048, 4000},
- {5,16#B7}).
+ {5, 16#DD2047CBDBB6F8E919BC63DE885B34D0FD6E3DB2887D8B46FE249886ACED6B46DFCD5553168185FD376122171CD8927E60120FA8D01F01D03E58281FEA9A1ABE97631C828E41815F34FDCDF787419FE13A3137649AA93D2584230DF5F24B5C00C88B7D7DE4367693428C730376F218A53E853B0851BAB7C53C15DA7839CBE1285DB63F6FA45C1BB59FE1C5BB918F0F8459D7EF60ACFF5C0FA0F3FCAD1C5F4CE4416D4F4B36B05CDCEBE4FB879E95847EFBC6449CD190248843BC7EDB145FBFC4EDBB1A3C959298F08F3BA2CFBE231BBE204BE6F906209D28BD4820AB3E7BE96C26AE8A809ADD8D1A5A0B008E9570FA4C4697E116B8119892C604293683A9635F}
+ ).
gex_server_gex_limit(Config) ->
do_gex_client_init(Config, {1000, 3000, 4000},
- {7,91}).
+ %% {7,91}).
+ {5, 16#D1391174233D315398FE2830AC6B2B66BCCD01B0A634899F339B7879F1DB85712E9DC4E4B1C6C8355570C1D2DCB53493DF18175A9C53D1128B592B4C72D97136F5542FEB981CBFE8012FDD30361F288A42BD5EBB08BAB0A5640E1AC48763B2ABD1945FEE36B2D55E1D50A1C86CED9DD141C4E7BE2D32D9B562A0F8E2E927020E91F58B57EB9ACDDA106A59302D7E92AD5F6E851A45FA1CFE86029A0F727F65A8F475F33572E2FDAB6073F0C21B8B54C3823DB2EF068927E5D747498F96E1E827}
+ ).
do_gex_client_init(Config, {Min,N,Max}, {G,P}) ->
@@ -390,8 +400,15 @@ do_gex_client_init(Config, {Min,N,Max}, {G,P}) ->
).
%%%--------------------------------------------------------------------
-gex_client_old_request_exact(Config) -> do_gex_client_init_old(Config, 500, {3,17}).
-gex_client_old_request_noexact(Config) -> do_gex_client_init_old(Config, 800, {7,91}).
+gex_client_old_request_exact(Config) ->
+ do_gex_client_init_old(Config, 1023,
+ {2, 16#D9277DAA27DB131C03B108D41A76B4DA8ACEECCCAE73D2E48CEDAAA70B09EF9F04FB020DCF36C51B8E485B26FABE0337E24232BE4F4E693548310244937433FB1A5758195DC73B84ADEF8237472C46747D79DC0A2CF8A57CE8DBD8F466A20F8551E7B1B824B2E4987A8816D9BC0741C2798F3EBAD3ADEBCC78FCE6A771225323}
+ ).
+
+gex_client_old_request_noexact(Config) ->
+ do_gex_client_init_old(Config, 1400,
+ {5, 16#D1391174233D315398FE2830AC6B2B66BCCD01B0A634899F339B7879F1DB85712E9DC4E4B1C6C8355570C1D2DCB53493DF18175A9C53D1128B592B4C72D97136F5542FEB981CBFE8012FDD30361F288A42BD5EBB08BAB0A5640E1AC48763B2ABD1945FEE36B2D55E1D50A1C86CED9DD141C4E7BE2D32D9B562A0F8E2E927020E91F58B57EB9ACDDA106A59302D7E92AD5F6E851A45FA1CFE86029A0F727F65A8F475F33572E2FDAB6073F0C21B8B54C3823DB2EF068927E5D747498F96E1E827}
+ ).
do_gex_client_init_old(Config, N, {G,P}) ->
{ok,_} =
diff --git a/lib/ssh/test/ssh_protocol_SUITE_data/dh_group_test b/lib/ssh/test/ssh_protocol_SUITE_data/dh_group_test
index 2887bb4b60..87c4b4afc8 100644
--- a/lib/ssh/test/ssh_protocol_SUITE_data/dh_group_test
+++ b/lib/ssh/test/ssh_protocol_SUITE_data/dh_group_test
@@ -1,3 +1,3 @@
-{2222, 5, 61}.
-{1111, 7, 91}.
+{1023, 5, 16#D9277DAA27DB131C03B108D41A76B4DA8ACEECCCAE73D2E48CEDAAA70B09EF9F04FB020DCF36C51B8E485B26FABE0337E24232BE4F4E693548310244937433FB1A5758195DC73B84ADEF8237472C46747D79DC0A2CF8A57CE8DBD8F466A20F8551E7B1B824B2E4987A8816D9BC0741C2798F3EBAD3ADEBCC78FCE6A770E2EC9F}.
+{3071, 5, 16#DFAA35D35531E0F524F0099877A482D2AC8D589F374394A262A8E81A8A4FB2F65FADBAB395E05D147B29D486DFAA41F41597A256DA82A8B6F76401AED53D0253F956CEC610D417E42E3B287F7938FC24D8821B40BFA218A956EB7401BED6C96C68C7FD64F8170A8A76B953DD2F05420118F6B144D8FE48060A2BCB85056B478EDEF96DBC70427053ECD2958C074169E9550DD877779A3CF17C5AC850598C7586BEEA9DCFE9DD2A5FB62DF5F33EA7BC00CDA31B9D2DD721F979EA85B6E63F0C4E30BDDCD3A335522F9004C4ED50B15DC537F55324DD4FA119FB3F101467C6D7E1699DE4B3E3C478A8679B8EB3FA5C9B826B44530FD3BE9AD3063B240B0C853EBDDBD68DD940332D98F148D5D9E1DC977D60A0D23D0CA1198637FEAE4E7FAAC173AF2B84313A666CFB4EE6972811921D0AD867CE57F3BBC8D6CB057E3B66757BB46C9F72662624D44E14528327E3A7100E81A12C43C4E236118318CD90C8AA185BBB0C764826DAEAEE8DD245C5B451B4944E6122CC522D1C335C2EEF9424273F1F}.
diff --git a/lib/ssh/test/ssh_protocol_SUITE_data/dh_group_test.moduli b/lib/ssh/test/ssh_protocol_SUITE_data/dh_group_test.moduli
index f6995ba4c9..6d2b4bcb59 100644
--- a/lib/ssh/test/ssh_protocol_SUITE_data/dh_group_test.moduli
+++ b/lib/ssh/test/ssh_protocol_SUITE_data/dh_group_test.moduli
@@ -1,3 +1,2 @@
-20151021104105 2 6 100 2222 5 B7
-20151021104106 2 6 100 1111 5 4F
-
+20120821044046 2 6 100 1023 2 D9277DAA27DB131C03B108D41A76B4DA8ACEECCCAE73D2E48CEDAAA70B09EF9F04FB020DCF36C51B8E485B26FABE0337E24232BE4F4E693548310244937433FB1A5758195DC73B84ADEF8237472C46747D79DC0A2CF8A57CE8DBD8F466A20F8551E7B1B824B2E4987A8816D9BC0741C2798F3EBAD3ADEBCC78FCE6A7711F2C6B
+20120821050554 2 6 100 2047 5 DD2047CBDBB6F8E919BC63DE885B34D0FD6E3DB2887D8B46FE249886ACED6B46DFCD5553168185FD376122171CD8927E60120FA8D01F01D03E58281FEA9A1ABE97631C828E41815F34FDCDF787419FE13A3137649AA93D2584230DF5F24B5C00C88B7D7DE4367693428C730376F218A53E853B0851BAB7C53C15DA7839CBE1285DB63F6FA45C1BB59FE1C5BB918F0F8459D7EF60ACFF5C0FA0F3FCAD1C5F4CE4416D4F4B36B05CDCEBE4FB879E95847EFBC6449CD190248843BC7EDB145FBFC4EDBB1A3C959298F08F3BA2CFBE231BBE204BE6F906209D28BD4820AB3E7BE96C26AE8A809ADD8D1A5A0B008E9570FA4C4697E116B8119892C604293683A9635F
--
cgit v1.2.3
From da0f783dce990e6c3953a7852a8c90a1933b21b2 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 6 Feb 2017 12:20:37 +0100
Subject: Revert "ssh: removed 'ssh-dss' from default list"
This reverts commit 6847d9223420fb86cdf72f0e608a5f41a2673053.
The removal of ssh-dss seems to give a too high risk of failing customer systems. Needs to be properly deprecated.
---
lib/ssh/src/ssh_transport.erl | 5 -----
1 file changed, 5 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 02209d5dfd..5d178a202d 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -84,11 +84,6 @@ default_algorithms(kex) ->
'diffie-hellman-group1-sha1' % Gone in OpenSSH 7.3.p1
]);
-default_algorithms(public_key) ->
- supported_algorithms(public_key, [
- 'ssh-dss' % Gone in OpenSSH 7.3.p1
- ]);
-
default_algorithms(cipher) ->
supported_algorithms(cipher, same(['AEAD_AES_128_GCM',
'AEAD_AES_256_GCM']));
--
cgit v1.2.3
From c6f98b68c6c3a390d7d087184a34448f79450530 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 8 Feb 2017 12:50:32 +0100
Subject: ssh: modify ssh_algorithms_SUITE:init_per_suite for some Windows
hangning
---
lib/ssh/test/ssh_algorithms_SUITE.erl | 19 ++++++++-----------
1 file changed, 8 insertions(+), 11 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_algorithms_SUITE.erl b/lib/ssh/test/ssh_algorithms_SUITE.erl
index 4327068b7b..313b7fc559 100644
--- a/lib/ssh/test/ssh_algorithms_SUITE.erl
+++ b/lib/ssh/test/ssh_algorithms_SUITE.erl
@@ -58,9 +58,11 @@ groups() ->
|| {Tag,Algs} <- ErlAlgos,
lists:member(Tag,tags())
],
+
+ TypeSSH = ssh_test_lib:ssh_type(),
AlgoTcSet =
- [{Alg, [parallel], specific_test_cases(Tag,Alg,SshcAlgos,SshdAlgos)}
+ [{Alg, [parallel], specific_test_cases(Tag,Alg,SshcAlgos,SshdAlgos,TypeSSH)}
|| {Tag,Algs} <- ErlAlgos ++ DoubleAlgos,
Alg <- Algs],
@@ -313,18 +315,13 @@ concat(A1, A2) -> list_to_atom(lists:concat([A1," + ",A2])).
split(Alg) -> ssh_test_lib:to_atoms(string:tokens(atom_to_list(Alg), " + ")).
-specific_test_cases(Tag, Alg, SshcAlgos, SshdAlgos) ->
+specific_test_cases(Tag, Alg, SshcAlgos, SshdAlgos, TypeSSH) ->
[simple_exec, simple_sftp] ++
case supports(Tag, Alg, SshcAlgos) of
- true ->
- case ssh_test_lib:ssh_type() of
- openSSH ->
- [sshc_simple_exec_os_cmd];
- _ ->
- []
- end;
- false ->
- []
+ true when TypeSSH == openSSH ->
+ [sshc_simple_exec_os_cmd];
+ _ ->
+ []
end ++
case supports(Tag, Alg, SshdAlgos) of
true ->
--
cgit v1.2.3
From 859ac82433da2dcd11685b8c8beb972336cf70cf Mon Sep 17 00:00:00 2001
From: Karolis Petrauskas
Date: Wed, 8 Feb 2017 15:06:43 +0200
Subject: Consider root_dir and cwd in ssh_sftpd, if both are provided
The SFTPD server should use root_dir and cwd when resolving
file paths, if both are provided. The root directory should
be used for resolving absolute file names, and cwd should
be used for resolving relative paths.
---
lib/ssh/src/ssh_sftpd.erl | 31 ++++++++++++++++++-------------
lib/ssh/test/ssh_sftpd_SUITE.erl | 39 ++++++++++++++++++++++++++++++++++++++-
2 files changed, 56 insertions(+), 14 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_sftpd.erl b/lib/ssh/src/ssh_sftpd.erl
index b739955836..bc30b7fb7d 100644
--- a/lib/ssh/src/ssh_sftpd.erl
+++ b/lib/ssh/src/ssh_sftpd.erl
@@ -742,6 +742,10 @@ resolve_symlinks_2([], State, _LinkCnt, AccPath) ->
{{ok, AccPath}, State}.
+%% The File argument is always in a user visible file system, i.e.
+%% is under Root and is relative to CWD or Root, if starts with "/".
+%% The result of the function is always an absolute path in a
+%% "backend" file system.
relate_file_name(File, State) ->
relate_file_name(File, State, _Canonicalize=true).
@@ -749,19 +753,20 @@ relate_file_name(File, State, Canonicalize) when is_binary(File) ->
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) ->
- case is_within_root(Root, File) of
- true ->
- File;
- false ->
- RelFile = make_relative_filename(File),
- NewFile = relate_filename_to_path(RelFile, Root, Canonicalize),
- case is_within_root(Root, NewFile) of
- true ->
- NewFile;
- false ->
- Root
- end
+relate_file_name(File, #state{cwd = CWD, root = Root}, Canonicalize) ->
+ CWD1 = case is_within_root(Root, CWD) of
+ true -> CWD;
+ false -> Root
+ end,
+ AbsFile = case make_relative_filename(File) of
+ File ->
+ relate_filename_to_path(File, CWD1, Canonicalize);
+ RelFile ->
+ relate_filename_to_path(RelFile, Root, Canonicalize)
+ end,
+ case is_within_root(Root, AbsFile) of
+ true -> AbsFile;
+ false -> Root
end.
is_within_root(Root, File) ->
diff --git a/lib/ssh/test/ssh_sftpd_SUITE.erl b/lib/ssh/test/ssh_sftpd_SUITE.erl
index 52a26110c4..a248c5e1e6 100644
--- a/lib/ssh/test/ssh_sftpd_SUITE.erl
+++ b/lib/ssh/test/ssh_sftpd_SUITE.erl
@@ -65,7 +65,8 @@ all() ->
ver3_open_flags,
relpath,
sshd_read_file,
- ver6_basic].
+ ver6_basic,
+ root_with_cwd].
groups() ->
[].
@@ -117,6 +118,11 @@ init_per_testcase(TestCase, Config) ->
ver6_basic ->
SubSystems = [ssh_sftpd:subsystem_spec([{sftpd_vsn, 6}])],
ssh:daemon(0, [{subsystems, SubSystems}|Options]);
+ root_with_cwd ->
+ RootDir = filename:join(PrivDir, root_with_cwd),
+ CWD = filename:join(RootDir, home),
+ SubSystems = [ssh_sftpd:subsystem_spec([{root, RootDir}, {cwd, CWD}])],
+ ssh:daemon(0, [{subsystems, SubSystems}|Options]);
_ ->
SubSystems = [ssh_sftpd:subsystem_spec([])],
ssh:daemon(0, [{subsystems, SubSystems}|Options])
@@ -646,6 +652,37 @@ ver6_basic(Config) when is_list(Config) ->
open_file(PrivDir, Cm, Channel, ReqId,
?ACE4_READ_DATA bor ?ACE4_READ_ATTRIBUTES,
?SSH_FXF_OPEN_EXISTING).
+
+%%--------------------------------------------------------------------
+root_with_cwd() ->
+ [{doc, "Check if files are found, if the CWD and Root are specified"}].
+root_with_cwd(Config) when is_list(Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ RootDir = filename:join(PrivDir, root_with_cwd),
+ CWD = filename:join(RootDir, home),
+ FileName = "root_with_cwd.txt",
+ FilePath = filename:join(CWD, FileName),
+ ok = filelib:ensure_dir(FilePath),
+ ok = file:write_file(FilePath ++ "0", <<>>),
+ ok = file:write_file(FilePath ++ "1", <<>>),
+ ok = file:write_file(FilePath ++ "2", <<>>),
+ {Cm, Channel} = proplists:get_value(sftp, Config),
+ ReqId0 = 0,
+ {ok, <>, _} =
+ open_file(FileName ++ "0", Cm, Channel, ReqId0,
+ ?ACE4_READ_DATA bor ?ACE4_READ_ATTRIBUTES,
+ ?SSH_FXF_OPEN_EXISTING),
+ ReqId1 = 1,
+ {ok, <>, _} =
+ open_file("./" ++ FileName ++ "1", Cm, Channel, ReqId1,
+ ?ACE4_READ_DATA bor ?ACE4_READ_ATTRIBUTES,
+ ?SSH_FXF_OPEN_EXISTING),
+ ReqId2 = 2,
+ {ok, <>, _} =
+ open_file("/home/" ++ FileName ++ "2", Cm, Channel, ReqId2,
+ ?ACE4_READ_DATA bor ?ACE4_READ_ATTRIBUTES,
+ ?SSH_FXF_OPEN_EXISTING).
+
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
--
cgit v1.2.3
From a34576111652d2d7972147160f93cfbbc9f13251 Mon Sep 17 00:00:00 2001
From: Karolis Petrauskas
Date: Tue, 7 Feb 2017 11:50:40 +0200
Subject: Fix relative path handling in sftpd
Relative path handling fixed to allow opening a file
by a path relative to the current working directory.
---
lib/ssh/src/ssh_sftpd.erl | 9 ++-------
lib/ssh/test/ssh_sftpd_SUITE.erl | 23 ++++++++++++++++++++++-
2 files changed, 24 insertions(+), 8 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_sftpd.erl b/lib/ssh/src/ssh_sftpd.erl
index b739955836..a6f4af7879 100644
--- a/lib/ssh/src/ssh_sftpd.erl
+++ b/lib/ssh/src/ssh_sftpd.erl
@@ -664,7 +664,7 @@ 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, xf = #ssh_xfer{vsn = Vsn}} = State0,
+ #state{file_handler = FileMod, file_state = FS0, xf = #ssh_xfer{vsn = Vsn}} = State0,
XF = State0#state.xf,
F = [binary | Flags],
{IsDir, _FS1} = FileMod:is_dir(Path, FS0),
@@ -676,12 +676,7 @@ do_open(ReqId, State0, Path, Flags) ->
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,
+ AbsPath = relate_file_name(Path, State0),
{Res, FS1} = FileMod:open(AbsPath, F, FS0),
State1 = State0#state{file_state = FS1},
case Res of
diff --git a/lib/ssh/test/ssh_sftpd_SUITE.erl b/lib/ssh/test/ssh_sftpd_SUITE.erl
index 52a26110c4..6d71b33c9b 100644
--- a/lib/ssh/test/ssh_sftpd_SUITE.erl
+++ b/lib/ssh/test/ssh_sftpd_SUITE.erl
@@ -65,7 +65,8 @@ all() ->
ver3_open_flags,
relpath,
sshd_read_file,
- ver6_basic].
+ ver6_basic,
+ relative_path].
groups() ->
[].
@@ -117,6 +118,9 @@ init_per_testcase(TestCase, Config) ->
ver6_basic ->
SubSystems = [ssh_sftpd:subsystem_spec([{sftpd_vsn, 6}])],
ssh:daemon(0, [{subsystems, SubSystems}|Options]);
+ relative_path ->
+ SubSystems = [ssh_sftpd:subsystem_spec([{cwd, PrivDir}])],
+ ssh:daemon(0, [{subsystems, SubSystems}|Options]);
_ ->
SubSystems = [ssh_sftpd:subsystem_spec([])],
ssh:daemon(0, [{subsystems, SubSystems}|Options])
@@ -646,6 +650,23 @@ ver6_basic(Config) when is_list(Config) ->
open_file(PrivDir, Cm, Channel, ReqId,
?ACE4_READ_DATA bor ?ACE4_READ_ATTRIBUTES,
?SSH_FXF_OPEN_EXISTING).
+
+%%--------------------------------------------------------------------
+relative_path() ->
+ [{doc, "Test paths relative to CWD when opening a file handle."}].
+relative_path(Config) when is_list(Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ FileName = "test_relative_path.txt",
+ FilePath = filename:join(PrivDir, FileName),
+ ok = filelib:ensure_dir(FilePath),
+ ok = file:write_file(FilePath, <<>>),
+ {Cm, Channel} = proplists:get_value(sftp, Config),
+ ReqId = 0,
+ {ok, <>, _} =
+ open_file(FileName, Cm, Channel, ReqId,
+ ?ACE4_READ_DATA bor ?ACE4_READ_ATTRIBUTES,
+ ?SSH_FXF_OPEN_EXISTING).
+
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
--
cgit v1.2.3
From 002e507bab9209aeb5487ee3a1dbe52a73f80f84 Mon Sep 17 00:00:00 2001
From: Karolis Petrauskas
Date: Sun, 12 Feb 2017 15:00:36 +0200
Subject: Check for directory with correct path
When opening file in the ssh_sftpd, directory check
should be performed on the server's file tree.
---
lib/ssh/src/ssh_sftpd.erl | 4 ++--
lib/ssh/test/ssh_sftpd_SUITE.erl | 45 +++++++++++++++++++++++++++++++++++++++-
2 files changed, 46 insertions(+), 3 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_sftpd.erl b/lib/ssh/src/ssh_sftpd.erl
index a6f4af7879..7ebe5ed4ef 100644
--- a/lib/ssh/src/ssh_sftpd.erl
+++ b/lib/ssh/src/ssh_sftpd.erl
@@ -667,7 +667,8 @@ do_open(ReqId, State0, Path, Flags) ->
#state{file_handler = FileMod, file_state = FS0, xf = #ssh_xfer{vsn = Vsn}} = State0,
XF = State0#state.xf,
F = [binary | Flags],
- {IsDir, _FS1} = FileMod:is_dir(Path, FS0),
+ AbsPath = relate_file_name(Path, State0),
+ {IsDir, _FS1} = FileMod:is_dir(AbsPath, FS0),
case IsDir of
true when Vsn > 5 ->
ssh_xfer:xf_send_status(State0#state.xf, ReqId,
@@ -676,7 +677,6 @@ do_open(ReqId, State0, Path, Flags) ->
ssh_xfer:xf_send_status(State0#state.xf, ReqId,
?SSH_FX_FAILURE, "File is a directory");
false ->
- AbsPath = relate_file_name(Path, State0),
{Res, FS1} = FileMod:open(AbsPath, F, FS0),
State1 = State0#state{file_state = FS1},
case Res of
diff --git a/lib/ssh/test/ssh_sftpd_SUITE.erl b/lib/ssh/test/ssh_sftpd_SUITE.erl
index 6d71b33c9b..380b01d32d 100644
--- a/lib/ssh/test/ssh_sftpd_SUITE.erl
+++ b/lib/ssh/test/ssh_sftpd_SUITE.erl
@@ -66,7 +66,9 @@ all() ->
relpath,
sshd_read_file,
ver6_basic,
- relative_path].
+ relative_path,
+ open_file_dir_v5,
+ open_file_dir_v6].
groups() ->
[].
@@ -121,6 +123,13 @@ init_per_testcase(TestCase, Config) ->
relative_path ->
SubSystems = [ssh_sftpd:subsystem_spec([{cwd, PrivDir}])],
ssh:daemon(0, [{subsystems, SubSystems}|Options]);
+ open_file_dir_v5 ->
+ SubSystems = [ssh_sftpd:subsystem_spec([{cwd, PrivDir}])],
+ ssh:daemon(0, [{subsystems, SubSystems}|Options]);
+ open_file_dir_v6 ->
+ SubSystems = [ssh_sftpd:subsystem_spec([{cwd, PrivDir},
+ {sftpd_vsn, 6}])],
+ ssh:daemon(0, [{subsystems, SubSystems}|Options]);
_ ->
SubSystems = [ssh_sftpd:subsystem_spec([])],
ssh:daemon(0, [{subsystems, SubSystems}|Options])
@@ -667,6 +676,40 @@ relative_path(Config) when is_list(Config) ->
?ACE4_READ_DATA bor ?ACE4_READ_ATTRIBUTES,
?SSH_FXF_OPEN_EXISTING).
+%%--------------------------------------------------------------------
+open_file_dir_v5() ->
+ [{doc, "Test if open_file fails when opening existing directory."}].
+open_file_dir_v5(Config) when is_list(Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ FileName = "open_file_dir_v5",
+ FilePath = filename:join(PrivDir, FileName),
+ ok = filelib:ensure_dir(FilePath),
+ ok = file:make_dir(FilePath),
+ {Cm, Channel} = proplists:get_value(sftp, Config),
+ ReqId = 0,
+ {ok, <>, _} =
+ open_file(FileName, Cm, Channel, ReqId,
+ ?ACE4_READ_DATA bor ?ACE4_READ_ATTRIBUTES,
+ ?SSH_FXF_OPEN_EXISTING).
+
+%%--------------------------------------------------------------------
+open_file_dir_v6() ->
+ [{doc, "Test if open_file fails when opening existing directory."}].
+open_file_dir_v6(Config) when is_list(Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ FileName = "open_file_dir_v6",
+ FilePath = filename:join(PrivDir, FileName),
+ ok = filelib:ensure_dir(FilePath),
+ ok = file:make_dir(FilePath),
+ {Cm, Channel} = proplists:get_value(sftp, Config),
+ ReqId = 0,
+ {ok, <>, _} =
+ open_file(FileName, Cm, Channel, ReqId,
+ ?ACE4_READ_DATA bor ?ACE4_READ_ATTRIBUTES,
+ ?SSH_FXF_OPEN_EXISTING).
+
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
--
cgit v1.2.3
From 4541b1f6c136bd2225ec6a6392454b2e5dddd6e9 Mon Sep 17 00:00:00 2001
From: Andrew Dryga
Date: Tue, 14 Feb 2017 11:28:34 +0200
Subject: Fixed typos in lib/ssh
---
lib/ssh/src/ssh_sftp.erl | 6 +++---
lib/ssh/src/ssh_transport.erl | 2 +-
lib/ssh/test/ssh_to_openssh_SUITE.erl | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_sftp.erl b/lib/ssh/src/ssh_sftp.erl
index b937f0412d..8d994cdb43 100644
--- a/lib/ssh/src/ssh_sftp.erl
+++ b/lib/ssh/src/ssh_sftp.erl
@@ -294,7 +294,7 @@ read(Pid, Handle, Len) ->
read(Pid, Handle, Len, FileOpTimeout) ->
call(Pid, {read,false,Handle, Len}, FileOpTimeout).
-%% TODO this ought to be a cast! Is so in all practial meaning
+%% TODO this ought to be a cast! Is so in all practical meaning
%% even if it is obscure!
apread(Pid, Handle, Offset, Len) ->
call(Pid, {pread,true,Handle, Offset, Len}, infinity).
@@ -313,12 +313,12 @@ write(Pid, Handle, Data) ->
write(Pid, Handle, Data, FileOpTimeout) ->
call(Pid, {write,false,Handle,Data}, FileOpTimeout).
-%% TODO this ought to be a cast! Is so in all practial meaning
+%% TODO this ought to be a cast! Is so in all practical meaning
%% even if it is obscure!
apwrite(Pid, Handle, Offset, Data) ->
call(Pid, {pwrite,true,Handle,Offset,Data}, infinity).
-%% TODO this ought to be a cast! Is so in all practial meaning
+%% TODO this ought to be a cast! Is so in all practical meaning
%% even if it is obscure!
awrite(Pid, Handle, Data) ->
call(Pid, {write,true,Handle,Data}, infinity).
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 5d178a202d..a17ad560d1 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -481,7 +481,7 @@ handle_kex_dh_gex_request(#ssh_msg_kex_dh_gex_request_old{n = NBits},
%% This message was in the draft-00 of rfc4419
%% (https://tools.ietf.org/html/draft-ietf-secsh-dh-group-exchange-00)
%% In later drafts and the rfc is "is used for backward compatibility".
- %% Unfortunatly the rfc does not specify how to treat the parameter n
+ %% Unfortunately the rfc does not specify how to treat the parameter n
%% if there is no group of that modulus length :(
%% The draft-00 however specifies that n is the "... number of bits
%% the subgroup should have at least".
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl
index 86c3d5de26..425b4d20f2 100644
--- a/lib/ssh/test/ssh_to_openssh_SUITE.erl
+++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl
@@ -442,7 +442,7 @@ erlang_server_openssh_client_renegotiate(Config) ->
ssh_test_lib:rcv_expected(Expect, OpenSsh, ?TIMEOUT)
of
_ ->
- %% Unfortunatly we can't check that there has been a renegotiation, just trust OpenSSH.
+ %% Unfortunately we can't check that there has been a renegotiation, just trust OpenSSH.
ssh:stop_daemon(Pid)
catch
throw:{skip,R} -> {skip,R}
--
cgit v1.2.3
From c1c1dc1d7f18ab5fceab5aa668627cf2960e5fb4 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 8 Feb 2017 17:30:49 +0100
Subject: ssh: new test - try access outside sftp tree
---
lib/ssh/test/ssh_sftpd_SUITE.erl | 60 ++++++++++++++++++++++++++++++++++++++--
1 file changed, 57 insertions(+), 3 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_sftpd_SUITE.erl b/lib/ssh/test/ssh_sftpd_SUITE.erl
index 52a26110c4..5616736f6e 100644
--- a/lib/ssh/test/ssh_sftpd_SUITE.erl
+++ b/lib/ssh/test/ssh_sftpd_SUITE.erl
@@ -65,7 +65,8 @@ all() ->
ver3_open_flags,
relpath,
sshd_read_file,
- ver6_basic].
+ ver6_basic,
+ access_outside_root].
groups() ->
[].
@@ -117,6 +118,16 @@ init_per_testcase(TestCase, Config) ->
ver6_basic ->
SubSystems = [ssh_sftpd:subsystem_spec([{sftpd_vsn, 6}])],
ssh:daemon(0, [{subsystems, SubSystems}|Options]);
+ access_outside_root ->
+ %% Build RootDir/access_outside_root/a/b and set Root and CWD
+ BaseDir = filename:join(PrivDir, access_outside_root),
+ RootDir = filename:join(BaseDir, a),
+ CWD = filename:join(RootDir, b),
+ %% Make the directory chain:
+ ok = filelib:ensure_dir(filename:join(CWD, tmp)),
+ SubSystems = [ssh_sftpd:subsystem_spec([{root, RootDir},
+ {cwd, CWD}])],
+ ssh:daemon(0, [{subsystems, SubSystems}|Options]);
_ ->
SubSystems = [ssh_sftpd:subsystem_spec([])],
ssh:daemon(0, [{subsystems, SubSystems}|Options])
@@ -646,6 +657,51 @@ ver6_basic(Config) when is_list(Config) ->
open_file(PrivDir, Cm, Channel, ReqId,
?ACE4_READ_DATA bor ?ACE4_READ_ATTRIBUTES,
?SSH_FXF_OPEN_EXISTING).
+
+%%--------------------------------------------------------------------
+access_outside_root(Config) when is_list(Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ BaseDir = filename:join(PrivDir, access_outside_root),
+ %% A file outside the tree below RootDir which is BaseDir/a
+ %% Make the file BaseDir/bad :
+ BadFilePath = filename:join([BaseDir, bad]),
+ ok = file:write_file(BadFilePath, <<>>),
+ {Cm, Channel} = proplists:get_value(sftp, Config),
+ %% Try to access a file parallell to the RootDir:
+ try_access("/../bad", Cm, Channel, 0),
+ %% Try to access the same file via the CWD which is /b relative to the RootDir:
+ try_access("../../bad", Cm, Channel, 1).
+
+
+try_access(Path, Cm, Channel, ReqId) ->
+ Return =
+ open_file(Path, Cm, Channel, ReqId,
+ ?ACE4_READ_DATA bor ?ACE4_READ_ATTRIBUTES,
+ ?SSH_FXF_OPEN_EXISTING),
+ ct:log("Try open ~p -> ~p",[Path,Return]),
+ case Return of
+ {ok, <>, _} ->
+ ct:fail("Could open a file outside the root tree!");
+ {ok, <>, <<>>} ->
+ case Code of
+ ?SSH_FX_FILE_IS_A_DIRECTORY ->
+ ct:pal("Got the expected SSH_FX_FILE_IS_A_DIRECTORY status",[]),
+ ok;
+ ?SSH_FX_FAILURE ->
+ ct:pal("Got the expected SSH_FX_FAILURE status",[]),
+ ok;
+ _ ->
+ case Rest of
+ <> ->
+ ct:fail("Got unexpected SSH_FX_code: ~p (~p)",[Code,Txt]);
+ _ ->
+ ct:fail("Got unexpected SSH_FX_code: ~p",[Code])
+ end
+ end;
+ _ ->
+ ct:fail("Completly unexpected return: ~p", [Return])
+ end.
+
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
@@ -688,9 +744,7 @@ reply(Cm, Channel, RBuf) ->
30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE])
end.
-
open_file(File, Cm, Channel, ReqId, Access, Flags) ->
-
Data = list_to_binary([?uint32(ReqId),
?binary(list_to_binary(File)),
?uint32(Access),
--
cgit v1.2.3
From 9f23065062eb724e58f39a65e416e5b0e1e9d95d Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 10 Feb 2017 14:37:41 +0100
Subject: ssh: allow a list of fingerprint algos in silently_accept_hosts
option
---
lib/ssh/doc/src/ssh.xml | 13 ++++++++++---
lib/ssh/src/ssh.erl | 21 ++++++++++++++++-----
lib/ssh/test/ssh_options_SUITE.erl | 26 +++++++++++++++++++-------
3 files changed, 45 insertions(+), 15 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index 6b49f89449..1a6bac8355 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -175,9 +175,11 @@
supplied with this option.
-
+
- boolean()]]>
+
+
+ boolean()]]>
-
When true, hosts are added to the
@@ -188,8 +190,13 @@
(PeerName, PeerHostKeyFingerPrint). The fingerprint is calculated on the Peer's Host Key with
public_key:ssh_hostkey_fingerprint/1.
- If the crypto:digest_type() is present, the fingerprint is calculated with that digest type by the function
+
If the HashAlgoSpec is present and is an crypto:digest_type(), the fingerprint is calculated
+ with that digest type by the function
public_key:ssh_hostkey_fingerprint/2.
+
+ If the HashAlgoSpec is present and is a list of crypto:digest_type(), the fingerprint is calulated for
+ each digest_type and PeerHostKeyFingerPrint is the list of the results in order corresponding to the
+ HashAlgoSpec.
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 31e343e81b..f408086c0f 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -620,11 +620,22 @@ handle_ssh_option({silently_accept_hosts, Value} = Opt) when is_boolean(Value) -
handle_ssh_option({silently_accept_hosts, Value} = Opt) when is_function(Value,2) ->
Opt;
handle_ssh_option({silently_accept_hosts, {DigestAlg,Value}} = Opt) when is_function(Value,2) ->
- case lists:member(DigestAlg, [md5, sha, sha224, sha256, sha384, sha512]) of
- true ->
- Opt;
- false ->
- throw({error, {eoptions, Opt}})
+ Algs = if is_atom(DigestAlg) -> [DigestAlg];
+ is_list(DigestAlg) -> DigestAlg;
+ true -> throw({error, {eoptions, Opt}})
+ end,
+ case [A || A <- Algs,
+ not lists:member(A, [md5, sha, sha224, sha256, sha384, sha512])] of
+ [_|_] = UnSup1 ->
+ throw({error, {{eoptions, Opt}, {not_fingerprint_algos,UnSup1}}});
+ [] ->
+ CryptoHashAlgs = proplists:get_value(hashs, crypto:supports(), []),
+ case [A || A <- Algs,
+ not lists:member(A, CryptoHashAlgs)] of
+ [_|_] = UnSup2 ->
+ throw({error, {{eoptions, Opt}, {unsupported_algo,UnSup2}}});
+ [] -> Opt
+ end
end;
handle_ssh_option({user_interaction, Value} = Opt) when is_boolean(Value) ->
Opt;
diff --git a/lib/ssh/test/ssh_options_SUITE.erl b/lib/ssh/test/ssh_options_SUITE.erl
index 86f5cb1746..d07c596411 100644
--- a/lib/ssh/test/ssh_options_SUITE.erl
+++ b/lib/ssh/test/ssh_options_SUITE.erl
@@ -67,7 +67,8 @@
hostkey_fingerprint_check_sha/1,
hostkey_fingerprint_check_sha256/1,
hostkey_fingerprint_check_sha384/1,
- hostkey_fingerprint_check_sha512/1
+ hostkey_fingerprint_check_sha512/1,
+ hostkey_fingerprint_check_list/1
]).
%%% Common test callbacks
@@ -112,6 +113,7 @@ all() ->
hostkey_fingerprint_check_sha256,
hostkey_fingerprint_check_sha384,
hostkey_fingerprint_check_sha512,
+ hostkey_fingerprint_check_list,
id_string_no_opt_client,
id_string_own_string_client,
id_string_random_client,
@@ -812,6 +814,8 @@ hostkey_fingerprint_check_sha384(Config) ->
hostkey_fingerprint_check_sha512(Config) ->
do_hostkey_fingerprint_check(Config, sha512).
+hostkey_fingerprint_check_list(Config) ->
+ do_hostkey_fingerprint_check(Config, [sha,md5,sha256]).
%%%----
do_hostkey_fingerprint_check(Config, HashAlg) ->
@@ -824,9 +828,10 @@ do_hostkey_fingerprint_check(Config, HashAlg) ->
supported_hash(old) -> true;
supported_hash(HashAlg) ->
- proplists:get_value(HashAlg,
- proplists:get_value(hashs, crypto:supports(), []),
- false).
+ Hs = if is_atom(HashAlg) -> [HashAlg];
+ is_list(HashAlg) -> HashAlg
+ end,
+ [] == (Hs -- proplists:get_value(hashs, crypto:supports(), [])).
really_do_hostkey_fingerprint_check(Config, HashAlg) ->
@@ -840,7 +845,7 @@ really_do_hostkey_fingerprint_check(Config, HashAlg) ->
%% All host key fingerprints. Trust that public_key has checked the ssh_hostkey_fingerprint
%% function since that function is used by the ssh client...
- FPs = [case HashAlg of
+ FPs0 = [case HashAlg of
old -> public_key:ssh_hostkey_fingerprint(Key);
_ -> public_key:ssh_hostkey_fingerprint(HashAlg, Key)
end
@@ -856,6 +861,9 @@ really_do_hostkey_fingerprint_check(Config, HashAlg) ->
_:_ -> []
end
end],
+ FPs = if is_atom(HashAlg) -> FPs0;
+ is_list(HashAlg) -> lists:concat(FPs0)
+ end,
ct:log("Fingerprints(~p) = ~p",[HashAlg,FPs]),
%% Start daemon with the public keys that we got fingerprints from
@@ -866,8 +874,12 @@ really_do_hostkey_fingerprint_check(Config, HashAlg) ->
FP_check_fun = fun(PeerName, FP) ->
ct:pal("PeerName = ~p, FP = ~p",[PeerName,FP]),
HostCheck = (Host == PeerName),
- FPCheck = lists:member(FP, FPs),
- ct:log("check ~p == ~p (~p) and ~n~p in ~p (~p)~n",
+ FPCheck =
+ if is_atom(HashAlg) -> lists:member(FP, FPs);
+ is_list(HashAlg) -> lists:all(fun(FP1) -> lists:member(FP1,FPs) end,
+ FP)
+ end,
+ ct:log("check ~p == ~p (~p) and ~n~p~n in ~p (~p)~n",
[PeerName,Host,HostCheck,FP,FPs,FPCheck]),
HostCheck and FPCheck
end,
--
cgit v1.2.3
From 1ca3a090fb9027aa140fea06f57aa22f8790940a Mon Sep 17 00:00:00 2001
From: Karolis Petrauskas
Date: Wed, 15 Feb 2017 08:24:32 +0200
Subject: Return correct state in the case of failure
---
lib/ssh/src/ssh_sftpd.erl | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_sftpd.erl b/lib/ssh/src/ssh_sftpd.erl
index 7ebe5ed4ef..13c68e4c95 100644
--- a/lib/ssh/src/ssh_sftpd.erl
+++ b/lib/ssh/src/ssh_sftpd.erl
@@ -665,23 +665,24 @@ open(Vsn, ReqId, Data, State) when Vsn >= 4 ->
do_open(ReqId, State0, Path, Flags) ->
#state{file_handler = FileMod, file_state = FS0, xf = #ssh_xfer{vsn = Vsn}} = State0,
- XF = State0#state.xf,
- F = [binary | Flags],
AbsPath = relate_file_name(Path, State0),
{IsDir, _FS1} = FileMod:is_dir(AbsPath, 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");
+ ?SSH_FX_FILE_IS_A_DIRECTORY, "File is a directory"),
+ State0;
true ->
ssh_xfer:xf_send_status(State0#state.xf, ReqId,
- ?SSH_FX_FAILURE, "File is a directory");
+ ?SSH_FX_FAILURE, "File is a directory"),
+ State0;
false ->
- {Res, FS1} = FileMod:open(AbsPath, F, FS0),
+ OpenFlags = [binary | Flags],
+ {Res, FS1} = FileMod:open(AbsPath, OpenFlags, FS0),
State1 = State0#state{file_state = FS1},
case Res of
{ok, IoDevice} ->
- add_handle(State1, XF, ReqId, file, {Path,IoDevice});
+ add_handle(State1, State0#state.xf, ReqId, file, {Path,IoDevice});
{error, Error} ->
ssh_xfer:xf_send_status(State1#state.xf, ReqId,
ssh_xfer:encode_erlang_status(Error)),
--
cgit v1.2.3
From 82a5b5f3b8824ab7c1da403c3a40bcf0fc98c690 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 15 Feb 2017 13:26:18 +0100
Subject: ssh: reword documentation
---
lib/ssh/doc/src/ssh.xml | 61 ++++++++++++++++++++++++++++++++-----------------
1 file changed, 40 insertions(+), 21 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index 1a6bac8355..e42f16ebd0 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -153,7 +153,7 @@
-
IP version to use.
-
+
-
Sets the user directory, that is, the directory containing
ssh configuration files for the user, such as
@@ -175,29 +175,48 @@
supplied with this option.
-
-
-
-
- boolean()]]>
+
+
+
+
+
+
+ boolean()]]>
+
+
-
-
When true, hosts are added to the
- file without asking the user.
- Defaults to false which will give a user question on stdio of whether to accept or reject a previously
- unseen host.
- If the option value is has an accept_fun(), that fun will called with the arguments
- (PeerName, PeerHostKeyFingerPrint). The fingerprint is calculated on the Peer's Host Key with
- public_key:ssh_hostkey_fingerprint/1.
-
- If the HashAlgoSpec is present and is an crypto:digest_type(), the fingerprint is calculated
- with that digest type by the function
- public_key:ssh_hostkey_fingerprint/2.
+
This option guides the connect function how to act when the connected server presents a Host
+ Key that the client has not seen before. The default is to ask the user with a question on stdio of whether to
+ accept or reject the new Host Key.
+ See also the option user_dir
+ for the path to the file known_hosts where previously accepted Host Keys are recorded.
- If the HashAlgoSpec is present and is a list of crypto:digest_type(), the fingerprint is calulated for
- each digest_type and PeerHostKeyFingerPrint is the list of the results in order corresponding to the
- HashAlgoSpec.
-
+ The option can be given in three different forms as seen above:
+
+ - The value is a boolean(). The value true will make the client accept any unknown
+ Host Key without any user interaction. The value false keeps the default behaviour of asking the
+ the user on stdio.
+
+ - A CallbackFun will be called and the boolean return value true will make the client
+ accept the Host Key. A reurn value of false will make the client to reject the Host Key and therefore
+ also the connection will be closed. The arguments to the fun are:
+
+ - PeerName - a string with the name or address of the remote host.
+ - FingerPrint - the fingerprint of the Host Key as
+ public_key:ssh_hostkey_fingerprint/1
+ calculates it.
+
+
+
+ - A tuple {HashAlgoSpec, CallbackFun}. The HashAlgoSpec specifies which hash algorithm
+ shall be used to calculate the fingerprint used in the call of the CallbackFun. The HashALgoSpec
+ is either an atom or a list of atoms as the first argument in
+ public_key:ssh_hostkey_fingerprint/2.
+ If it is a list of hash algorithm names, the FingerPrint argument in the CallbackFun will be
+ a list of fingerprints in the same order as the corresponding name in the HashAlgoSpec list.
+
+
-
--
cgit v1.2.3
From 2869472d38814d8ab5f034e383c7aa063aab4618 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 15 Feb 2017 13:29:32 +0100
Subject: ssh: speling error
---
lib/ssh/doc/src/ssh.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index e42f16ebd0..20508a73a6 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -226,7 +226,7 @@
supplying a password. Defaults to true.
Even if user interaction is allowed it can be
suppressed by other options, such as silently_accept_hosts
- and password. However, those optins are not always desirable
+ and password. However, those options are not always desirable
to use from a security point of view.
--
cgit v1.2.3
From 5fa9ae3f7cce55047061b94f35940d6eaf94d9ee Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 15 Feb 2017 13:34:16 +0100
Subject: ssh: speling error
---
lib/ssh/doc/src/ssh.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index 20508a73a6..f6e26f5ee8 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -199,7 +199,7 @@
the user on stdio.
- A CallbackFun will be called and the boolean return value true will make the client
- accept the Host Key. A reurn value of false will make the client to reject the Host Key and therefore
+ accept the Host Key. A return value of false will make the client to reject the Host Key and therefore
also the connection will be closed. The arguments to the fun are:
- PeerName - a string with the name or address of the remote host.
--
cgit v1.2.3
From d21031900160a70408f0ee6f1b2f8bd01f1cbde7 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 15 Feb 2017 15:12:37 +0100
Subject: ssh: Add error case for bad socket
---
lib/ssh/src/ssh.erl | 2 ++
1 file changed, 2 insertions(+)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 31e343e81b..8d8e20730d 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -317,6 +317,7 @@ start_daemon(Socket, Options) ->
do_start_daemon(Socket, [{role,server}|SshOptions], SocketOptions)
catch
throw:bad_fd -> {error,bad_fd};
+ throw:bad_socket -> {error,bad_socket};
_C:_E -> {error,{cannot_start_daemon,_C,_E}}
end;
{error,SockError} ->
@@ -333,6 +334,7 @@ start_daemon(Host, Port, Options, Inet) ->
do_start_daemon(Host, Port, [{role,server}|SshOptions] , [Inet|SocketOptions])
catch
throw:bad_fd -> {error,bad_fd};
+ throw:bad_socket -> {error,bad_socket};
_C:_E -> {error,{cannot_start_daemon,_C,_E}}
end
end.
--
cgit v1.2.3
From cd88d70ffb0f325fa84c8548b3dca1f7865ee86d Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 15 Feb 2017 15:13:54 +0100
Subject: ssh: More exact test for is_tcp_socket
---
lib/ssh/src/ssh.erl | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 8d8e20730d..657cf4c62d 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -280,9 +280,11 @@ valid_socket_to_use(Socket, Options) ->
{error, {unsupported,L4}}
end.
-is_tcp_socket(Socket) -> {ok,[]} =/= inet:getopts(Socket, [delay_send]).
-
-
+is_tcp_socket(Socket) ->
+ case inet:getopts(Socket, [delay_send]) of
+ {ok,[_]} -> true;
+ _ -> false
+ end.
daemon_shell_opt(Options) ->
case proplists:get_value(shell, Options) of
--
cgit v1.2.3
From 8fbb5b7c55c78f5696a3c504a1f7c164d5be3dc3 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 15 Feb 2017 17:00:09 +0100
Subject: ssh: handle return values and exceptions from
ssh_acceptor:handle_connection
---
lib/ssh/src/ssh.erl | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 657cf4c62d..f572e02d5f 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -366,8 +366,7 @@ do_start_daemon(Socket, SshOptions, SocketOptions) ->
{error, {already_started, _}} ->
{error, eaddrinuse};
Result = {ok,_} ->
- ssh_acceptor:handle_connection(Callback, Host, Port, Opts, Socket),
- Result;
+ call_ssh_acceptor_handle_connection(Callback, Host, Port, Opts, Socket, Result);
Result = {error, _} ->
Result
catch
@@ -380,8 +379,7 @@ do_start_daemon(Socket, SshOptions, SocketOptions) ->
{error, {already_started, _}} ->
{error, eaddrinuse};
{ok, _} ->
- ssh_acceptor:handle_connection(Callback, Host, Port, Opts, Socket),
- {ok, Sup};
+ call_ssh_acceptor_handle_connection(Callback, Host, Port, Opts, Socket, {ok, Sup});
Other ->
Other
end
@@ -451,6 +449,16 @@ do_start_daemon(Host0, Port0, SshOptions, SocketOptions) ->
end
end.
+call_ssh_acceptor_handle_connection(Callback, Host, Port, Opts, Socket, DefaultResult) ->
+ try ssh_acceptor:handle_connection(Callback, Host, Port, Opts, Socket)
+ of
+ {error,Error} -> {error,Error};
+ _ -> DefaultResult
+ catch
+ C:R -> {error,{could_not_start_connection,{C,R}}}
+ end.
+
+
sync_request_control(false) ->
ok;
sync_request_control({LSock,Callback}) ->
--
cgit v1.2.3
From e001bf6951b9a02d0a9a0c6ca1ea4f364713ac4c Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 17 Feb 2017 12:16:08 +0100
Subject: ssh: increase timetrap in ssh_to_openssh_SUITE to not interrupt some
slow machines
---
lib/ssh/test/ssh_to_openssh_SUITE.erl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl
index 86c3d5de26..b6f4a7371d 100644
--- a/lib/ssh/test/ssh_to_openssh_SUITE.erl
+++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl
@@ -36,7 +36,7 @@
%%--------------------------------------------------------------------
suite() ->
- [{timetrap,{seconds,20}}].
+ [{timetrap,{seconds,60}}].
all() ->
case os:find_executable("ssh") of
--
cgit v1.2.3
From de437e3639912a0570541fa10c473ac0f0372806 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 17 Feb 2017 14:08:15 +0100
Subject: ssh: replace byte-only function with element-size agnostic
An error report on ssh_cli pointed to a usage of erlang:iolist_size/1. It is replaced by a specialized function.
---
lib/ssh/src/ssh_cli.erl | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_cli.erl b/lib/ssh/src/ssh_cli.erl
index 8af0ecc5f9..6f8c050486 100644
--- a/lib/ssh/src/ssh_cli.erl
+++ b/lib/ssh/src/ssh_cli.erl
@@ -453,14 +453,20 @@ move_cursor(From, To, #ssh_pty{width=Width, term=Type}) ->
%% %%% make sure that there is data to send
%% %%% before calling ssh_connection:send
write_chars(ConnectionHandler, ChannelId, Chars) ->
- case erlang:iolist_size(Chars) of
- 0 ->
- ok;
- _ ->
- ssh_connection:send(ConnectionHandler, ChannelId,
- ?SSH_EXTENDED_DATA_DEFAULT, Chars)
+ case has_chars(Chars) of
+ false -> ok;
+ true -> ssh_connection:send(ConnectionHandler,
+ ChannelId,
+ ?SSH_EXTENDED_DATA_DEFAULT,
+ Chars)
end.
+has_chars([C|_]) when is_integer(C) -> true;
+has_chars([H|T]) when is_list(H) ; is_binary(H) -> has_chars(H) orelse has_chars(T);
+has_chars(<<_:8,_/binary>>) -> true;
+has_chars(_) -> false.
+
+
%%% tail, works with empty lists
tl1([_|A]) -> A;
tl1(_) -> [].
--
cgit v1.2.3
From 82b661fb3aa20c6051dc968baf7815b1b2958d6f Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 24 Feb 2017 13:18:57 +0100
Subject: ssh: increase timetrap for test on slow machine
---
lib/ssh/test/ssh_algorithms_SUITE.erl | 3 +++
1 file changed, 3 insertions(+)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_algorithms_SUITE.erl b/lib/ssh/test/ssh_algorithms_SUITE.erl
index 313b7fc559..6f75d83c4a 100644
--- a/lib/ssh/test/ssh_algorithms_SUITE.erl
+++ b/lib/ssh/test/ssh_algorithms_SUITE.erl
@@ -200,6 +200,9 @@ try_exec_simple_group(Group, Config) ->
%%--------------------------------------------------------------------
%% Testing all default groups
+simple_exec_groups() ->
+ [{timetrap,{seconds,120}}].
+
simple_exec_groups(Config) ->
Sizes = interpolate( public_key:dh_gex_group_sizes() ),
lists:foreach(
--
cgit v1.2.3
From 73e380177532af093edf3b27926967fefc9dcb0b Mon Sep 17 00:00:00 2001
From: Malcolm
Date: Sun, 26 Feb 2017 20:37:18 +0000
Subject: Documentation: use behaviour(ssh_daemon_channel)
In the SSH User's Guide, section 2.8 'Creating a Subsystem' uses
behaviour(ssh_subsystem) but should use behaviour(ssh_daemon_channel).
The renaming was updated in the Reference Manual but never reflected
in the User's Guide.
---
lib/ssh/doc/src/using_ssh.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/using_ssh.xml b/lib/ssh/doc/src/using_ssh.xml
index 0861c641c7..864378b640 100644
--- a/lib/ssh/doc/src/using_ssh.xml
+++ b/lib/ssh/doc/src/using_ssh.xml
@@ -305,7 +305,7 @@ ok = erl_tar:close(HandleRead),
-module(ssh_echo_server).
--behaviour(ssh_subsystem).
+-behaviour(ssh_daemon_channel).
-record(state, {
n,
id,
--
cgit v1.2.3
From cba9c49ee26a848a8dac7971b4c8edf39f9f0bf0 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 27 Feb 2017 12:23:32 +0100
Subject: ssh: Print Pids in testcase for debugging
---
lib/ssh/test/ssh_to_openssh_SUITE.erl | 1 +
1 file changed, 1 insertion(+)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl
index b6f4a7371d..0b9b7acde8 100644
--- a/lib/ssh/test/ssh_to_openssh_SUITE.erl
+++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl
@@ -464,6 +464,7 @@ erlang_client_openssh_server_renegotiate(_Config) ->
{silently_accept_hosts,true}],
group_leader(IO, self()),
{ok, ConnRef} = ssh:connect(Host, ?SSH_DEFAULT_PORT, Options),
+ ct:pal("Parent = ~p, IO = ~p, Shell = ~p, ConnRef = ~p~n",[Parent, IO, self(), ConnRef]),
case ssh_connection:session_channel(ConnRef, infinity) of
{ok,ChannelId} ->
success = ssh_connection:ptty_alloc(ConnRef, ChannelId, []),
--
cgit v1.2.3
From 89a829f32d855610b0bc0c3ea53e7c05454b7a24 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 16 Feb 2017 14:48:04 +0100
Subject: ssh: Initial commit of option handling changes
---
lib/ssh/src/Makefile | 1 +
lib/ssh/src/ssh.app.src | 1 +
lib/ssh/src/ssh.erl | 817 ++++++------------------------
lib/ssh/src/ssh.hrl | 27 +-
lib/ssh/src/ssh_acceptor.erl | 117 +++--
lib/ssh/src/ssh_acceptor_sup.erl | 28 +-
lib/ssh/src/ssh_auth.erl | 79 ++-
lib/ssh/src/ssh_cli.erl | 12 +-
lib/ssh/src/ssh_connection.erl | 38 +-
lib/ssh/src/ssh_connection_handler.erl | 124 +++--
lib/ssh/src/ssh_file.erl | 4 +-
lib/ssh/src/ssh_io.erl | 16 +-
lib/ssh/src/ssh_options.erl | 897 +++++++++++++++++++++++++++++++++
lib/ssh/src/ssh_sftp.erl | 43 +-
lib/ssh/src/ssh_subsystem_sup.erl | 36 +-
lib/ssh/src/ssh_system_sup.erl | 34 +-
lib/ssh/src/ssh_transport.erl | 72 +--
lib/ssh/src/sshd_sup.erl | 22 +-
lib/ssh/test/ssh_trpt_test_lib.erl | 30 +-
19 files changed, 1385 insertions(+), 1013 deletions(-)
create mode 100644 lib/ssh/src/ssh_options.erl
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/Makefile b/lib/ssh/src/Makefile
index 7ab6f22424..f826fdfd9b 100644
--- a/lib/ssh/src/Makefile
+++ b/lib/ssh/src/Makefile
@@ -51,6 +51,7 @@ MODULES= \
ssh_sup \
sshc_sup \
sshd_sup \
+ ssh_options \
ssh_connection_sup \
ssh_connection \
ssh_connection_handler \
diff --git a/lib/ssh/src/ssh.app.src b/lib/ssh/src/ssh.app.src
index 2bb7491b0c..95d2686094 100644
--- a/lib/ssh/src/ssh.app.src
+++ b/lib/ssh/src/ssh.app.src
@@ -7,6 +7,7 @@
ssh_app,
ssh_acceptor,
ssh_acceptor_sup,
+ ssh_options,
ssh_auth,
ssh_message,
ssh_bits,
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 68d98d3875..0186ac7922 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -41,7 +41,8 @@
%%% Type exports
-export_type([connection_ref/0,
- channel_id/0
+ channel_id/0,
+ role/0
]).
%%--------------------------------------------------------------------
@@ -71,55 +72,63 @@ stop() ->
application:stop(ssh).
%%--------------------------------------------------------------------
--spec connect(port(), proplists:proplist()) -> {ok, pid()} | {error, term()}.
+-spec connect(inet:socket(), proplists:proplist()) -> ok_error(connection_ref()).
--spec connect(port(), proplists:proplist(), timeout()) -> {ok, pid()} | {error, term()}
- ; (string(), integer(), proplists:proplist()) -> {ok, pid()} | {error, term()}.
+-spec connect(inet:socket(), proplists:proplist(), timeout()) -> ok_error(connection_ref())
+ ; (string(), inet:port_number(), proplists:proplist()) -> ok_error(connection_ref()).
+
+-spec connect(string(), inet:port_number(), proplists:proplist(), timeout()) -> ok_error(connection_ref()).
--spec connect(string(), integer(), proplists:proplist(), timeout()) -> {ok, pid()} | {error, term()}.
%%
%% Description: Starts an ssh connection.
%%--------------------------------------------------------------------
-connect(Socket, Options) ->
- connect(Socket, Options, infinity).
+connect(Socket, UserOptions) when is_port(Socket),
+ is_list(UserOptions) ->
+ connect(Socket, UserOptions, infinity).
-connect(Socket, Options, Timeout) when is_port(Socket) ->
- case handle_options(Options) of
+connect(Socket, UserOptions, Timeout) when is_port(Socket),
+ is_list(UserOptions) ->
+ case ssh_options:handle_options(client, UserOptions) of
{error, Error} ->
{error, Error};
- {_SocketOptions, SshOptions} ->
- case valid_socket_to_use(Socket, Options) of
+ Options ->
+ case valid_socket_to_use(Socket, ?GET_OPT(transport,Options)) of
ok ->
{ok, {Host,_Port}} = inet:sockname(Socket),
- Opts = [{user_pid,self()}, {host,fmt_host(Host)} | SshOptions],
+ Opts = ?PUT_INTERNAL_OPT([{user_pid,self()}, {host,fmt_host(Host)}], Options),
ssh_connection_handler:start_connection(client, Socket, Opts, Timeout);
{error,SockError} ->
{error,SockError}
end
end;
-connect(Host, Port, Options) when is_integer(Port), Port>0 ->
- connect(Host, Port, Options, infinity).
+connect(Host, Port, UserOptions) when is_integer(Port),
+ Port>0,
+ is_list(UserOptions) ->
+ connect(Host, Port, UserOptions, infinity).
-connect(Host, Port, Options, Timeout) ->
- case handle_options(Options) of
+connect(Host, Port, UserOptions, Timeout) when is_integer(Port),
+ Port>0,
+ is_list(UserOptions) ->
+ case ssh_options:handle_options(client, UserOptions) of
{error, _Reason} = Error ->
Error;
- {SocketOptions, SshOptions} ->
- {_, Transport, _} = TransportOpts =
- proplists:get_value(transport, Options, {tcp, gen_tcp, tcp_closed}),
- ConnectionTimeout = proplists:get_value(connect_timeout, Options, infinity),
- try Transport:connect(Host, Port, [ {active, false} | SocketOptions], ConnectionTimeout) of
+ Options ->
+ {_, Transport, _} = TransportOpts = ?GET_OPT(transport, Options),
+ ConnectionTimeout = ?GET_OPT(connect_timeout, Options),
+ SocketOpts = [{active,false} | ?GET_OPT(socket_options,Options)],
+ try Transport:connect(Host, Port, SocketOpts, ConnectionTimeout) of
{ok, Socket} ->
- Opts = [{user_pid,self()}, {host,Host} | SshOptions],
+ Opts = ?PUT_INTERNAL_OPT([{user_pid,self()}, {host,Host}], Options),
ssh_connection_handler:start_connection(client, Socket, Opts, Timeout);
{error, Reason} ->
{error, Reason}
catch
- exit:{function_clause, _} ->
+ exit:{function_clause, _F} ->
+ io:format('function_clause ~p~n',[_F]),
{error, {options, {transport, TransportOpts}}};
exit:badarg ->
- {error, {options, {socket_options, SocketOptions}}}
+ {error, {options, {socket_options, SocketOpts}}}
end
end.
@@ -148,9 +157,11 @@ channel_info(ConnectionRef, ChannelId, Options) ->
ssh_connection_handler:channel_info(ConnectionRef, ChannelId, Options).
%%--------------------------------------------------------------------
--spec daemon(integer()) -> {ok, pid()} | {error, term()}.
--spec daemon(integer()|port(), proplists:proplist()) -> {ok, pid()} | {error, term()}.
--spec daemon(any | inet:ip_address(), integer(), proplists:proplist()) -> {ok, pid()} | {error, term()}.
+-spec daemon(inet:port_number()) -> ok_error(pid()).
+-spec daemon(inet:port_number()|inet:socket(), proplists:proplist()) -> ok_error(pid()).
+-spec daemon(any | inet:ip_address(), inet:port_number(), proplists:proplist()) -> ok_error(pid())
+ ;(socket, inet:socket(), proplists:proplist()) -> ok_error(pid())
+ .
%% Description: Starts a server listening for SSH connections
%% on the given port.
@@ -158,19 +169,21 @@ channel_info(ConnectionRef, ChannelId, Options) ->
daemon(Port) ->
daemon(Port, []).
-daemon(Port, Options) when is_integer(Port) ->
- daemon(any, Port, Options);
-daemon(Socket, Options0) when is_port(Socket) ->
- Options = daemon_shell_opt(Options0),
- start_daemon(Socket, Options).
+daemon(Port, UserOptions) when is_integer(Port), Port >= 0 ->
+ daemon(any, Port, UserOptions);
+
+daemon(Socket, UserOptions) when is_port(Socket) ->
+ daemon(socket, Socket, UserOptions).
+
-daemon(HostAddr, Port, Options0) ->
- Options1 = daemon_shell_opt(Options0),
- {Host, Inet, Options} = daemon_host_inet_opt(HostAddr, Options1),
- start_daemon(Host, Port, Options, Inet).
+daemon(Host0, Port, UserOptions0) ->
+ {Host, UserOptions} = handle_daemon_args(Host0, UserOptions0),
+ start_daemon(Host, Port, ssh_options:handle_options(server, UserOptions)).
%%--------------------------------------------------------------------
+-spec daemon_info(pid()) -> ok_error( [{atom(), term()}] ).
+
daemon_info(Pid) ->
case catch ssh_system_sup:acceptor_supervisor(Pid) of
AsupPid when is_pid(AsupPid) ->
@@ -185,7 +198,7 @@ daemon_info(Pid) ->
%%--------------------------------------------------------------------
-spec stop_listener(pid()) -> ok.
--spec stop_listener(inet:ip_address(), integer()) -> ok.
+-spec stop_listener(inet:ip_address(), inet:port_number()) -> ok.
%%
%% Description: Stops the listener, but leaves
%% existing connections started by the listener up and running.
@@ -199,7 +212,8 @@ stop_listener(Address, Port, Profile) ->
%%--------------------------------------------------------------------
-spec stop_daemon(pid()) -> ok.
--spec stop_daemon(inet:ip_address(), integer()) -> ok.
+-spec stop_daemon(inet:ip_address(), inet:port_number()) -> ok.
+-spec stop_daemon(inet:ip_address(), inet:port_number(), atom()) -> ok.
%%
%% Description: Stops the listener and all connections started by
%% the listener.
@@ -210,10 +224,11 @@ stop_daemon(Address, Port) ->
ssh_system_sup:stop_system(Address, Port, ?DEFAULT_PROFILE).
stop_daemon(Address, Port, Profile) ->
ssh_system_sup:stop_system(Address, Port, Profile).
+
%%--------------------------------------------------------------------
--spec shell(port() | string()) -> _.
--spec shell(port() | string(), proplists:proplist()) -> _.
--spec shell(string(), integer(), proplists:proplist()) -> _.
+-spec shell(inet:socket() | string()) -> _.
+-spec shell(inet:socket() | string(), proplists:proplist()) -> _.
+-spec shell(string(), inet:port_number(), proplists:proplist()) -> _.
%% Host = string()
%% Port = integer()
@@ -261,112 +276,96 @@ default_algorithms() ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
-valid_socket_to_use(Socket, Options) ->
- case proplists:get_value(transport, Options, {tcp, gen_tcp, tcp_closed}) of
- {tcp,_,_} ->
- %% Is this tcp-socket a valid socket?
- case {is_tcp_socket(Socket),
- {ok,[{active,false}]} == inet:getopts(Socket, [active])
- }
- of
- {true, true} ->
- ok;
- {true, false} ->
- {error, not_passive_mode};
- _ ->
- {error, not_tcp_socket}
- end;
- {L4,_,_} ->
- {error, {unsupported,L4}}
+handle_daemon_args(Host, UserOptions0) ->
+ case Host of
+ socket ->
+ {Host, UserOptions0};
+ any ->
+ {ok, Host0} = inet:gethostname(),
+ Inet = proplists:get_value(inet, UserOptions0, inet),
+ {Host0, [Inet | UserOptions0]};
+ {_,_,_,_} ->
+ {Host, [inet, {ip,Host} | UserOptions0]};
+ {_,_,_,_,_,_,_,_} ->
+ {Host, [inet6, {ip,Host} | UserOptions0]};
+ _ ->
+ error(badarg)
end.
+%%%----------------------------------------------------------------
+valid_socket_to_use(Socket, {tcp,_,_}) ->
+ %% Is this tcp-socket a valid socket?
+ case {is_tcp_socket(Socket),
+ {ok,[{active,false}]} == inet:getopts(Socket, [active])
+ }
+ of
+ {true, true} ->
+ ok;
+ {true, false} ->
+ {error, not_passive_mode};
+ _ ->
+ {error, not_tcp_socket}
+ end;
+
+valid_socket_to_use(_, {L4,_,_}) ->
+ {error, {unsupported,L4}}.
+
+
is_tcp_socket(Socket) ->
case inet:getopts(Socket, [delay_send]) of
{ok,[_]} -> true;
_ -> false
end.
-daemon_shell_opt(Options) ->
- case proplists:get_value(shell, Options) of
- undefined ->
- [{shell, {shell, start, []}} | Options];
- _ ->
- Options
- end.
-
-daemon_host_inet_opt(HostAddr, Options1) ->
- case HostAddr of
- any ->
- {ok, Host0} = inet:gethostname(),
- {Host0, proplists:get_value(inet, Options1, inet), Options1};
- {_,_,_,_} ->
- {HostAddr, inet,
- [{ip, HostAddr} | Options1]};
- {_,_,_,_,_,_,_,_} ->
- {HostAddr, inet6,
- [{ip, HostAddr} | Options1]}
- end.
-
+%%%----------------------------------------------------------------
+start_daemon(_, _, {error,Error}) ->
+ {error,Error};
+
+start_daemon(socket, Socket, Options) ->
+ case valid_socket_to_use(Socket, ?GET_OPT(transport,Options)) of
+ ok ->
+ try
+ do_start_daemon(Socket, Options)
+ catch
+ throw:bad_fd -> {error,bad_fd};
+ throw:bad_socket -> {error,bad_socket};
+ _C:_E -> {error,{cannot_start_daemon,_C,_E}}
+ end;
+ {error,SockError} ->
+ {error,SockError}
+ end;
-start_daemon(Socket, Options) ->
- case handle_options(Options) of
- {error, Error} ->
- {error, Error};
- {SocketOptions, SshOptions} ->
- case valid_socket_to_use(Socket, Options) of
- ok ->
- try
- do_start_daemon(Socket, [{role,server}|SshOptions], SocketOptions)
- catch
- throw:bad_fd -> {error,bad_fd};
- throw:bad_socket -> {error,bad_socket};
- _C:_E -> {error,{cannot_start_daemon,_C,_E}}
- end;
- {error,SockError} ->
- {error,SockError}
- end
+start_daemon(Host, Port, Options) ->
+ try
+ do_start_daemon(Host, Port, Options)
+ catch
+ throw:bad_fd -> {error,bad_fd};
+ throw:bad_socket -> {error,bad_socket};
+ _C:_E -> {error,{cannot_start_daemon,_C,_E}}
end.
-start_daemon(Host, Port, Options, Inet) ->
- case handle_options(Options) of
- {error, _Reason} = Error ->
- Error;
- {SocketOptions, SshOptions}->
- try
- do_start_daemon(Host, Port, [{role,server}|SshOptions] , [Inet|SocketOptions])
- catch
- throw:bad_fd -> {error,bad_fd};
- throw:bad_socket -> {error,bad_socket};
- _C:_E -> {error,{cannot_start_daemon,_C,_E}}
- end
- end.
-do_start_daemon(Socket, SshOptions, SocketOptions) ->
+do_start_daemon(Socket, Options) ->
{ok, {IP,Port}} =
try {ok,_} = inet:sockname(Socket)
catch
_:_ -> throw(bad_socket)
end,
Host = fmt_host(IP),
- Profile = proplists:get_value(profile, SshOptions, ?DEFAULT_PROFILE),
- Opts = [{asocket, Socket},
- {asock_owner,self()},
- {address, Host},
- {port, Port},
- {role, server},
- {socket_opts, SocketOptions},
- {ssh_opts, SshOptions}],
- {_, Callback, _} = proplists:get_value(transport, SshOptions, {tcp, gen_tcp, tcp_closed}),
+ Opts = ?PUT_INTERNAL_OPT([{asocket, Socket},
+ {asock_owner,self()},
+ {address, Host},
+ {port, Port},
+ {role, server}], Options),
+
+ Profile = ?GET_OPT(profile, Options),
case ssh_system_sup:system_supervisor(Host, Port, Profile) of
undefined ->
- %% It would proably make more sense to call the
- %% address option host but that is a too big change at the
- %% monent. The name is a legacy name!
try sshd_sup:start_child(Opts) of
{error, {already_started, _}} ->
{error, eaddrinuse};
Result = {ok,_} ->
- call_ssh_acceptor_handle_connection(Callback, Host, Port, Opts, Socket, Result);
+ call_ssh_acceptor_handle_connection(Host, Port, Opts, Socket, Result);
Result = {error, _} ->
Result
catch
@@ -379,56 +378,47 @@ do_start_daemon(Socket, SshOptions, SocketOptions) ->
{error, {already_started, _}} ->
{error, eaddrinuse};
{ok, _} ->
- call_ssh_acceptor_handle_connection(Callback, Host, Port, Opts, Socket, {ok, Sup});
+ call_ssh_acceptor_handle_connection(Host, Port, Opts, Socket, {ok,Sup});
Other ->
Other
end
end.
-do_start_daemon(Host0, Port0, SshOptions, SocketOptions) ->
+do_start_daemon(Host0, Port0, Options0) ->
{Host,Port1} =
try
- case proplists:get_value(fd, SocketOptions) of
+ case ?GET_SOCKET_OPT(fd, Options0) of
undefined ->
{Host0,Port0};
Fd when Port0==0 ->
- find_hostport(Fd);
- _ ->
- {Host0,Port0}
+ find_hostport(Fd)
end
catch
_:_ -> throw(bad_fd)
end,
- Profile = proplists:get_value(profile, SshOptions, ?DEFAULT_PROFILE),
- {Port, WaitRequestControl, Opts0} =
+ {Port, WaitRequestControl, Options1} =
case Port1 of
0 -> %% Allocate the socket here to get the port number...
- {_, Callback, _} =
- proplists:get_value(transport, SshOptions, {tcp, gen_tcp, tcp_closed}),
- {ok,LSock} = ssh_acceptor:callback_listen(Callback, 0, SocketOptions),
+ {ok,LSock} = ssh_acceptor:callback_listen(0, Options0),
{ok,{_,LPort}} = inet:sockname(LSock),
{LPort,
- {LSock,Callback},
- [{lsocket,LSock},{lsock_owner,self()}]
+ LSock,
+ ?PUT_INTERNAL_OPT({lsocket,{LSock,self()}}, Options0)
};
_ ->
- {Port1, false, []}
+ {Port1, false, Options0}
end,
- Opts = [{address, Host},
- {port, Port},
- {role, server},
- {socket_opts, SocketOptions},
- {ssh_opts, SshOptions} | Opts0],
+ Options = ?PUT_INTERNAL_OPT([{address, Host},
+ {port, Port},
+ {role, server}], Options1),
+ Profile = ?GET_OPT(profile, Options0),
case ssh_system_sup:system_supervisor(Host, Port, Profile) of
undefined ->
- %% It would proably make more sense to call the
- %% address option host but that is a too big change at the
- %% monent. The name is a legacy name!
- try sshd_sup:start_child(Opts) of
+ try sshd_sup:start_child(Options) of
{error, {already_started, _}} ->
{error, eaddrinuse};
Result = {ok,_} ->
- sync_request_control(WaitRequestControl),
+ sync_request_control(WaitRequestControl, Options),
Result;
Result = {error, _} ->
Result
@@ -436,21 +426,22 @@ do_start_daemon(Host0, Port0, SshOptions, SocketOptions) ->
exit:{noproc, _} ->
{error, ssh_not_started}
end;
- Sup ->
+ Sup ->
AccPid = ssh_system_sup:acceptor_supervisor(Sup),
- case ssh_acceptor_sup:start_child(AccPid, Opts) of
+ case ssh_acceptor_sup:start_child(AccPid, Options) of
{error, {already_started, _}} ->
{error, eaddrinuse};
{ok, _} ->
- sync_request_control(WaitRequestControl),
+ sync_request_control(WaitRequestControl, Options),
{ok, Sup};
Other ->
Other
end
end.
-call_ssh_acceptor_handle_connection(Callback, Host, Port, Opts, Socket, DefaultResult) ->
- try ssh_acceptor:handle_connection(Callback, Host, Port, Opts, Socket)
+call_ssh_acceptor_handle_connection(Host, Port, Options, Socket, DefaultResult) ->
+ {_, Callback, _} = ?GET_OPT(transport, Options),
+ try ssh_acceptor:handle_connection(Callback, Host, Port, Options, Socket)
of
{error,Error} -> {error,Error};
_ -> DefaultResult
@@ -459,9 +450,10 @@ call_ssh_acceptor_handle_connection(Callback, Host, Port, Opts, Socket, DefaultR
end.
-sync_request_control(false) ->
+sync_request_control(false, _Options) ->
ok;
-sync_request_control({LSock,Callback}) ->
+sync_request_control(LSock, Options) ->
+ {_, Callback, _} = ?GET_OPT(transport, Options),
receive
{request_control,LSock,ReqPid} ->
ok = Callback:controlling_process(LSock, ReqPid),
@@ -477,523 +469,6 @@ find_hostport(Fd) ->
ok = inet:close(S),
HostPort.
-
-handle_options(Opts) ->
- try handle_option(algs_compatibility(proplists:unfold(Opts)), [], []) of
- {Inet, Ssh} ->
- {handle_ip(Inet), Ssh}
- catch
- throw:Error ->
- Error
- end.
-
-
-algs_compatibility(Os0) ->
- %% Take care of old options 'public_key_alg' and 'pref_public_key_algs'
- case proplists:get_value(public_key_alg, Os0) of
- undefined ->
- Os0;
- A when is_atom(A) ->
- %% Skip public_key_alg if pref_public_key_algs is defined:
- Os = lists:keydelete(public_key_alg, 1, Os0),
- case proplists:get_value(pref_public_key_algs,Os) of
- undefined when A == 'ssh-rsa' ; A==ssh_rsa ->
- [{pref_public_key_algs,['ssh-rsa','ssh-dss']} | Os];
- undefined when A == 'ssh-dss' ; A==ssh_dsa ->
- [{pref_public_key_algs,['ssh-dss','ssh-rsa']} | Os];
- undefined ->
- throw({error, {eoptions, {public_key_alg,A} }});
- _ ->
- Os
- end;
- V ->
- throw({error, {eoptions, {public_key_alg,V} }})
- end.
-
-
-handle_option([], SocketOptions, SshOptions) ->
- {SocketOptions, SshOptions};
-handle_option([{system_dir, _} = Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{user_dir, _} = Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{user_dir_fun, _} = Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{silently_accept_hosts, _} = Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{user_interaction, _} = Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{connect_timeout, _} = Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{user, _} = Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{dsa_pass_phrase, _} = Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{rsa_pass_phrase, _} = Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{password, _} = Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{user_passwords, _} = Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{pwdfun, _} = Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{key_cb, {Module, Options}} | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option({key_cb, Module}),
- handle_ssh_priv_option({key_cb_private, Options}) |
- SshOptions]);
-handle_option([{key_cb, Module} | Rest], SocketOptions, SshOptions) ->
- handle_option([{key_cb, {Module, []}} | Rest], SocketOptions, SshOptions);
-handle_option([{keyboard_interact_fun, _} = Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-%%Backwards compatibility
-handle_option([{allow_user_interaction, Value} | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option({user_interaction, Value}) | SshOptions]);
-handle_option([{infofun, _} = Opt | Rest],SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{connectfun, _} = Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{disconnectfun, _} = Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{unexpectedfun, _} = Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{failfun, _} = Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{ssh_msg_debug_fun, _} = Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-%%Backwards compatibility should not be underscore between ip and v6 in API
-handle_option([{ip_v6_disabled, Value} | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option({ipv6_disabled, Value}) | SshOptions]);
-handle_option([{ipv6_disabled, _} = Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{transport, _} = Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{subsystems, _} = Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{ssh_cli, _} = Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{shell, _} = Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{exec, _} = Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{auth_methods, _} = Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{auth_method_kb_interactive_data, _} = Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{pref_public_key_algs, _} = Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{preferred_algorithms,_} = Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{dh_gex_groups,_} = Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{dh_gex_limits,_} = Opt | Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-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([{max_sessions, _} = Opt|Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{max_channels, _} = Opt|Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{negotiation_timeout, _} = Opt|Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{parallel_login, _} = Opt|Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-%% (Is handled by proplists:unfold above:)
-%% handle_option([parallel_login|Rest], SocketOptions, SshOptions) ->
-%% handle_option(Rest, SocketOptions, [handle_ssh_option({parallel_login,true}) | SshOptions]);
-handle_option([{minimal_remote_max_packet_size, _} = Opt|Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{id_string, _ID} = Opt|Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{profile, _ID} = Opt|Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{max_random_length_padding, _Bool} = Opt|Rest], SocketOptions, SshOptions) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{tstflg, _} = 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).
-
-
-handle_ssh_option({tstflg,_F} = Opt) -> Opt;
-handle_ssh_option({minimal_remote_max_packet_size, Value} = Opt) when is_integer(Value), Value >=0 ->
- Opt;
-handle_ssh_option({system_dir, Value} = Opt) when is_list(Value) ->
- check_dir(Opt);
-handle_ssh_option({user_dir, Value} = Opt) when is_list(Value) ->
- check_dir(Opt);
-handle_ssh_option({user_dir_fun, Value} = Opt) when is_function(Value) ->
- Opt;
-handle_ssh_option({silently_accept_hosts, Value} = Opt) when is_boolean(Value) ->
- Opt;
-handle_ssh_option({silently_accept_hosts, Value} = Opt) when is_function(Value,2) ->
- Opt;
-handle_ssh_option({silently_accept_hosts, {DigestAlg,Value}} = Opt) when is_function(Value,2) ->
- Algs = if is_atom(DigestAlg) -> [DigestAlg];
- is_list(DigestAlg) -> DigestAlg;
- true -> throw({error, {eoptions, Opt}})
- end,
- case [A || A <- Algs,
- not lists:member(A, [md5, sha, sha224, sha256, sha384, sha512])] of
- [_|_] = UnSup1 ->
- throw({error, {{eoptions, Opt}, {not_fingerprint_algos,UnSup1}}});
- [] ->
- CryptoHashAlgs = proplists:get_value(hashs, crypto:supports(), []),
- case [A || A <- Algs,
- not lists:member(A, CryptoHashAlgs)] of
- [_|_] = UnSup2 ->
- throw({error, {{eoptions, Opt}, {unsupported_algo,UnSup2}}});
- [] -> Opt
- end
- end;
-handle_ssh_option({user_interaction, Value} = Opt) when is_boolean(Value) ->
- Opt;
-handle_ssh_option({preferred_algorithms,[_|_]} = Opt) ->
- handle_pref_algs(Opt);
-
-handle_ssh_option({dh_gex_groups,L0}) when is_list(L0) ->
- {dh_gex_groups,
- collect_per_size(
- lists:foldl(
- fun({N,G,P}, Acc) when is_integer(N),N>0,
- is_integer(G),G>0,
- is_integer(P),P>0 ->
- [{N,{G,P}} | Acc];
- ({N,{G,P}}, Acc) when is_integer(N),N>0,
- is_integer(G),G>0,
- is_integer(P),P>0 ->
- [{N,{G,P}} | Acc];
- ({N,GPs}, Acc) when is_list(GPs) ->
- lists:foldr(fun({Gi,Pi}, Acci) when is_integer(Gi),Gi>0,
- is_integer(Pi),Pi>0 ->
- [{N,{Gi,Pi}} | Acci]
- end, Acc, GPs)
- end, [], L0))};
-
-handle_ssh_option({dh_gex_groups,{Tag,File=[C|_]}}=Opt) when is_integer(C), C>0,
- Tag == file ;
- Tag == ssh_moduli_file ->
- {ok,GroupDefs} =
- case Tag of
- file ->
- file:consult(File);
- ssh_moduli_file ->
- case file:open(File,[read]) of
- {ok,D} ->
- try
- {ok,Moduli} = read_moduli_file(D, 1, []),
- file:close(D),
- {ok, Moduli}
- catch
- _:_ ->
- throw({error, {{eoptions, Opt}, "Bad format in file "++File}})
- end;
- {error,enoent} ->
- throw({error, {{eoptions, Opt}, "File not found:"++File}});
- {error,Error} ->
- throw({error, {{eoptions, Opt}, io_lib:format("Error reading file ~s: ~p",[File,Error])}})
- end
- end,
-
- try
- handle_ssh_option({dh_gex_groups,GroupDefs})
- catch
- _:_ ->
- throw({error, {{eoptions, Opt}, "Bad format in file: "++File}})
- end;
-
-
-handle_ssh_option({dh_gex_limits,{Min,Max}} = Opt) when is_integer(Min), Min>0,
- is_integer(Max), Max>=Min ->
- %% Server
- Opt;
-handle_ssh_option({dh_gex_limits,{Min,I,Max}} = Opt) when is_integer(Min), Min>0,
- is_integer(I), I>=Min,
- is_integer(Max), Max>=I ->
- %% Client
- Opt;
-handle_ssh_option({pref_public_key_algs, Value} = Opt) when is_list(Value), length(Value) >= 1 ->
- case handle_user_pref_pubkey_algs(Value, []) of
- {true, NewOpts} ->
- {pref_public_key_algs, NewOpts};
- _ ->
- throw({error, {eoptions, Opt}})
- end;
-handle_ssh_option({connect_timeout, Value} = Opt) when is_integer(Value); Value == infinity ->
- Opt;
-handle_ssh_option({max_sessions, Value} = Opt) when is_integer(Value), Value>0 ->
- Opt;
-handle_ssh_option({max_channels, Value} = Opt) when is_integer(Value), Value>0 ->
- Opt;
-handle_ssh_option({negotiation_timeout, Value} = Opt) when is_integer(Value); Value == infinity ->
- Opt;
-handle_ssh_option({parallel_login, Value} = Opt) when Value==true ; Value==false ->
- Opt;
-handle_ssh_option({user, Value} = Opt) when is_list(Value) ->
- Opt;
-handle_ssh_option({dsa_pass_phrase, Value} = Opt) when is_list(Value) ->
- Opt;
-handle_ssh_option({rsa_pass_phrase, Value} = Opt) when is_list(Value) ->
- Opt;
-handle_ssh_option({password, Value} = Opt) when is_list(Value) ->
- Opt;
-handle_ssh_option({user_passwords, Value} = Opt) when is_list(Value)->
- Opt;
-handle_ssh_option({pwdfun, Value} = Opt) when is_function(Value,2) ->
- Opt;
-handle_ssh_option({pwdfun, Value} = Opt) when is_function(Value,4) ->
- Opt;
-handle_ssh_option({key_cb, Value} = Opt) when is_atom(Value) ->
- Opt;
-handle_ssh_option({key_cb, {CallbackMod, CallbackOptions}} = Opt) when is_atom(CallbackMod),
- is_list(CallbackOptions) ->
- Opt;
-handle_ssh_option({keyboard_interact_fun, Value} = Opt) when is_function(Value,3) ->
- Opt;
-handle_ssh_option({compression, Value} = Opt) when is_atom(Value) ->
- Opt;
-handle_ssh_option({exec, {Module, Function, _}} = Opt) when is_atom(Module),
- is_atom(Function) ->
- Opt;
-handle_ssh_option({exec, Function} = Opt) when is_function(Function) ->
- Opt;
-handle_ssh_option({auth_methods, Value} = Opt) when is_list(Value) ->
- Opt;
-handle_ssh_option({auth_method_kb_interactive_data, {Name,Instruction,Prompt,Echo}} = Opt) when is_list(Name),
- is_list(Instruction),
- is_list(Prompt),
- is_boolean(Echo) ->
- Opt;
-handle_ssh_option({auth_method_kb_interactive_data, F} = Opt) when is_function(F,3) ->
- Opt;
-handle_ssh_option({infofun, Value} = Opt) when is_function(Value) ->
- Opt;
-handle_ssh_option({connectfun, Value} = Opt) when is_function(Value) ->
- Opt;
-handle_ssh_option({disconnectfun, Value} = Opt) when is_function(Value) ->
- Opt;
-handle_ssh_option({unexpectedfun, Value} = Opt) when is_function(Value,2) ->
- Opt;
-handle_ssh_option({failfun, Value} = Opt) when is_function(Value) ->
- Opt;
-handle_ssh_option({ssh_msg_debug_fun, Value} = Opt) when is_function(Value,4) ->
- Opt;
-
-handle_ssh_option({ipv6_disabled, Value} = Opt) when is_boolean(Value) ->
- throw({error, {{ipv6_disabled, Opt}, option_no_longer_valid_use_inet_option_instead}});
-handle_ssh_option({transport, {Protocol, Cb, ClosTag}} = Opt) when is_atom(Protocol),
- is_atom(Cb),
- is_atom(ClosTag) ->
- Opt;
-handle_ssh_option({subsystems, Value} = Opt) when is_list(Value) ->
- Opt;
-handle_ssh_option({ssh_cli, {Cb, _}}= Opt) when is_atom(Cb) ->
- Opt;
-handle_ssh_option({ssh_cli, no_cli} = Opt) ->
- Opt;
-handle_ssh_option({shell, {Module, Function, _}} = Opt) when is_atom(Module),
- is_atom(Function) ->
- Opt;
-handle_ssh_option({shell, Value} = Opt) when is_function(Value) ->
- Opt;
-handle_ssh_option({quiet_mode, Value} = Opt) when is_boolean(Value) ->
- 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({id_string, random}) ->
- {id_string, {random,2,5}}; %% 2 - 5 random characters
-handle_ssh_option({id_string, ID} = Opt) when is_list(ID) ->
- Opt;
-handle_ssh_option({max_random_length_padding, Value} = Opt) when is_integer(Value),
- Value =< 255 ->
- Opt;
-handle_ssh_option({profile, Value} = Opt) when is_atom(Value) ->
- Opt;
-handle_ssh_option(Opt) ->
- throw({error, {eoptions, Opt}}).
-
-handle_ssh_priv_option({key_cb_private, Value} = Opt) when is_list(Value) ->
- Opt.
-
-handle_inet_option({active, _} = Opt) ->
- throw({error, {{eoptions, Opt}, "SSH has built in flow control, "
- "and active is handled internally, user is not allowed"
- "to specify this option"}});
-
-handle_inet_option({inet, Value}) when (Value == inet) or (Value == inet6) ->
- Value;
-handle_inet_option({reuseaddr, _} = Opt) ->
- throw({error, {{eoptions, Opt},"Is set internally, user is not allowed"
- "to specify this option"}});
-%% Option verified by inet
-handle_inet_option(Opt) ->
- Opt.
-
-
-%% Check preferred algs
-
-handle_pref_algs({preferred_algorithms,Algs}) ->
- try alg_duplicates(Algs, [], []) of
- [] ->
- {preferred_algorithms,
- [try ssh_transport:supported_algorithms(Key)
- of
- DefAlgs -> handle_pref_alg(Key,Vals,DefAlgs)
- catch
- _:_ -> throw({error, {{eoptions, {preferred_algorithms,Key}},
- "Bad preferred_algorithms key"}})
- end || {Key,Vals} <- Algs]
- };
-
- Dups ->
- throw({error, {{eoptions, {preferred_algorithms,Dups}}, "Duplicates found"}})
- catch
- _:_ ->
- throw({error, {{eoptions, preferred_algorithms}, "Malformed"}})
- end.
-
-alg_duplicates([{K,V}|KVs], Ks, Dups0) ->
- Dups =
- case lists:member(K,Ks) of
- true ->
- [K|Dups0];
- false ->
- Dups0
- end,
- case V--lists:usort(V) of
- [] ->
- alg_duplicates(KVs, [K|Ks], Dups);
- Ds ->
- alg_duplicates(KVs, [K|Ks], Dups++Ds)
- end;
-alg_duplicates([], _Ks, Dups) ->
- Dups.
-
-handle_pref_alg(Key,
- Vs=[{client2server,C2Ss=[_|_]},{server2client,S2Cs=[_|_]}],
- [{client2server,Sup_C2Ss},{server2client,Sup_S2Cs}]
- ) ->
- chk_alg_vs(Key, C2Ss, Sup_C2Ss),
- chk_alg_vs(Key, S2Cs, Sup_S2Cs),
- {Key, Vs};
-
-handle_pref_alg(Key,
- Vs=[{server2client,[_|_]},{client2server,[_|_]}],
- Sup=[{client2server,_},{server2client,_}]
- ) ->
- handle_pref_alg(Key, lists:reverse(Vs), Sup);
-
-handle_pref_alg(Key,
- Vs=[V|_],
- Sup=[{client2server,_},{server2client,_}]
- ) when is_atom(V) ->
- handle_pref_alg(Key, [{client2server,Vs},{server2client,Vs}], Sup);
-
-handle_pref_alg(Key,
- Vs=[V|_],
- Sup=[S|_]
- ) when is_atom(V), is_atom(S) ->
- chk_alg_vs(Key, Vs, Sup),
- {Key, Vs};
-
-handle_pref_alg(Key, Vs, _) ->
- throw({error, {{eoptions, {preferred_algorithms,[{Key,Vs}]}}, "Badly formed list"}}).
-
-chk_alg_vs(OptKey, Values, SupportedValues) ->
- case (Values -- SupportedValues) of
- [] -> Values;
- Bad -> throw({error, {{eoptions, {OptKey,Bad}}, "Unsupported value(s) found"}})
- end.
-
-handle_ip(Inet) -> %% Default to ipv4
- case lists:member(inet, Inet) of
- true ->
- Inet;
- false ->
- case lists:member(inet6, Inet) of
- true ->
- Inet;
- false ->
- [inet | Inet]
- end
- end.
-
-check_dir({_,Dir} = Opt) ->
- case directory_exist_readable(Dir) of
- ok ->
- Opt;
- {error,Error} ->
- throw({error, {eoptions,{Opt,Error}}})
- end.
-
-directory_exist_readable(Dir) ->
- case file:read_file_info(Dir) of
- {ok, #file_info{type = directory,
- access = Access}} ->
- case Access of
- read -> ok;
- read_write -> ok;
- _ -> {error, eacces}
- end;
-
- {ok, #file_info{}}->
- {error, enotdir};
-
- {error, Error} ->
- {error, Error}
- end.
-
-
-
-collect_per_size(L) ->
- lists:foldr(
- fun({Sz,GP}, [{Sz,GPs}|Acc]) -> [{Sz,[GP|GPs]}|Acc];
- ({Sz,GP}, Acc) -> [{Sz,[GP]}|Acc]
- end, [], lists:sort(L)).
-
-read_moduli_file(D, I, Acc) ->
- case io:get_line(D,"") of
- {error,Error} ->
- {error,Error};
- eof ->
- {ok, Acc};
- "#" ++ _ -> read_moduli_file(D, I+1, Acc);
- <<"#",_/binary>> -> read_moduli_file(D, I+1, Acc);
- Data ->
- Line = if is_binary(Data) -> binary_to_list(Data);
- is_list(Data) -> Data
- end,
- try
- [_Time,_Type,_Tests,_Tries,Size,G,P] = string:tokens(Line," \r\n"),
- M = {list_to_integer(Size),
- {list_to_integer(G), list_to_integer(P,16)}
- },
- read_moduli_file(D, I+1, [M|Acc])
- catch
- _:_ ->
- read_moduli_file(D, I+1, Acc)
- end
- end.
-
-handle_user_pref_pubkey_algs([], Acc) ->
- {true, lists:reverse(Acc)};
-handle_user_pref_pubkey_algs([H|T], Acc) ->
- case lists:member(H, ?SUPPORTED_USER_KEYS) of
- true ->
- handle_user_pref_pubkey_algs(T, [H| Acc]);
-
- false when H==ssh_dsa -> handle_user_pref_pubkey_algs(T, ['ssh-dss'| Acc]);
- false when H==ssh_rsa -> handle_user_pref_pubkey_algs(T, ['ssh-rsa'| Acc]);
-
- false ->
- false
- end.
-
fmt_host({A,B,C,D}) ->
lists:concat([A,".",B,".",C,".",D]);
fmt_host(T={_,_,_,_,_,_,_,_}) ->
diff --git a/lib/ssh/src/ssh.hrl b/lib/ssh/src/ssh.hrl
index 4cd91177f6..475534f572 100644
--- a/lib/ssh/src/ssh.hrl
+++ b/lib/ssh/src/ssh.hrl
@@ -33,6 +33,10 @@
-define(REKEY_DATA_TIMOUT, 60000).
-define(DEFAULT_PROFILE, default).
+-define(DEFAULT_TRANSPORT, {tcp, gen_tcp, tcp_closed} ).
+
+-define(MAX_RND_PADDING_LEN, 15).
+
-define(SUPPORTED_AUTH_METHODS, "publickey,keyboard-interactive,password").
-define(SUPPORTED_USER_KEYS, ['ssh-rsa','ssh-dss','ecdsa-sha2-nistp256','ecdsa-sha2-nistp384','ecdsa-sha2-nistp521']).
@@ -64,10 +68,31 @@
-define(string_utf8(X), << ?STRING(unicode:characters_to_binary(X)) >> ).
-define(binary(X), << ?STRING(X) >>).
+%% Cipher details
-define(SSH_CIPHER_NONE, 0).
-define(SSH_CIPHER_3DES, 3).
-define(SSH_CIPHER_AUTHFILE, ?SSH_CIPHER_3DES).
+%% Option access macros
+-define(do_get_opt(C,K,O), ssh_options:get_value(C,K,O, ?MODULE,?LINE)).
+-define(do_get_opt(C,K,O,D), ssh_options:get_value(C,K,O,D,?MODULE,?LINE)).
+
+-define(GET_OPT(Key,Opts), ?do_get_opt(user_options, Key,Opts ) ).
+-define(GET_INTERNAL_OPT(Key,Opts), ?do_get_opt(internal_options,Key,Opts ) ).
+-define(GET_INTERNAL_OPT(Key,Opts,Def), ?do_get_opt(internal_options,Key,Opts,Def) ).
+-define(GET_SOCKET_OPT(Key,Opts), ?do_get_opt(socket_options, Key,Opts ) ).
+-define(GET_SOCKET_OPT(Key,Opts,Def), ?do_get_opt(socket_options, Key,Opts,Def) ).
+
+-define(do_put_opt(C,KV,O), ssh_options:put_value(C,KV,O, ?MODULE,?LINE)).
+
+-define(PUT_OPT(KeyVal,Opts), ?do_put_opt(user_options, KeyVal,Opts) ).
+-define(PUT_INTERNAL_OPT(KeyVal,Opts), ?do_put_opt(internal_options,KeyVal,Opts) ).
+-define(PUT_SOCKET_OPT(KeyVal,Opts), ?do_put_opt(socket_options, KeyVal,Opts) ).
+
+%% Types
+-type ok_error(SuccessType) :: {ok, SuccessType} | {error, any()} .
+
+%% Records
-record(ssh,
{
role, %% client | server
@@ -127,7 +152,7 @@
recv_sequence = 0,
keyex_key,
keyex_info,
- random_length_padding = 15, % From RFC 4253 section 6.
+ random_length_padding = ?MAX_RND_PADDING_LEN, % From RFC 4253 section 6.
%% User auth
user,
diff --git a/lib/ssh/src/ssh_acceptor.erl b/lib/ssh/src/ssh_acceptor.erl
index 13c9d9af4a..42be18f2ad 100644
--- a/lib/ssh/src/ssh_acceptor.erl
+++ b/lib/ssh/src/ssh_acceptor.erl
@@ -25,56 +25,63 @@
-include("ssh.hrl").
%% Internal application API
--export([start_link/5,
+-export([start_link/4,
number_of_connections/1,
- callback_listen/3,
+ callback_listen/2,
handle_connection/5]).
%% spawn export
--export([acceptor_init/6, acceptor_loop/6]).
+-export([acceptor_init/5, acceptor_loop/6]).
-define(SLEEP_TIME, 200).
%%====================================================================
%% Internal application API
%%====================================================================
-start_link(Port, Address, SockOpts, Opts, AcceptTimeout) ->
- Args = [self(), Port, Address, SockOpts, Opts, AcceptTimeout],
+start_link(Port, Address, Options, AcceptTimeout) ->
+ Args = [self(), Port, Address, Options, AcceptTimeout],
proc_lib:start_link(?MODULE, acceptor_init, Args).
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
-acceptor_init(Parent, Port, Address, SockOpts, Opts, AcceptTimeout) ->
- {_, Callback, _} =
- proplists:get_value(transport, Opts, {tcp, gen_tcp, tcp_closed}),
-
- SockOwner = proplists:get_value(lsock_owner, Opts),
- LSock = proplists:get_value(lsocket, Opts),
- UseExistingSocket =
- case catch inet:sockname(LSock) of
- {ok,{_,Port}} -> is_pid(SockOwner);
- _ -> false
- end,
-
- case UseExistingSocket of
- true ->
- proc_lib:init_ack(Parent, {ok, self()}),
+acceptor_init(Parent, Port, Address, Opts, AcceptTimeout) ->
+ {_, Callback, _} = ?GET_OPT(transport, Opts),
+ try
+ {LSock0,SockOwner0} = ?GET_INTERNAL_OPT(lsocket, Opts),
+ true = is_pid(SockOwner0),
+ {ok,{_,Port}} = inet:sockname(LSock0),
+ {LSock0, SockOwner0}
+ of
+ {LSock, SockOwner} ->
+ %% Use existing socket
+ proc_lib:init_ack(Parent, {ok, self()}),
request_ownership(LSock, SockOwner),
- acceptor_loop(Callback, Port, Address, Opts, LSock, AcceptTimeout);
-
- false ->
- case (catch do_socket_listen(Callback, Port, SockOpts)) of
- {ok, ListenSocket} ->
- proc_lib:init_ack(Parent, {ok, self()}),
- acceptor_loop(Callback,
- Port, Address, Opts, ListenSocket, AcceptTimeout);
- Error ->
- proc_lib:init_ack(Parent, Error),
- error
- end
+ acceptor_loop(Callback, Port, Address, Opts, LSock, AcceptTimeout)
+ catch
+ error:{badkey,lsocket} ->
+ %% Open new socket
+ try
+ socket_listen(Port, Opts)
+ of
+ {ok, ListenSocket} ->
+ proc_lib:init_ack(Parent, {ok, self()}),
+ {_, Callback, _} = ?GET_OPT(transport, Opts),
+ acceptor_loop(Callback,
+ Port, Address, Opts, ListenSocket, AcceptTimeout);
+ {error,Error} ->
+ proc_lib:init_ack(Parent, Error),
+ {error,Error}
+ catch
+ _:_ ->
+ {error,listen_socket_failed}
+ end;
+
+ _:_ ->
+ {error,use_existing_socket_failed}
end.
+
request_ownership(LSock, SockOwner) ->
SockOwner ! {request_control,LSock,self()},
receive
@@ -82,23 +89,25 @@ request_ownership(LSock, SockOwner) ->
end.
-do_socket_listen(Callback, Port0, Opts) ->
- Port =
- case proplists:get_value(fd, Opts) of
- undefined -> Port0;
- _ -> 0
- end,
- callback_listen(Callback, Port, Opts).
-
-callback_listen(Callback, Port, Opts0) ->
- Opts = [{active, false}, {reuseaddr,true} | Opts0],
- case Callback:listen(Port, Opts) of
+socket_listen(Port0, Opts) ->
+ Port = case ?GET_SOCKET_OPT(fd, Opts) of
+ undefined -> Port0;
+ _ -> 0
+ end,
+ callback_listen(Port, Opts).
+
+
+callback_listen(Port, Opts0) ->
+ {_, Callback, _} = ?GET_OPT(transport, Opts0),
+ Opts = ?PUT_SOCKET_OPT([{active, false}, {reuseaddr,true}], Opts0),
+ SockOpts = ?GET_OPT(socket_options, Opts),
+ case Callback:listen(Port, SockOpts) of
{error, nxdomain} ->
- Callback:listen(Port, lists:delete(inet6, Opts));
+ Callback:listen(Port, lists:delete(inet6, SockOpts));
{error, enetunreach} ->
- Callback:listen(Port, lists:delete(inet6, Opts));
+ Callback:listen(Port, lists:delete(inet6, SockOpts));
{error, eafnosupport} ->
- Callback:listen(Port, lists:delete(inet6, Opts));
+ Callback:listen(Port, lists:delete(inet6, SockOpts));
Other ->
Other
end.
@@ -120,21 +129,21 @@ acceptor_loop(Callback, Port, Address, Opts, ListenSocket, AcceptTimeout) ->
end.
handle_connection(Callback, Address, Port, Options, Socket) ->
- SSHopts = proplists:get_value(ssh_opts, Options, []),
- Profile = proplists:get_value(profile, SSHopts, ?DEFAULT_PROFILE),
+ Profile = ?GET_OPT(profile, Options),
SystemSup = ssh_system_sup:system_supervisor(Address, Port, Profile),
- MaxSessions = proplists:get_value(max_sessions,SSHopts,infinity),
+ MaxSessions = ?GET_OPT(max_sessions, Options),
case number_of_connections(SystemSup) < MaxSessions of
true ->
{ok, SubSysSup} = ssh_system_sup:start_subsystem(SystemSup, Options),
ConnectionSup = ssh_subsystem_sup:connection_supervisor(SubSysSup),
- Timeout = proplists:get_value(negotiation_timeout, SSHopts, 2*60*1000),
+ NegTimeout = ?GET_OPT(negotiation_timeout, Options),
ssh_connection_handler:start_connection(server, Socket,
- [{supervisors, [{system_sup, SystemSup},
- {subsystem_sup, SubSysSup},
- {connection_sup, ConnectionSup}]}
- | Options], Timeout);
+ ?PUT_INTERNAL_OPT(
+ {supervisors, [{system_sup, SystemSup},
+ {subsystem_sup, SubSysSup},
+ {connection_sup, ConnectionSup}]},
+ Options), NegTimeout);
false ->
Callback:close(Socket),
IPstr = if is_tuple(Address) -> inet:ntoa(Address);
diff --git a/lib/ssh/src/ssh_acceptor_sup.erl b/lib/ssh/src/ssh_acceptor_sup.erl
index 129f85a3e0..77f7826918 100644
--- a/lib/ssh/src/ssh_acceptor_sup.erl
+++ b/lib/ssh/src/ssh_acceptor_sup.erl
@@ -44,14 +44,13 @@
start_link(Servers) ->
supervisor:start_link(?MODULE, [Servers]).
-start_child(AccSup, ServerOpts) ->
- Spec = child_spec(ServerOpts),
+start_child(AccSup, Options) ->
+ Spec = child_spec(Options),
case supervisor:start_child(AccSup, Spec) of
{error, already_present} ->
- Address = proplists:get_value(address, ServerOpts),
- Port = proplists:get_value(port, ServerOpts),
- Profile = proplists:get_value(profile,
- proplists:get_value(ssh_opts, ServerOpts), ?DEFAULT_PROFILE),
+ Address = ?GET_INTERNAL_OPT(address, Options),
+ Port = ?GET_INTERNAL_OPT(port, Options),
+ Profile = ?GET_OPT(profile, Options),
stop_child(AccSup, Address, Port, Profile),
supervisor:start_child(AccSup, Spec);
Reply ->
@@ -70,24 +69,23 @@ stop_child(AccSup, Address, Port, Profile) ->
%%%=========================================================================
%%% Supervisor callback
%%%=========================================================================
-init([ServerOpts]) ->
+init([Options]) ->
RestartStrategy = one_for_one,
MaxR = 10,
MaxT = 3600,
- Children = [child_spec(ServerOpts)],
+ Children = [child_spec(Options)],
{ok, {{RestartStrategy, MaxR, MaxT}, Children}}.
%%%=========================================================================
%%% Internal functions
%%%=========================================================================
-child_spec(ServerOpts) ->
- Address = proplists:get_value(address, ServerOpts),
- Port = proplists:get_value(port, ServerOpts),
- Timeout = proplists:get_value(timeout, ServerOpts, ?DEFAULT_TIMEOUT),
- Profile = proplists:get_value(profile, proplists:get_value(ssh_opts, ServerOpts), ?DEFAULT_PROFILE),
+child_spec(Options) ->
+ Address = ?GET_INTERNAL_OPT(address, Options),
+ Port = ?GET_INTERNAL_OPT(port, Options),
+ Timeout = ?GET_INTERNAL_OPT(timeout, Options, ?DEFAULT_TIMEOUT),
+ Profile = ?GET_OPT(profile, Options),
Name = id(Address, Port, Profile),
- SocketOpts = proplists:get_value(socket_opts, ServerOpts),
- StartFunc = {ssh_acceptor, start_link, [Port, Address, SocketOpts, ServerOpts, Timeout]},
+ StartFunc = {ssh_acceptor, start_link, [Port, Address, Options, Timeout]},
Restart = transient,
Shutdown = brutal_kill,
Modules = [ssh_acceptor],
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl
index 9b54ecb2dd..88c8144063 100644
--- a/lib/ssh/src/ssh_auth.erl
+++ b/lib/ssh/src/ssh_auth.erl
@@ -96,14 +96,14 @@ unique(L) ->
password_msg([#ssh{opts = Opts, io_cb = IoCb,
user = User, service = Service} = Ssh0]) ->
{Password,Ssh} =
- case proplists:get_value(password, Opts) of
+ case ?GET_OPT(password, Opts) of
undefined when IoCb == ssh_no_io ->
{not_ok, Ssh0};
undefined ->
- {IoCb:read_password("ssh password: ",Ssh0), Ssh0};
+ {IoCb:read_password("ssh password: ",Opts), Ssh0};
PW ->
%% If "password" option is given it should not be tried again
- {PW, Ssh0#ssh{opts = lists:keyreplace(password,1,Opts,{password,not_ok})}}
+ {PW, Ssh0#ssh{opts = ?PUT_OPT({password,not_ok}, Opts)}}
end,
case Password of
not_ok ->
@@ -123,7 +123,7 @@ password_msg([#ssh{opts = Opts, io_cb = IoCb,
keyboard_interactive_msg([#ssh{user = User,
opts = Opts,
service = Service} = Ssh]) ->
- case proplists:get_value(password, Opts) of
+ case ?GET_OPT(password, Opts) of
not_ok ->
{not_ok,Ssh}; % No need to use a failed pwd once more
_ ->
@@ -141,8 +141,9 @@ publickey_msg([Alg, #ssh{user = User,
service = Service,
opts = Opts} = Ssh]) ->
Hash = ssh_transport:sha(Alg),
- KeyCb = proplists:get_value(key_cb, Opts, ssh_file),
- case KeyCb:user_key(Alg, Opts) of
+ {KeyCb,KeyCbOpts} = ?GET_OPT(key_cb, Opts),
+ UserOpts = ?GET_OPT(user_options, Opts),
+ case KeyCb:user_key(Alg, [{key_cb_private,KeyCbOpts}|UserOpts]) of
{ok, PrivKey} ->
StrAlgo = atom_to_list(Alg),
case encode_public_key(StrAlgo, ssh_transport:extract_public_key(PrivKey)) of
@@ -174,13 +175,19 @@ service_request_msg(Ssh) ->
%%%----------------------------------------------------------------
init_userauth_request_msg(#ssh{opts = Opts} = Ssh) ->
- case user_name(Opts) of
- {ok, User} ->
+ case ?GET_OPT(user, Opts) of
+ undefined ->
+ ErrStr = "Could not determine the users name",
+ ssh_connection_handler:disconnect(
+ #ssh_msg_disconnect{code = ?SSH_DISCONNECT_ILLEGAL_USER_NAME,
+ description = ErrStr});
+
+ User ->
Msg = #ssh_msg_userauth_request{user = User,
service = "ssh-connection",
method = "none",
data = <<>>},
- Algs0 = proplists:get_value(pref_public_key_algs, Opts, ?SUPPORTED_USER_KEYS),
+ Algs0 = ?GET_OPT(pref_public_key_algs, Opts),
%% The following line is not strictly correct. The call returns the
%% supported HOST key types while we are interested in USER keys. However,
%% they "happens" to be the same (for now). This could change....
@@ -194,12 +201,7 @@ init_userauth_request_msg(#ssh{opts = Opts} = Ssh) ->
ssh_transport:ssh_packet(Msg, Ssh#ssh{user = User,
userauth_preference = Prefs,
userauth_methods = none,
- service = "ssh-connection"});
- {error, no_user} ->
- ErrStr = "Could not determine the users name",
- ssh_connection_handler:disconnect(
- #ssh_msg_disconnect{code = ?SSH_DISCONNECT_ILLEGAL_USER_NAME,
- description = ErrStr})
+ service = "ssh-connection"})
end.
%%%----------------------------------------------------------------
@@ -342,7 +344,7 @@ handle_userauth_request(#ssh_msg_userauth_request{user = User,
false},
{Name, Instruction, Prompt, Echo} =
- case proplists:get_value(auth_method_kb_interactive_data, Opts) of
+ case ?GET_OPT(auth_method_kb_interactive_data, Opts) of
undefined ->
Default;
{_,_,_,_}=V ->
@@ -407,9 +409,9 @@ handle_userauth_info_response(#ssh_msg_userauth_info_response{num_responses = 1,
user = User,
userauth_supported_methods = Methods} = Ssh) ->
SendOneEmpty =
- (proplists:get_value(tstflg,Opts) == one_empty)
+ (?GET_OPT(tstflg,Opts) == one_empty)
orelse
- proplists:get_value(one_empty, proplists:get_value(tstflg,Opts,[]), false),
+ proplists:get_value(one_empty, ?GET_OPT(tstflg,Opts), false),
case check_password(User, unicode:characters_to_list(Password), Opts, Ssh) of
{true,Ssh1} when SendOneEmpty==true ->
@@ -460,27 +462,8 @@ method_preference(Algs) ->
],
Algs).
-user_name(Opts) ->
- Env = case os:type() of
- {win32, _} ->
- "USERNAME";
- {unix, _} ->
- "LOGNAME"
- end,
- case proplists:get_value(user, Opts, os:getenv(Env)) of
- false ->
- case os:getenv("USER") of
- false ->
- {error, no_user};
- User ->
- {ok, User}
- end;
- User ->
- {ok, User}
- end.
-
check_password(User, Password, Opts, Ssh) ->
- case proplists:get_value(pwdfun, Opts) of
+ case ?GET_OPT(pwdfun, Opts) of
undefined ->
Static = get_password_option(Opts, User),
{Password == Static, Ssh};
@@ -510,17 +493,18 @@ check_password(User, Password, Opts, Ssh) ->
end.
get_password_option(Opts, User) ->
- Passwords = proplists:get_value(user_passwords, Opts, []),
+ Passwords = ?GET_OPT(user_passwords, Opts),
case lists:keysearch(User, 1, Passwords) of
{value, {User, Pw}} -> Pw;
- false -> proplists:get_value(password, Opts, false)
+ false -> ?GET_OPT(password, Opts)
end.
pre_verify_sig(User, Alg, KeyBlob, Opts) ->
try
{ok, Key} = decode_public_key_v2(KeyBlob, Alg),
- KeyCb = proplists:get_value(key_cb, Opts, ssh_file),
- KeyCb:is_auth_key(Key, User, Opts)
+ {KeyCb,KeyCbOpts} = ?GET_OPT(key_cb, Opts),
+ UserOpts = ?GET_OPT(user_options, Opts),
+ KeyCb:is_auth_key(Key, User, [{key_cb_private,KeyCbOpts}|UserOpts])
catch
_:_ ->
false
@@ -529,9 +513,10 @@ pre_verify_sig(User, Alg, KeyBlob, Opts) ->
verify_sig(SessionId, User, Service, Alg, KeyBlob, SigWLen, Opts) ->
try
{ok, Key} = decode_public_key_v2(KeyBlob, Alg),
- KeyCb = proplists:get_value(key_cb, Opts, ssh_file),
- case KeyCb:is_auth_key(Key, User, Opts) of
+ {KeyCb,KeyCbOpts} = ?GET_OPT(key_cb, Opts),
+ UserOpts = ?GET_OPT(user_options, Opts),
+ case KeyCb:is_auth_key(Key, User, [{key_cb_private,KeyCbOpts}|UserOpts]) of
true ->
PlainText = build_sig_data(SessionId, User,
Service, KeyBlob, Alg),
@@ -565,9 +550,9 @@ decode_keyboard_interactive_prompts(_NumPrompts, Data) ->
keyboard_interact_get_responses(IoCb, Opts, Name, Instr, PromptInfos) ->
NumPrompts = length(PromptInfos),
- keyboard_interact_get_responses(proplists:get_value(user_interaction, Opts, true),
- proplists:get_value(keyboard_interact_fun, Opts),
- proplists:get_value(password, Opts, undefined), IoCb, Name,
+ keyboard_interact_get_responses(?GET_OPT(user_interaction, Opts),
+ ?GET_OPT(keyboard_interact_fun, Opts),
+ ?GET_OPT(password, Opts), IoCb, Name,
Instr, PromptInfos, Opts, NumPrompts).
diff --git a/lib/ssh/src/ssh_cli.erl b/lib/ssh/src/ssh_cli.erl
index 6f8c050486..4c4f61e036 100644
--- a/lib/ssh/src/ssh_cli.erl
+++ b/lib/ssh/src/ssh_cli.erl
@@ -499,14 +499,12 @@ start_shell(ConnectionHandler, State) ->
[peer, user]),
ShellFun = case is_function(Shell) of
true ->
- User =
- proplists:get_value(user, ConnectionInfo),
+ User = proplists:get_value(user, ConnectionInfo),
case erlang:fun_info(Shell, arity) of
{arity, 1} ->
fun() -> Shell(User) end;
{arity, 2} ->
- {_, PeerAddr} =
- proplists:get_value(peer, ConnectionInfo),
+ {_, PeerAddr} = proplists:get_value(peer, ConnectionInfo),
fun() -> Shell(User, PeerAddr) end;
_ ->
Shell
@@ -525,8 +523,7 @@ start_shell(ConnectionHandler, Cmd, #state{exec=Shell} = State) when is_function
ConnectionInfo = ssh_connection_handler:connection_info(ConnectionHandler,
[peer, user]),
- User =
- proplists:get_value(user, ConnectionInfo),
+ User = proplists:get_value(user, ConnectionInfo),
ShellFun =
case erlang:fun_info(Shell, arity) of
{arity, 1} ->
@@ -534,8 +531,7 @@ start_shell(ConnectionHandler, Cmd, #state{exec=Shell} = State) when is_function
{arity, 2} ->
fun() -> Shell(Cmd, User) end;
{arity, 3} ->
- {_, PeerAddr} =
- proplists:get_value(peer, ConnectionInfo),
+ {_, PeerAddr} = proplists:get_value(peer, ConnectionInfo),
fun() -> Shell(Cmd, User, PeerAddr) end;
_ ->
Shell
diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl
index c7a2c92670..6a48ed581c 100644
--- a/lib/ssh/src/ssh_connection.erl
+++ b/lib/ssh/src/ssh_connection.erl
@@ -197,16 +197,16 @@ reply_request(_,false, _, _) ->
ptty_alloc(ConnectionHandler, Channel, Options) ->
ptty_alloc(ConnectionHandler, Channel, Options, infinity).
ptty_alloc(ConnectionHandler, Channel, Options0, TimeOut) ->
- Options = backwards_compatible(Options0, []),
- {Width, PixWidth} = pty_default_dimensions(width, Options),
- {Height, PixHeight} = pty_default_dimensions(height, Options),
+ TermData = backwards_compatible(Options0, []), % FIXME
+ {Width, PixWidth} = pty_default_dimensions(width, TermData),
+ {Height, PixHeight} = pty_default_dimensions(height, TermData),
pty_req(ConnectionHandler, Channel,
- proplists:get_value(term, Options, os:getenv("TERM", ?DEFAULT_TERMINAL)),
- proplists:get_value(width, Options, Width),
- proplists:get_value(height, Options, Height),
- proplists:get_value(pixel_widh, Options, PixWidth),
- proplists:get_value(pixel_height, Options, PixHeight),
- proplists:get_value(pty_opts, Options, []), TimeOut
+ proplists:get_value(term, TermData, os:getenv("TERM", ?DEFAULT_TERMINAL)),
+ proplists:get_value(width, TermData, Width),
+ proplists:get_value(height, TermData, Height),
+ proplists:get_value(pixel_widh, TermData, PixWidth),
+ proplists:get_value(pixel_height, TermData, PixHeight),
+ proplists:get_value(pty_opts, TermData, []), TimeOut
).
%%--------------------------------------------------------------------
%% Not yet officialy supported! The following functions are part of the
@@ -417,7 +417,8 @@ handle_msg(#ssh_msg_channel_open{channel_type = "session" = Type,
maximum_packet_size = PacketSz},
#connection{options = SSHopts} = Connection0,
server) ->
- MinAcceptedPackSz = proplists:get_value(minimal_remote_max_packet_size, SSHopts, 0),
+ MinAcceptedPackSz =
+ ?GET_OPT(minimal_remote_max_packet_size, SSHopts),
if
MinAcceptedPackSz =< PacketSz ->
@@ -574,7 +575,6 @@ handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
PixWidth, PixHeight, decode_pty_opts(Modes)},
Channel = ssh_channel:cache_lookup(Cache, ChannelId),
-
handle_cli_msg(Connection, Channel,
{pty, ChannelId, WantReply, PtyRequest});
@@ -691,7 +691,6 @@ handle_cli_msg(#connection{channel_cache = Cache} = Connection,
#channel{user = undefined,
remote_id = RemoteId,
local_id = ChannelId} = Channel0, Reply0) ->
-
case (catch start_cli(Connection, ChannelId)) of
{ok, Pid} ->
erlang:monitor(process, Pid),
@@ -819,7 +818,7 @@ start_channel(Cb, Id, Args, SubSysSup, Exec, Opts) ->
ssh_channel_sup:start_child(ChannelSup, ChildSpec).
assert_limit_num_channels_not_exceeded(ChannelSup, Opts) ->
- MaxNumChannels = proplists:get_value(max_channels, Opts, infinity),
+ MaxNumChannels = ?GET_OPT(max_channels, Opts),
NumChannels = length([x || {_,_,worker,[ssh_channel]} <-
supervisor:which_children(ChannelSup)]),
if
@@ -858,8 +857,8 @@ setup_session(#connection{channel_cache = Cache
check_subsystem("sftp"= SsName, Options) ->
- case proplists:get_value(subsystems, Options, no_subsys) of
- no_subsys ->
+ case ?GET_OPT(subsystems, Options) of
+ no_subsys -> % FIXME: Can 'no_subsys' ever be matched?
{SsName, {Cb, Opts}} = ssh_sftpd:subsystem_spec([]),
{Cb, Opts};
SubSystems ->
@@ -867,7 +866,7 @@ check_subsystem("sftp"= SsName, Options) ->
end;
check_subsystem(SsName, Options) ->
- Subsystems = proplists:get_value(subsystems, Options, []),
+ Subsystems = ?GET_OPT(subsystems, Options),
case proplists:get_value(SsName, Subsystems, {none, []}) of
Fun when is_function(Fun) ->
{Fun, []};
@@ -1022,12 +1021,13 @@ pty_req(ConnectionHandler, Channel, Term, Width, Height,
?uint32(PixWidth),?uint32(PixHeight),
encode_pty_opts(PtyOpts)], TimeOut).
-pty_default_dimensions(Dimension, Options) ->
- case proplists:get_value(Dimension, Options, 0) of
+pty_default_dimensions(Dimension, TermData) ->
+ case proplists:get_value(Dimension, TermData, 0) of
N when is_integer(N), N > 0 ->
{N, 0};
_ ->
- case proplists:get_value(list_to_atom("pixel_" ++ atom_to_list(Dimension)), Options, 0) of
+ PixelDim = list_to_atom("pixel_" ++ atom_to_list(Dimension)),
+ case proplists:get_value(PixelDim, TermData, 0) of
N when is_integer(N), N > 0 ->
{0, N};
_ ->
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index dcf509ca09..706b68d78b 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -76,7 +76,7 @@
%%--------------------------------------------------------------------
-spec start_link(role(),
inet:socket(),
- proplists:proplist()
+ ssh_options:options()
) -> {ok, pid()}.
%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
start_link(Role, Socket, Options) ->
@@ -99,12 +99,10 @@ stop(ConnectionHandler)->
%% Internal application API
%%====================================================================
--define(DefaultTransport, {tcp, gen_tcp, tcp_closed} ).
-
%%--------------------------------------------------------------------
-spec start_connection(role(),
inet:socket(),
- proplists:proplist(),
+ ssh_options:options(),
timeout()
) -> {ok, connection_ref()} | {error, term()}.
%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
@@ -121,9 +119,8 @@ start_connection(client = Role, Socket, Options, Timeout) ->
end;
start_connection(server = Role, Socket, Options, Timeout) ->
- SSH_Opts = proplists:get_value(ssh_opts, Options, []),
try
- case proplists:get_value(parallel_login, SSH_Opts, false) of
+ case ?GET_OPT(parallel_login, Options) of
true ->
HandshakerPid =
spawn_link(fun() ->
@@ -346,7 +343,7 @@ renegotiate_data(ConnectionHandler) ->
| undefined,
last_size_rekey = 0 :: non_neg_integer(),
event_queue = [] :: list(),
- opts :: proplists:proplist(),
+ opts :: ssh_options:options(),
inet_initial_recbuf_size :: pos_integer()
| undefined
}).
@@ -357,15 +354,14 @@ renegotiate_data(ConnectionHandler) ->
%%--------------------------------------------------------------------
-spec init_connection_handler(role(),
inet:socket(),
- proplists:proplist()
+ ssh_options:options()
) -> no_return().
%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
init_connection_handler(Role, Socket, Opts) ->
process_flag(trap_exit, true),
S0 = init_process_state(Role, Socket, Opts),
try
- {Protocol, Callback, CloseTag} =
- proplists:get_value(transport, Opts, ?DefaultTransport),
+ {Protocol, Callback, CloseTag} = ?GET_OPT(transport, Opts),
S0#data{ssh_params = init_ssh_record(Role, Socket, Opts),
transport_protocol = Protocol,
transport_cb = Callback,
@@ -393,7 +389,7 @@ init_process_state(Role, Socket, Opts) ->
port_bindings = [],
requests = [],
options = Opts},
- starter = proplists:get_value(user_pid, Opts),
+ starter = ?GET_INTERNAL_OPT(user_pid, Opts),
socket = Socket,
opts = Opts
},
@@ -409,13 +405,18 @@ init_process_state(Role, Socket, Opts) ->
init_connection(server, C = #connection{}, Opts) ->
- Sups = proplists:get_value(supervisors, Opts),
- SystemSup = proplists:get_value(system_sup, Sups),
- SubSystemSup = proplists:get_value(subsystem_sup, Sups),
+ Sups = ?GET_INTERNAL_OPT(supervisors, Opts),
+
+ SystemSup = proplists:get_value(system_sup, Sups),
+ SubSystemSup = proplists:get_value(subsystem_sup, Sups),
ConnectionSup = proplists:get_value(connection_sup, Sups),
- Shell = proplists:get_value(shell, Opts),
- Exec = proplists:get_value(exec, Opts),
- CliSpec = proplists:get_value(ssh_cli, Opts, {ssh_cli, [Shell]}),
+
+ Shell = ?GET_OPT(shell, Opts),
+ Exec = ?GET_OPT(exec, Opts),
+ CliSpec = case ?GET_OPT(ssh_cli, Opts) of
+ undefined -> {ssh_cli, [Shell]};
+ Spec -> Spec
+ end,
C#connection{cli_spec = CliSpec,
exec = Exec,
system_supervisor = SystemSup,
@@ -426,41 +427,38 @@ init_connection(server, C = #connection{}, Opts) ->
init_ssh_record(Role, Socket, Opts) ->
{ok, PeerAddr} = inet:peername(Socket),
- KeyCb = proplists:get_value(key_cb, Opts, ssh_file),
- AuthMethods = proplists:get_value(auth_methods,
- Opts,
- case Role of
- server -> ?SUPPORTED_AUTH_METHODS;
- client -> undefined
- end),
+ KeyCb = ?GET_OPT(key_cb, Opts),
+ AuthMethods =
+ case Role of
+ server -> ?GET_OPT(auth_methods, Opts);
+ client -> undefined
+ end,
S0 = #ssh{role = Role,
key_cb = KeyCb,
opts = Opts,
userauth_supported_methods = AuthMethods,
available_host_keys = supported_host_keys(Role, KeyCb, Opts),
- random_length_padding = proplists:get_value(max_random_length_padding,
- Opts,
- (#ssh{})#ssh.random_length_padding)
+ random_length_padding = ?GET_OPT(max_random_length_padding, Opts)
},
{Vsn, Version} = ssh_transport:versions(Role, Opts),
case Role of
client ->
- PeerName = proplists:get_value(host, Opts),
+ PeerName = ?GET_INTERNAL_OPT(host, Opts),
S0#ssh{c_vsn = Vsn,
c_version = Version,
- io_cb = case proplists:get_value(user_interaction, Opts, true) of
+ io_cb = case ?GET_OPT(user_interaction, Opts) of
true -> ssh_io;
false -> ssh_no_io
end,
- userauth_quiet_mode = proplists:get_value(quiet_mode, Opts, false),
+ userauth_quiet_mode = ?GET_OPT(quiet_mode, Opts),
peer = {PeerName, PeerAddr}
};
server ->
S0#ssh{s_vsn = Vsn,
s_version = Version,
- io_cb = proplists:get_value(io_cb, Opts, ssh_io),
+ io_cb = ?GET_INTERNAL_OPT(io_cb, Opts, ssh_io),
userauth_methods = string:tokens(AuthMethods, ","),
kb_tries_left = 3,
peer = {undefined, PeerAddr}
@@ -849,14 +847,12 @@ handle_event(_, Msg = #ssh_msg_userauth_failure{}, {userauth_keyboard_interactiv
handle_event(_, Msg=#ssh_msg_userauth_failure{}, {userauth_keyboard_interactive_info_response, client},
#data{ssh_params = Ssh0} = D0) ->
Opts = Ssh0#ssh.opts,
- D = case proplists:get_value(password, Opts) of
+ D = case ?GET_OPT(password, Opts) of
undefined ->
D0;
_ ->
D0#data{ssh_params =
- Ssh0#ssh{opts =
- lists:keyreplace(password,1,Opts,
- {password,not_ok})}} % FIXME:intermodule dependency
+ Ssh0#ssh{opts = ?PUT_OPT({password,not_ok}, Opts)}} % FIXME:intermodule dependency
end,
{next_state, {userauth,client}, D, [{next_event, internal, Msg}]};
@@ -954,7 +950,7 @@ handle_event(cast, renegotiate, _, _) ->
handle_event(cast, data_size, {connected,Role}, D) ->
{ok, [{send_oct,Sent0}]} = inet:getstat(D#data.socket, [send_oct]),
Sent = Sent0 - D#data.last_size_rekey,
- MaxSent = proplists:get_value(rekey_limit, D#data.opts, 1024000000),
+ MaxSent = ?GET_OPT(rekey_limit, D#data.opts),
timer:apply_after(?REKEY_DATA_TIMOUT, gen_statem, cast, [self(), data_size]),
case Sent >= MaxSent of
true ->
@@ -1294,11 +1290,12 @@ handle_event(info, UnexpectedMessage, StateName, D = #data{ssh_params = Ssh}) ->
"Unexpected message '~p' received in state '~p'\n"
"Role: ~p\n"
"Peer: ~p\n"
- "Local Address: ~p\n", [UnexpectedMessage,
- StateName,
- Ssh#ssh.role,
- Ssh#ssh.peer,
- proplists:get_value(address, Ssh#ssh.opts)])),
+ "Local Address: ~p\n",
+ [UnexpectedMessage,
+ StateName,
+ Ssh#ssh.role,
+ Ssh#ssh.peer,
+ ?GET_INTERNAL_OPT(address, Ssh#ssh.opts)])),
error_logger:info_report(Msg),
keep_state_and_data;
@@ -1312,11 +1309,12 @@ handle_event(info, UnexpectedMessage, StateName, D = #data{ssh_params = Ssh}) ->
"Message: ~p\n"
"Role: ~p\n"
"Peer: ~p\n"
- "Local Address: ~p\n", [Other,
- UnexpectedMessage,
- Ssh#ssh.role,
- element(2,Ssh#ssh.peer),
- proplists:get_value(address, Ssh#ssh.opts)]
+ "Local Address: ~p\n",
+ [Other,
+ UnexpectedMessage,
+ Ssh#ssh.role,
+ element(2,Ssh#ssh.peer),
+ ?GET_INTERNAL_OPT(address, Ssh#ssh.opts)]
)),
error_logger:error_report(Msg),
keep_state_and_data
@@ -1438,11 +1436,11 @@ code_change(_OldVsn, StateName, State, _Extra) ->
%%--------------------------------------------------------------------
%% Starting
-start_the_connection_child(UserPid, Role, Socket, Options) ->
- Sups = proplists:get_value(supervisors, Options),
+start_the_connection_child(UserPid, Role, Socket, Options0) ->
+ Sups = ?GET_INTERNAL_OPT(supervisors, Options0),
ConnectionSup = proplists:get_value(connection_sup, Sups),
- Opts = [{supervisors, Sups}, {user_pid, UserPid} | proplists:get_value(ssh_opts, Options, [])],
- {ok, Pid} = ssh_connection_sup:start_child(ConnectionSup, [Role, Socket, Opts]),
+ Options = ?PUT_INTERNAL_OPT({user_pid,UserPid}, Options0),
+ {ok, Pid} = ssh_connection_sup:start_child(ConnectionSup, [Role, Socket, Options]),
ok = socket_control(Socket, Pid, Options),
Pid.
@@ -1499,7 +1497,7 @@ supported_host_keys(server, KeyCb, Options) ->
find_sup_hkeys(Options) ->
case proplists:get_value(public_key,
- proplists:get_value(preferred_algorithms,Options,[])
+ ?GET_OPT(preferred_algorithms,Options)
)
of
undefined ->
@@ -1512,9 +1510,10 @@ find_sup_hkeys(Options) ->
%% Alg :: atom()
-available_host_key(KeyCb, Alg, Opts) ->
- element(1, catch KeyCb:host_key(Alg, Opts)) == ok.
-
+available_host_key({KeyCb,KeyCbOpts}, Alg, Opts) ->
+ UserOpts = ?GET_OPT(user_options, Opts),
+ element(1,
+ catch KeyCb:host_key(Alg, [{key_cb_private,KeyCbOpts}|UserOpts])) == ok.
send_msg(Msg, State=#data{ssh_params=Ssh0}) when is_tuple(Msg) ->
{Bytes, Ssh} = ssh_transport:ssh_packet(Msg, Ssh0),
@@ -1773,7 +1772,7 @@ get_repl(X, Acc) ->
disconnect_fun({disconnect,Msg}, D) ->
disconnect_fun(Msg, D);
disconnect_fun(Reason, #data{opts=Opts}) ->
- case proplists:get_value(disconnectfun, Opts) of
+ case ?GET_OPT(disconnectfun, Opts) of
undefined ->
ok;
Fun ->
@@ -1783,7 +1782,7 @@ disconnect_fun(Reason, #data{opts=Opts}) ->
unexpected_fun(UnexpectedMessage, #data{opts = Opts,
ssh_params = #ssh{peer = {_,Peer} }
} ) ->
- case proplists:get_value(unexpectedfun, Opts) of
+ case ?GET_OPT(unexpectedfun, Opts) of
undefined ->
report;
Fun ->
@@ -1795,7 +1794,7 @@ debug_fun(#ssh_msg_debug{always_display = Display,
message = DbgMsg,
language = Lang},
#data{opts = Opts}) ->
- case proplists:get_value(ssh_msg_debug_fun, Opts) of
+ case ?GET_OPT(ssh_msg_debug_fun, Opts) of
undefined ->
ok;
Fun ->
@@ -1805,7 +1804,7 @@ debug_fun(#ssh_msg_debug{always_display = Display,
connected_fun(User, Method, #data{ssh_params = #ssh{peer = {_,Peer}},
opts = Opts}) ->
- case proplists:get_value(connectfun, Opts) of
+ case ?GET_OPT(connectfun, Opts) of
undefined ->
ok;
Fun ->
@@ -1824,7 +1823,7 @@ retry_fun(User, Reason, #data{ssh_params = #ssh{opts = Opts,
_ ->
{infofun, Reason}
end,
- Fun = proplists:get_value(Tag, Opts, fun(_,_)-> ok end),
+ Fun = ?GET_OPT(Tag, Opts),
try erlang:fun_info(Fun, arity)
of
{arity, 2} -> %% Backwards compatible
@@ -1843,7 +1842,7 @@ retry_fun(User, Reason, #data{ssh_params = #ssh{opts = Opts,
%%% channels open for a while.
cache_init_idle_timer(D) ->
- case proplists:get_value(idle_time, D#data.opts, infinity) of
+ case ?GET_OPT(idle_time, D#data.opts) of
infinity ->
D#data{idle_timer_value = infinity,
idle_timer_ref = infinity % A flag used later...
@@ -1906,9 +1905,8 @@ start_channel_request_timer(Channel, From, Time) ->
%%% Connection start and initalization helpers
socket_control(Socket, Pid, Options) ->
- {_, TransportCallback, _} = % For example {_,gen_tcp,_}
- proplists:get_value(transport, Options, ?DefaultTransport),
- case TransportCallback:controlling_process(Socket, Pid) of
+ {_, Callback, _} = ?GET_OPT(transport, Options),
+ case Callback:controlling_process(Socket, Pid) of
ok ->
gen_statem:cast(Pid, socket_control);
{error, Reason} ->
diff --git a/lib/ssh/src/ssh_file.erl b/lib/ssh/src/ssh_file.erl
index 216f65f33a..898b4cc5c4 100644
--- a/lib/ssh/src/ssh_file.erl
+++ b/lib/ssh/src/ssh_file.erl
@@ -192,8 +192,8 @@ lookup_user_key(Key, User, Opts) ->
ssh_dir({remoteuser, User}, Opts) ->
case proplists:get_value(user_dir_fun, Opts) of
undefined ->
- case proplists:get_value(user_dir, Opts) of
- undefined ->
+ case proplists:get_value(user_dir, Opts, false) of
+ false ->
default_user_dir();
Dir ->
Dir
diff --git a/lib/ssh/src/ssh_io.erl b/lib/ssh/src/ssh_io.erl
index 1d8f370884..6828fd4760 100644
--- a/lib/ssh/src/ssh_io.erl
+++ b/lib/ssh/src/ssh_io.erl
@@ -27,17 +27,17 @@
-export([yes_no/2, read_password/2, read_line/2, format/2]).
-include("ssh.hrl").
-read_line(Prompt, Ssh) ->
+read_line(Prompt, Opts) ->
format("~s", [listify(Prompt)]),
- proplists:get_value(user_pid, Ssh) ! {self(), question},
+ ?GET_INTERNAL_OPT(user_pid, Opts) ! {self(), question},
receive
Answer when is_list(Answer) ->
Answer
end.
-yes_no(Prompt, Ssh) ->
+yes_no(Prompt, Opts) ->
format("~s [y/n]?", [Prompt]),
- proplists:get_value(user_pid, Ssh#ssh.opts) ! {self(), question},
+ ?GET_INTERNAL_OPT(user_pid, Opts) ! {self(), question},
receive
%% I can't see that the atoms y and n are ever received, but it must
%% be investigated before removing
@@ -52,15 +52,13 @@ yes_no(Prompt, Ssh) ->
"N" -> no;
_ ->
format("please answer y or n\n",[]),
- yes_no(Prompt, Ssh)
+ yes_no(Prompt, Opts)
end
end.
-
-read_password(Prompt, #ssh{opts=Opts}) -> read_password(Prompt, Opts);
-read_password(Prompt, Opts) when is_list(Opts) ->
+read_password(Prompt, Opts) ->
format("~s", [listify(Prompt)]),
- proplists:get_value(user_pid, Opts) ! {self(), user_password},
+ ?GET_INTERNAL_OPT(user_pid, Opts) ! {self(), user_password},
receive
Answer when is_list(Answer) ->
case trim(Answer) of
diff --git a/lib/ssh/src/ssh_options.erl b/lib/ssh/src/ssh_options.erl
new file mode 100644
index 0000000000..52dea5d183
--- /dev/null
+++ b/lib/ssh/src/ssh_options.erl
@@ -0,0 +1,897 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+
+-module(ssh_options).
+
+-include("ssh.hrl").
+-include_lib("kernel/include/file.hrl").
+
+-export([default/1,
+ get_value/5, get_value/6,
+ put_value/5,
+ handle_options/2
+ ]).
+
+-export_type([options/0
+ ]).
+
+%%%================================================================
+%%% Types
+
+-type options() :: #{socket_options := socket_options(),
+ internal_options := internal_options(),
+ option_key() => any()
+ }.
+
+-type socket_options() :: proplists:proplist().
+-type internal_options() :: #{option_key() => any()}.
+
+-type option_key() :: atom().
+
+-type option_in() :: proplists:property() | proplists:proplist() .
+
+-type option_class() :: internal_options | socket_options | user_options .
+
+-type option_declaration() :: #{class := user_options,
+ chk := fun((any) -> boolean() | {true,any()}),
+ default => any()
+ }.
+
+-type option_declarations() :: #{ {option_key(),def} := option_declaration() }.
+
+-type role() :: client | server .
+
+-type error() :: {error,{eoptions,any()}} .
+
+%%%================================================================
+%%%
+%%% Get an option
+%%%
+
+-spec get_value(option_class(), option_key(), options(),
+ atom(), non_neg_integer()) -> any() | no_return().
+
+get_value(Class, Key, Opts, _CallerMod, _CallerLine) when is_map(Opts) ->
+ case Class of
+ internal_options -> maps:get(Key, maps:get(internal_options,Opts));
+ socket_options -> proplists:get_value(Key, maps:get(socket_options,Opts));
+ user_options -> maps:get(Key, Opts)
+ end;
+get_value(Class, Key, Opts, _CallerMod, _CallerLine) ->
+ io:format("*** Bad Opts GET OPT ~p ~p:~p Key=~p,~n Opts=~p~n",[Class,_CallerMod,_CallerLine,Key,Opts]),
+ error({bad_options,Class, Key, Opts, _CallerMod, _CallerLine}).
+
+
+-spec get_value(option_class(), option_key(), options(), any(),
+ atom(), non_neg_integer()) -> any() | no_return().
+
+get_value(socket_options, Key, Opts, Def, _CallerMod, _CallerLine) when is_map(Opts) ->
+ proplists:get_value(Key, maps:get(socket_options,Opts), Def);
+get_value(Class, Key, Opts, Def, CallerMod, CallerLine) when is_map(Opts) ->
+ try get_value(Class, Key, Opts, CallerMod, CallerLine)
+ catch
+ error:{badkey,Key} -> Def
+ end;
+get_value(Class, Key, Opts, _Def, _CallerMod, _CallerLine) ->
+ io:format("*** Bad Opts GET OPT ~p ~p:~p Key=~p,~n Opts=~p~n",[Class,_CallerMod,_CallerLine,Key,Opts]),
+ error({bad_options,Class, Key, Opts, _CallerMod, _CallerLine}).
+
+
+%%%================================================================
+%%%
+%%% Put an option
+%%%
+
+-spec put_value(option_class(), option_in(), options(),
+ atom(), non_neg_integer()) -> options().
+
+put_value(user_options, KeyVal, Opts, _CallerMod, _CallerLine) when is_map(Opts) ->
+ put_user_value(KeyVal, Opts);
+
+put_value(internal_options, KeyVal, Opts, _CallerMod, _CallerLine) when is_map(Opts) ->
+ InternalOpts = maps:get(internal_options,Opts),
+ Opts#{internal_options := put_internal_value(KeyVal, InternalOpts)};
+
+put_value(socket_options, KeyVal, Opts, _CallerMod, _CallerLine) when is_map(Opts) ->
+ SocketOpts = maps:get(socket_options,Opts),
+ Opts#{socket_options := put_socket_value(KeyVal, SocketOpts)}.
+
+
+%%%----------------
+put_user_value(L, Opts) when is_list(L) ->
+ lists:foldl(fun put_user_value/2, Opts, L);
+put_user_value({Key,Value}, Opts) ->
+ Opts#{Key := Value}.
+
+%%%----------------
+put_internal_value(L, IntOpts) when is_list(L) ->
+ lists:foldl(fun put_internal_value/2, IntOpts, L);
+put_internal_value({Key,Value}, IntOpts) ->
+ IntOpts#{Key => Value}.
+
+%%%----------------
+put_socket_value(L, SockOpts) when is_list(L) ->
+ L ++ SockOpts;
+put_socket_value({Key,Value}, SockOpts) ->
+ [{Key,Value} | SockOpts];
+put_socket_value(A, SockOpts) when is_atom(A) ->
+ [A | SockOpts].
+
+%%%================================================================
+%%%
+%%% Initialize the options
+%%%
+
+-spec handle_options(role(), proplists:proplist()) -> options() | error() .
+
+-spec handle_options(role(), proplists:proplist(), options()) -> options() | error() .
+
+handle_options(Role, PropList0) ->
+ handle_options(Role, PropList0, #{socket_options => [],
+ internal_options => #{},
+ user_options => []
+ }).
+
+handle_options(Role, PropList0, Opts0) when is_map(Opts0),
+ is_list(PropList0) ->
+ PropList1 = proplists:unfold(PropList0),
+ try
+ OptionDefinitions = default(Role),
+ InitialMap =
+ maps:fold(
+ fun({K,def}, #{default:=V}, M) -> M#{K=>V};
+ (_,_,M) -> M
+ end,
+ Opts0#{user_options =>
+ maps:get(user_options,Opts0) ++ PropList1
+ },
+ OptionDefinitions),
+ %% Enter the user's values into the map; unknown keys are
+ %% treated as socket options
+ lists:foldl(fun(KV, Vals) ->
+ save(KV, OptionDefinitions, Vals)
+ end, InitialMap, PropList1)
+ catch
+ error:{eoptions, KV, undefined} ->
+ {error, {eoptions,KV}};
+
+ error:{eoptions, KV, Txt} when is_list(Txt) ->
+ {error, {eoptions,{KV,lists:flatten(Txt)}}};
+
+ error:{eoptions, KV, Extra} ->
+ {error, {eoptions,{KV,Extra}}}
+ end.
+
+
+check_fun(Key, Defs) ->
+ #{chk := Fun} = maps:get({Key,def}, Defs),
+ Fun.
+
+%%%================================================================
+%%%
+%%% Check and save one option
+%%%
+
+
+%%% First some prohibited inet options:
+save({K,V}, _, _) when K == reuseaddr ;
+ K == active
+ ->
+ forbidden_option(K, V);
+
+%%% then compatibility conversions:
+save({allow_user_interaction,V}, Opts, Vals) ->
+ save({user_interaction,V}, Opts, Vals);
+
+save({public_key_alg,V}, Defs, Vals) -> % To remove in OTP-20
+ New = case V of
+ 'ssh-rsa' -> ['ssh-rsa', 'ssh-dss'];
+ ssh_rsa -> ['ssh-rsa', 'ssh-dss'];
+ 'ssh-dss' -> ['ssh-dss', 'ssh-rsa'];
+ ssh_dsa -> ['ssh-dss', 'ssh-rsa'];
+ _ -> error({eoptions, {public_key_alg,V},
+ "Unknown algorithm, try pref_public_key_algs instead"})
+ end,
+ save({pref_public_key_algs,New}, Defs, Vals);
+
+%% Special case for socket options 'inet' and 'inet6'
+save(Inet, Defs, OptMap) when Inet==inet ; Inet==inet6 ->
+ save({inet,Inet}, Defs, OptMap);
+
+%% Two clauses to prepare for a proplists:unfold
+save({Inet,true}, Defs, OptMap) when Inet==inet ; Inet==inet6 -> save({inet,Inet}, Defs, OptMap);
+save({Inet,false}, _Defs, OptMap) when Inet==inet ; Inet==inet6 -> OptMap;
+
+%% and finaly the 'real stuff':
+save({Key,Value}, Defs, OptMap) when is_map(OptMap) ->
+ try (check_fun(Key,Defs))(Value)
+ of
+ true ->
+ OptMap#{Key := Value};
+ {true, ModifiedValue} ->
+ OptMap#{Key := ModifiedValue};
+ false ->
+ error({eoptions, {Key,Value}, "Bad value"})
+ catch
+ %% An unknown Key (= not in the definition map) is
+ %% regarded as an inet option:
+ error:{badkey,{inet,def}} ->
+ %% atomic (= non-tuple) options 'inet' and 'inet6':
+ OptMap#{socket_options := [Value | maps:get(socket_options,OptMap)]};
+ error:{badkey,{Key,def}} ->
+ OptMap#{socket_options := [{Key,Value} | maps:get(socket_options,OptMap)]};
+
+ %% But a Key that is known but the value does not validate
+ %% by the check fun will give an error exception:
+ error:{check,{BadValue,Extra}} ->
+ error({eoptions, {Key,BadValue}, Extra})
+ end.
+
+%%%================================================================
+%%%
+%%% Default options
+%%%
+
+-spec default(role() | common) -> option_declarations() .
+
+default(server) ->
+ (default(common))
+ #{
+ {subsystems, def} =>
+ #{default => [ssh_sftpd:subsystem_spec([])],
+ chk => fun(L) ->
+ is_list(L) andalso
+ lists:all(fun({Name,{CB,Args}}) ->
+ check_string(Name) andalso
+ is_atom(CB) andalso
+ is_list(Args);
+ (_) ->
+ false
+ end, L)
+ end,
+ class => user_options
+ },
+
+ {shell, def} =>
+ #{default => {shell, start, []},
+ chk => fun({M,F,A}) -> is_atom(M) andalso is_atom(F) andalso is_list(A);
+ (V) -> check_function1(V) orelse check_function2(V)
+ end,
+ class => user_options
+ },
+
+ {exec, def} => % FIXME: need some archeology....
+ #{default => undefined,
+ chk => fun({M,F,_}) -> is_atom(M) andalso is_atom(F);
+ (V) -> is_function(V)
+ end,
+ class => user_options
+ },
+
+ {ssh_cli, def} =>
+ #{default => undefined,
+ chk => fun({Cb, As}) -> is_atom(Cb) andalso is_list(As);
+ (V) -> V == no_cli
+ end,
+ class => user_options
+ },
+
+ {system_dir, def} =>
+ #{default => "/etc/ssh",
+ chk => fun(V) -> check_string(V) andalso check_dir(V) end,
+ class => user_options
+ },
+
+ {auth_methods, def} =>
+ #{default => ?SUPPORTED_AUTH_METHODS,
+ chk => fun check_string/1,
+ class => user_options
+ },
+
+ {auth_method_kb_interactive_data, def} =>
+ #{default => undefined, % Default value can be constructed when User is known
+ chk => fun({S1,S2,S3,B}) ->
+ check_string(S1) andalso
+ check_string(S2) andalso
+ check_string(S3) andalso
+ is_boolean(B);
+ (F) ->
+ check_function3(F)
+ end,
+ class => user_options
+ },
+
+ {user_passwords, def} =>
+ #{default => [],
+ chk => fun(V) ->
+ is_list(V) andalso
+ lists:all(fun({S1,S2}) ->
+ check_string(S1) andalso
+ check_string(S2)
+ end, V)
+ end,
+ class => user_options
+ },
+
+ {password, def} =>
+ #{default => undefined,
+ chk => fun check_string/1,
+ class => user_options
+ },
+
+ {dh_gex_groups, def} =>
+ #{default => undefined,
+ chk => fun check_dh_gex_groups/1,
+ class => user_options
+ },
+
+ {dh_gex_limits, def} =>
+ #{default => {0, infinity},
+ chk => fun({I1,I2}) ->
+ check_pos_integer(I1) andalso
+ check_pos_integer(I2) andalso
+ I1 < I2;
+ (_) ->
+ false
+ end,
+ class => user_options
+ },
+
+ {pwdfun, def} =>
+ #{default => undefined,
+ chk => fun(V) -> check_function4(V) orelse check_function2(V) end,
+ class => user_options
+ },
+
+ {negotiation_timeout, def} =>
+ #{default => 2*60*1000,
+ chk => fun check_timeout/1,
+ class => user_options
+ },
+
+ {max_sessions, def} =>
+ #{default => infinity,
+ chk => fun check_pos_integer/1,
+ class => user_options
+ },
+
+ {max_channels, def} =>
+ #{default => infinity,
+ chk => fun check_pos_integer/1,
+ class => user_options
+ },
+
+ {parallel_login, def} =>
+ #{default => false,
+ chk => fun erlang:is_boolean/1,
+ class => user_options
+ },
+
+ {minimal_remote_max_packet_size, def} =>
+ #{default => 0,
+ chk => fun check_pos_integer/1,
+ class => user_options
+ },
+
+ {failfun, def} =>
+ #{default => fun(_,_,_) -> void end,
+ chk => fun(V) -> check_function3(V) orelse
+ check_function2(V) % Backwards compatibility
+ end,
+ class => user_options
+ },
+
+ {connectfun, def} =>
+ #{default => fun(_,_,_) -> void end,
+ chk => fun check_function3/1,
+ class => user_options
+ },
+
+%%%%% Undocumented
+ {infofun, def} =>
+ #{default => fun(_,_,_) -> void end,
+ chk => fun(V) -> check_function3(V) orelse
+ check_function2(V) % Backwards compatibility
+ end,
+ class => user_options
+ }
+ };
+
+default(client) ->
+ (default(common))
+ #{
+ {dsa_pass_phrase, def} =>
+ #{default => undefined,
+ chk => fun check_string/1,
+ class => user_options
+ },
+
+ {rsa_pass_phrase, def} =>
+ #{default => undefined,
+ chk => fun check_string/1,
+ class => user_options
+ },
+
+ {silently_accept_hosts, def} =>
+ #{default => false,
+ chk => fun check_silently_accept_hosts/1,
+ class => user_options
+ },
+
+ {user_interaction, def} =>
+ #{default => true,
+ chk => fun erlang:is_boolean/1,
+ class => user_options
+ },
+
+ {pref_public_key_algs, def} =>
+ #{default =>
+ %% Get dynamically supported keys in the order of the ?SUPPORTED_USER_KEYS
+ [A || A <- ?SUPPORTED_USER_KEYS,
+ lists:member(A, ssh_transport:supported_algorithms(public_key))],
+ chk =>
+ fun check_pref_public_key_algs/1,
+ class =>
+ ssh
+ },
+
+ {dh_gex_limits, def} =>
+ #{default => {1024, 6144, 8192}, % FIXME: Is this true nowadays?
+ chk => fun({Min,I,Max}) ->
+ lists:all(fun check_pos_integer/1,
+ [Min,I,Max]);
+ (_) -> false
+ end,
+ class => user_options
+ },
+
+ {connect_timeout, def} =>
+ #{default => infinity,
+ chk => fun check_timeout/1,
+ class => user_options
+ },
+
+ {user, def} =>
+ #{default =>
+ begin
+ Env = case os:type() of
+ {win32, _} -> "USERNAME";
+ {unix, _} -> "LOGNAME"
+ end,
+ case os:getenv(Env) of
+ false ->
+ case os:getenv("USER") of
+ false -> undefined;
+ User -> User
+ end;
+ User ->
+ User
+ end
+ end,
+ chk => fun check_string/1,
+ class => user_options
+ },
+
+ {password, def} =>
+ #{default => undefined,
+ chk => fun check_string/1,
+ class => user_options
+ },
+
+ {quiet_mode, def} =>
+ #{default => false,
+ chk => fun erlang:is_boolean/1,
+ class => user_options
+ },
+
+ {idle_time, def} =>
+ #{default => infinity,
+ chk => fun check_timeout/1,
+ class => user_options
+ },
+
+%%%%% Undocumented
+ {keyboard_interact_fun, def} =>
+ #{default => undefined,
+ chk => fun check_function3/1,
+ class => user_options
+ }
+ };
+
+default(common) ->
+ #{
+ {user_dir, def} =>
+ #{default => false, % FIXME: TBD ~/.ssh at time of call when user is known
+ chk => fun(V) -> check_string(V) andalso check_dir(V) end,
+ class => user_options
+ },
+
+ {preferred_algorithms, def} =>
+ #{default => ssh:default_algorithms(),
+ chk => fun check_preferred_algorithms/1,
+ class => user_options
+ },
+
+ {id_string, def} =>
+ #{default => undefined, % FIXME: see ssh_transport:ssh_vsn/0
+ chk => fun(random) ->
+ {true, {random,2,5}}; % 2 - 5 random characters
+ ({random,I1,I2}) ->
+ %% Undocumented
+ check_pos_integer(I1) andalso
+ check_pos_integer(I2) andalso
+ I1=
+ check_string(V)
+ end,
+ class => user_options
+ },
+
+ {key_cb, def} =>
+ #{default => {ssh_file, []},
+ chk => fun({Mod,Opts}) -> is_atom(Mod) andalso is_list(Opts);
+ (Mod) when is_atom(Mod) -> {true, {Mod,[]}};
+ (_) -> false
+ end,
+ class => user_options
+ },
+
+ {profile, def} =>
+ #{default => ?DEFAULT_PROFILE,
+ chk => fun erlang:is_atom/1,
+ class => user_options
+ },
+
+ %% This is a "SocketOption"...
+ %% {fd, def} =>
+ %% #{default => undefined,
+ %% chk => fun erlang:is_integer/1,
+ %% class => user_options
+ %% },
+
+ {disconnectfun, def} =>
+ #{default => fun(_) -> void end,
+ chk => fun check_function1/1,
+ class => user_options
+ },
+
+ {unexpectedfun, def} =>
+ #{default => fun(_,_) -> report end,
+ chk => fun check_function2/1,
+ class => user_options
+ },
+
+ {ssh_msg_debug_fun, def} =>
+ #{default => fun(_,_,_,_) -> void end,
+ chk => fun check_function4/1,
+ class => user_options
+ },
+
+ {rekey_limit, def} => % FIXME: Why not common?
+ #{default => 1024000000,
+ chk => fun check_non_neg_integer/1,
+ class => user_options
+ },
+
+%%%%% Undocumented
+ {transport, def} =>
+ #{default => ?DEFAULT_TRANSPORT,
+ chk => fun({A,B,C}) ->
+ is_atom(A) andalso is_atom(B) andalso is_atom(C)
+ end,
+ class => user_options
+ },
+
+ {vsn, def} =>
+ #{default => {2,0},
+ chk => fun({Maj,Min}) -> check_non_neg_integer(Maj) andalso check_non_neg_integer(Min);
+ (_) -> false
+ end,
+ class => user_options
+ },
+
+ {tstflg, def} =>
+ #{default => [],
+ chk => fun erlang:is_list/1,
+ class => user_options
+ },
+
+ {user_dir_fun, def} =>
+ #{default => undefined,
+ chk => fun check_function1/1,
+ class => user_options
+ },
+
+ {max_random_length_padding, def} =>
+ #{default => ?MAX_RND_PADDING_LEN,
+ chk => fun check_non_neg_integer/1,
+ class => user_options
+ }
+ }.
+
+
+%%%================================================================
+%%%================================================================
+%%%================================================================
+
+%%%
+%%% check_*/1 -> true | false | error({check,Spec})
+%%% See error_in_check/2,3
+%%%
+
+%%% error_in_check(BadValue) -> error_in_check(BadValue, undefined).
+
+error_in_check(BadValue, Extra) -> error({check,{BadValue,Extra}}).
+
+
+%%%----------------------------------------------------------------
+check_timeout(infinity) -> true;
+check_timeout(I) -> check_pos_integer(I).
+
+%%%----------------------------------------------------------------
+check_pos_integer(I) -> is_integer(I) andalso I>0.
+
+%%%----------------------------------------------------------------
+check_non_neg_integer(I) -> is_integer(I) andalso I>=0.
+
+%%%----------------------------------------------------------------
+check_function1(F) -> is_function(F,1).
+check_function2(F) -> is_function(F,2).
+check_function3(F) -> is_function(F,3).
+check_function4(F) -> is_function(F,4).
+
+%%%----------------------------------------------------------------
+check_pref_public_key_algs(V) ->
+ %% Get the dynamically supported keys, that is, thoose
+ %% that are stored
+ PKs = ssh_transport:supported_algorithms(public_key),
+ CHK = fun(A, Ack) ->
+ case lists:member(A, PKs) of
+ true ->
+ [A|Ack];
+ false ->
+ %% Check with the documented options, that is,
+ %% the one we can handle
+ case lists:member(A,?SUPPORTED_USER_KEYS) of
+ false ->
+ %% An algorithm ssh never can handle
+ error_in_check(A, "Not supported public key");
+ true ->
+ %% An algorithm ssh can handle, but not in
+ %% this very call
+ Ack
+ end
+ end
+ end,
+ case lists:foldr(
+ fun(ssh_dsa, Ack) -> CHK('ssh-dss', Ack); % compatibility
+ (ssh_rsa, Ack) -> CHK('ssh-rsa', Ack); % compatibility
+ (X, Ack) -> CHK(X, Ack)
+ end, [], V)
+ of
+ V -> true;
+ [] -> false;
+ V1 -> {true,V1}
+ end.
+
+
+%%%----------------------------------------------------------------
+%% Check that it is a directory and is readable
+check_dir(Dir) ->
+ case file:read_file_info(Dir) of
+ {ok, #file_info{type = directory,
+ access = Access}} ->
+ case Access of
+ read -> true;
+ read_write -> true;
+ _ -> error_in_check(Dir, eacces)
+ end;
+
+ {ok, #file_info{}}->
+ error_in_check(Dir, enotdir);
+
+ {error, Error} ->
+ error_in_check(Dir, Error)
+ end.
+
+%%%----------------------------------------------------------------
+check_string(S) -> is_list(S). % FIXME: stub
+
+%%%----------------------------------------------------------------
+check_dh_gex_groups({file,File}) when is_list(File) ->
+ case file:consult(File) of
+ {ok, GroupDefs} ->
+ check_dh_gex_groups(GroupDefs);
+ {error, Error} ->
+ error_in_check({file,File},Error)
+ end;
+
+check_dh_gex_groups({ssh_moduli_file,File}) when is_list(File) ->
+ case file:open(File,[read]) of
+ {ok,D} ->
+ try
+ read_moduli_file(D, 1, [])
+ of
+ {ok,Moduli} ->
+ check_dh_gex_groups(Moduli);
+ {error,Error} ->
+ error_in_check({ssh_moduli_file,File}, Error)
+ catch
+ _:_ ->
+ error_in_check({ssh_moduli_file,File}, "Bad format in file "++File)
+ after
+ file:close(D)
+ end;
+
+ {error, Error} ->
+ error_in_check({ssh_moduli_file,File}, Error)
+ end;
+
+check_dh_gex_groups(L0) when is_list(L0), is_tuple(hd(L0)) ->
+ {true,
+ collect_per_size(
+ lists:foldl(
+ fun({N,G,P}, Acc) when is_integer(N),N>0,
+ is_integer(G),G>0,
+ is_integer(P),P>0 ->
+ [{N,{G,P}} | Acc];
+ ({N,{G,P}}, Acc) when is_integer(N),N>0,
+ is_integer(G),G>0,
+ is_integer(P),P>0 ->
+ [{N,{G,P}} | Acc];
+ ({N,GPs}, Acc) when is_list(GPs) ->
+ lists:foldr(fun({Gi,Pi}, Acci) when is_integer(Gi),Gi>0,
+ is_integer(Pi),Pi>0 ->
+ [{N,{Gi,Pi}} | Acci]
+ end, Acc, GPs)
+ end, [], L0))};
+
+check_dh_gex_groups(_) ->
+ false.
+
+
+
+collect_per_size(L) ->
+ lists:foldr(
+ fun({Sz,GP}, [{Sz,GPs}|Acc]) -> [{Sz,[GP|GPs]}|Acc];
+ ({Sz,GP}, Acc) -> [{Sz,[GP]}|Acc]
+ end, [], lists:sort(L)).
+
+read_moduli_file(D, I, Acc) ->
+ case io:get_line(D,"") of
+ {error,Error} ->
+ {error,Error};
+ eof ->
+ {ok, Acc};
+ "#" ++ _ -> read_moduli_file(D, I+1, Acc);
+ <<"#",_/binary>> -> read_moduli_file(D, I+1, Acc);
+ Data ->
+ Line = if is_binary(Data) -> binary_to_list(Data);
+ is_list(Data) -> Data
+ end,
+ try
+ [_Time,_Class,_Tests,_Tries,Size,G,P] = string:tokens(Line," \r\n"),
+ M = {list_to_integer(Size),
+ {list_to_integer(G), list_to_integer(P,16)}
+ },
+ read_moduli_file(D, I+1, [M|Acc])
+ catch
+ _:_ ->
+ read_moduli_file(D, I+1, Acc)
+ end
+ end.
+
+%%%----------------------------------------------------------------
+-define(SHAs, [md5, sha, sha224, sha256, sha384, sha512]).
+
+check_silently_accept_hosts(B) when is_boolean(B) -> true;
+check_silently_accept_hosts(F) when is_function(F,2) -> true;
+check_silently_accept_hosts({S,F}) when is_atom(S),
+ is_function(F,2) ->
+ lists:member(S, ?SHAs) andalso
+ lists:member(S, proplists:get_value(hashs,crypto:supports()));
+check_silently_accept_hosts({L,F}) when is_list(L),
+ is_function(F,2) ->
+ lists:all(fun(S) ->
+ lists:member(S, ?SHAs) andalso
+ lists:member(S, proplists:get_value(hashs,crypto:supports()))
+ end, L);
+check_silently_accept_hosts(_) -> false.
+
+%%%----------------------------------------------------------------
+check_preferred_algorithms(Algs) ->
+ try alg_duplicates(Algs, [], [])
+ of
+ [] ->
+ {true,
+ [try ssh_transport:supported_algorithms(Key)
+ of
+ DefAlgs -> handle_pref_alg(Key,Vals,DefAlgs)
+ catch
+ _:_ -> error_in_check(Key,"Bad preferred_algorithms key")
+ end || {Key,Vals} <- Algs]
+ };
+
+ Dups ->
+ error_in_check(Dups, "Duplicates")
+ catch
+ _:_ ->
+ false
+ end.
+
+alg_duplicates([{K,V}|KVs], Ks, Dups0) ->
+ Dups =
+ case lists:member(K,Ks) of
+ true -> [K|Dups0];
+ false -> Dups0
+ end,
+ case V--lists:usort(V) of
+ [] -> alg_duplicates(KVs, [K|Ks], Dups);
+ Ds -> alg_duplicates(KVs, [K|Ks], Dups++Ds)
+ end;
+alg_duplicates([], _Ks, Dups) ->
+ Dups.
+
+handle_pref_alg(Key,
+ Vs=[{client2server,C2Ss=[_|_]},{server2client,S2Cs=[_|_]}],
+ [{client2server,Sup_C2Ss},{server2client,Sup_S2Cs}]
+ ) ->
+ chk_alg_vs(Key, C2Ss, Sup_C2Ss),
+ chk_alg_vs(Key, S2Cs, Sup_S2Cs),
+ {Key, Vs};
+
+handle_pref_alg(Key,
+ Vs=[{server2client,[_|_]},{client2server,[_|_]}],
+ Sup=[{client2server,_},{server2client,_}]
+ ) ->
+ handle_pref_alg(Key, lists:reverse(Vs), Sup);
+
+handle_pref_alg(Key,
+ Vs=[V|_],
+ Sup=[{client2server,_},{server2client,_}]
+ ) when is_atom(V) ->
+ handle_pref_alg(Key, [{client2server,Vs},{server2client,Vs}], Sup);
+
+handle_pref_alg(Key,
+ Vs=[V|_],
+ Sup=[S|_]
+ ) when is_atom(V), is_atom(S) ->
+ chk_alg_vs(Key, Vs, Sup),
+ {Key, Vs};
+
+handle_pref_alg(Key, Vs, _) ->
+ error_in_check({Key,Vs}, "Badly formed list").
+
+chk_alg_vs(OptKey, Values, SupportedValues) ->
+ case (Values -- SupportedValues) of
+ [] -> Values;
+ Bad -> error_in_check({OptKey,Bad}, "Unsupported value(s) found")
+ end.
+
+%%%----------------------------------------------------------------
+forbidden_option(K,V) ->
+ Txt = io_lib:format("The option '~s' is used internally. The "
+ "user is not allowed to specify this option.",
+ [K]),
+ error({eoptions, {K,V}, Txt}).
+
+%%%----------------------------------------------------------------
diff --git a/lib/ssh/src/ssh_sftp.erl b/lib/ssh/src/ssh_sftp.erl
index 8d994cdb43..140856c8e3 100644
--- a/lib/ssh/src/ssh_sftp.erl
+++ b/lib/ssh/src/ssh_sftp.erl
@@ -100,18 +100,14 @@ start_channel(Socket) when is_port(Socket) ->
start_channel(Host) when is_list(Host) ->
start_channel(Host, []).
-start_channel(Socket, Options) when is_port(Socket) ->
- Timeout =
- %% A mixture of ssh:connect and ssh_sftp:start_channel:
- case proplists:get_value(connect_timeout, Options, undefined) of
- undefined ->
- proplists:get_value(timeout, Options, infinity);
- TO ->
- TO
- end,
- case ssh:connect(Socket, Options, Timeout) of
+start_channel(Socket, UserOptions) when is_port(Socket) ->
+ {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:connect(Socket, SshOpts, Timeout) of
{ok,Cm} ->
- case start_channel(Cm, Options) of
+ case start_channel(Cm, UserOptions) of
{ok, Pid} ->
{ok, Pid, Cm};
Error ->
@@ -120,9 +116,9 @@ start_channel(Socket, Options) when is_port(Socket) ->
Error ->
Error
end;
-start_channel(Cm, Opts) when is_pid(Cm) ->
- Timeout = proplists:get_value(timeout, Opts, infinity),
- {_, ChanOpts, SftpOpts} = handle_options(Opts, [], [], []),
+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} ->
case ssh_channel:start(Cm, ChannelId,
@@ -143,15 +139,17 @@ start_channel(Cm, Opts) when is_pid(Cm) ->
Error
end;
-start_channel(Host, Opts) ->
- start_channel(Host, 22, Opts).
-start_channel(Host, Port, Opts) ->
- {SshOpts, ChanOpts, SftpOpts} = handle_options(Opts, [], [], []),
- Timeout = proplists:get_value(timeout, SftpOpts, infinity),
+start_channel(Host, UserOptions) ->
+ start_channel(Host, 22, UserOptions).
+
+start_channel(Host, Port, 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_channel:start(Cm, ChannelId, ?MODULE, [Cm,
- ChannelId, SftpOpts]) of
+ case ssh_channel:start(Cm, ChannelId, ?MODULE, [Cm,ChannelId,SftpOpts]) of
{ok, Pid} ->
case wait_for_version_negotiation(Pid, Timeout) of
ok ->
@@ -865,6 +863,9 @@ terminate(_Reason, State) ->
%%====================================================================
%% Internal functions
%%====================================================================
+handle_options(UserOptions) ->
+ handle_options(UserOptions, [], [], []).
+
handle_options([], Sftp, Chan, Ssh) ->
{Ssh, Chan, Sftp};
handle_options([{timeout, _} = Opt | Rest], Sftp, Chan, Ssh) ->
diff --git a/lib/ssh/src/ssh_subsystem_sup.erl b/lib/ssh/src/ssh_subsystem_sup.erl
index 637f5f398f..cf82db458f 100644
--- a/lib/ssh/src/ssh_subsystem_sup.erl
+++ b/lib/ssh/src/ssh_subsystem_sup.erl
@@ -26,6 +26,8 @@
-behaviour(supervisor).
+-include("ssh.hrl").
+
-export([start_link/1,
connection_supervisor/1,
channel_supervisor/1
@@ -37,8 +39,8 @@
%%%=========================================================================
%%% API
%%%=========================================================================
-start_link(Opts) ->
- supervisor:start_link(?MODULE, [Opts]).
+start_link(Options) ->
+ supervisor:start_link(?MODULE, [Options]).
connection_supervisor(SupPid) ->
Children = supervisor:which_children(SupPid),
@@ -53,42 +55,42 @@ channel_supervisor(SupPid) ->
%%%=========================================================================
-spec init( [term()] ) -> {ok,{supervisor:sup_flags(),[supervisor:child_spec()]}} | ignore .
-init([Opts]) ->
+init([Options]) ->
RestartStrategy = one_for_all,
MaxR = 0,
MaxT = 3600,
- Children = child_specs(Opts),
+ Children = child_specs(Options),
{ok, {{RestartStrategy, MaxR, MaxT}, Children}}.
%%%=========================================================================
%%% Internal functions
%%%=========================================================================
-child_specs(Opts) ->
- case proplists:get_value(role, Opts) of
+child_specs(Options) ->
+ case ?GET_INTERNAL_OPT(role, Options) of
client ->
[];
server ->
- [ssh_channel_child_spec(Opts), ssh_connectinon_child_spec(Opts)]
+ [ssh_channel_child_spec(Options), ssh_connectinon_child_spec(Options)]
end.
-ssh_connectinon_child_spec(Opts) ->
- Address = proplists:get_value(address, Opts),
- Port = proplists:get_value(port, Opts),
- Role = proplists:get_value(role, Opts),
+ssh_connectinon_child_spec(Options) ->
+ Address = ?GET_INTERNAL_OPT(address, Options),
+ Port = ?GET_INTERNAL_OPT(port, Options),
+ Role = ?GET_INTERNAL_OPT(role, Options),
Name = id(Role, ssh_connection_sup, Address, Port),
- StartFunc = {ssh_connection_sup, start_link, [Opts]},
+ StartFunc = {ssh_connection_sup, start_link, [Options]},
Restart = temporary,
Shutdown = 5000,
Modules = [ssh_connection_sup],
Type = supervisor,
{Name, StartFunc, Restart, Shutdown, Type, Modules}.
-ssh_channel_child_spec(Opts) ->
- Address = proplists:get_value(address, Opts),
- Port = proplists:get_value(port, Opts),
- Role = proplists:get_value(role, Opts),
+ssh_channel_child_spec(Options) ->
+ Address = ?GET_INTERNAL_OPT(address, Options),
+ Port = ?GET_INTERNAL_OPT(port, Options),
+ Role = ?GET_INTERNAL_OPT(role, Options),
Name = id(Role, ssh_channel_sup, Address, Port),
- StartFunc = {ssh_channel_sup, start_link, [Opts]},
+ StartFunc = {ssh_channel_sup, start_link, [Options]},
Restart = temporary,
Shutdown = infinity,
Modules = [ssh_channel_sup],
diff --git a/lib/ssh/src/ssh_system_sup.erl b/lib/ssh/src/ssh_system_sup.erl
index e97ac7b01a..b0bbd3aae5 100644
--- a/lib/ssh/src/ssh_system_sup.erl
+++ b/lib/ssh/src/ssh_system_sup.erl
@@ -45,12 +45,12 @@
%%%=========================================================================
%%% Internal API
%%%=========================================================================
-start_link(ServerOpts) ->
- Address = proplists:get_value(address, ServerOpts),
- Port = proplists:get_value(port, ServerOpts),
- Profile = proplists:get_value(profile, proplists:get_value(ssh_opts, ServerOpts), ?DEFAULT_PROFILE),
+start_link(Options) ->
+ Address = ?GET_INTERNAL_OPT(address, Options),
+ Port = ?GET_INTERNAL_OPT(port, Options),
+ Profile = ?GET_OPT(profile, Options),
Name = make_name(Address, Port, Profile),
- supervisor:start_link({local, Name}, ?MODULE, [ServerOpts]).
+ supervisor:start_link({local, Name}, ?MODULE, [Options]).
stop_listener(SysSup) ->
stop_acceptor(SysSup).
@@ -127,12 +127,12 @@ restart_acceptor(Address, Port, Profile) ->
%%%=========================================================================
-spec init( [term()] ) -> {ok,{supervisor:sup_flags(),[supervisor:child_spec()]}} | ignore .
-init([ServerOpts]) ->
+init([Options]) ->
RestartStrategy = one_for_one,
MaxR = 0,
MaxT = 3600,
- Children = case proplists:get_value(asocket,ServerOpts) of
- undefined -> child_specs(ServerOpts);
+ Children = case ?GET_INTERNAL_OPT(asocket,Options,undefined) of
+ undefined -> child_specs(Options);
_ -> []
end,
{ok, {{RestartStrategy, MaxR, MaxT}, Children}}.
@@ -140,24 +140,24 @@ init([ServerOpts]) ->
%%%=========================================================================
%%% Internal functions
%%%=========================================================================
-child_specs(ServerOpts) ->
- [ssh_acceptor_child_spec(ServerOpts)].
+child_specs(Options) ->
+ [ssh_acceptor_child_spec(Options)].
-ssh_acceptor_child_spec(ServerOpts) ->
- Address = proplists:get_value(address, ServerOpts),
- Port = proplists:get_value(port, ServerOpts),
- Profile = proplists:get_value(profile, proplists:get_value(ssh_opts, ServerOpts), ?DEFAULT_PROFILE),
+ssh_acceptor_child_spec(Options) ->
+ Address = ?GET_INTERNAL_OPT(address, Options),
+ Port = ?GET_INTERNAL_OPT(port, Options),
+ Profile = ?GET_OPT(profile, Options),
Name = id(ssh_acceptor_sup, Address, Port, Profile),
- StartFunc = {ssh_acceptor_sup, start_link, [ServerOpts]},
+ StartFunc = {ssh_acceptor_sup, start_link, [Options]},
Restart = transient,
Shutdown = infinity,
Modules = [ssh_acceptor_sup],
Type = supervisor,
{Name, StartFunc, Restart, Shutdown, Type, Modules}.
-ssh_subsystem_child_spec(ServerOpts) ->
+ssh_subsystem_child_spec(Options) ->
Name = make_ref(),
- StartFunc = {ssh_subsystem_sup, start_link, [ServerOpts]},
+ StartFunc = {ssh_subsystem_sup, start_link, [Options]},
Restart = temporary,
Shutdown = infinity,
Modules = [ssh_subsystem_sup],
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index a17ad560d1..02c995399a 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -153,14 +153,14 @@ supported_algorithms(compression) ->
%%%----------------------------------------------------------------------------
versions(client, Options)->
- Vsn = proplists:get_value(vsn, Options, ?DEFAULT_CLIENT_VERSION),
+ Vsn = ?GET_INTERNAL_OPT(vsn, Options, ?DEFAULT_CLIENT_VERSION),
{Vsn, format_version(Vsn, software_version(Options))};
versions(server, Options) ->
- Vsn = proplists:get_value(vsn, Options, ?DEFAULT_SERVER_VERSION),
+ Vsn = ?GET_INTERNAL_OPT(vsn, Options, ?DEFAULT_SERVER_VERSION),
{Vsn, format_version(Vsn, software_version(Options))}.
software_version(Options) ->
- case proplists:get_value(id_string, Options) of
+ case ?GET_OPT(id_string, Options) of
undefined ->
"Erlang"++ssh_vsn();
{random,Nlo,Nup} ->
@@ -171,7 +171,7 @@ software_version(Options) ->
ssh_vsn() ->
try {ok,L} = application:get_all_key(ssh),
- proplists:get_value(vsn,L,"")
+ proplists:get_value(vsn, L, "")
of
"" -> "";
VSN when is_list(VSN) -> "/" ++ VSN;
@@ -232,13 +232,7 @@ key_exchange_init_msg(Ssh0) ->
kex_init(#ssh{role = Role, opts = Opts, available_host_keys = HostKeyAlgs}) ->
Random = ssh_bits:random(16),
- PrefAlgs =
- case proplists:get_value(preferred_algorithms,Opts) of
- undefined ->
- default_algorithms();
- Algs0 ->
- Algs0
- end,
+ PrefAlgs = ?GET_OPT(preferred_algorithms, Opts),
kexinit_message(Role, Random, PrefAlgs, HostKeyAlgs).
key_init(client, Ssh, Value) ->
@@ -341,10 +335,7 @@ key_exchange_first_msg(Kex, Ssh0) when Kex == 'diffie-hellman-group1-sha1' ;
key_exchange_first_msg(Kex, Ssh0=#ssh{opts=Opts}) when Kex == 'diffie-hellman-group-exchange-sha1' ;
Kex == 'diffie-hellman-group-exchange-sha256' ->
- {Min,NBits0,Max} =
- proplists:get_value(dh_gex_limits, Opts, {?DEFAULT_DH_GROUP_MIN,
- ?DEFAULT_DH_GROUP_NBITS,
- ?DEFAULT_DH_GROUP_MAX}),
+ {Min,NBits0,Max} = ?GET_OPT(dh_gex_limits, Opts),
DhBits = dh_bits(Ssh0#ssh.algorithms),
NBits1 =
%% NIST Special Publication 800-57 Part 1 Revision 4: Recommendation for Key Management
@@ -458,7 +449,7 @@ handle_kex_dh_gex_request(#ssh_msg_kex_dh_gex_request{min = Min0,
%% server
{Min, Max} = adjust_gex_min_max(Min0, Max0, Opts),
case public_key:dh_gex_group(Min, NBits, Max,
- proplists:get_value(dh_gex_groups,Opts)) of
+ ?GET_OPT(dh_gex_groups,Opts)) of
{ok, {_, {G,P}}} ->
{SshPacket, Ssh} =
ssh_packet(#ssh_msg_kex_dh_gex_group{p = P, g = G}, Ssh0),
@@ -492,7 +483,7 @@ handle_kex_dh_gex_request(#ssh_msg_kex_dh_gex_request_old{n = NBits},
Max0 = 8192,
{Min, Max} = adjust_gex_min_max(Min0, Max0, Opts),
case public_key:dh_gex_group(Min, NBits, Max,
- proplists:get_value(dh_gex_groups,Opts)) of
+ ?GET_OPT(dh_gex_groups,Opts)) of
{ok, {_, {G,P}}} ->
{SshPacket, Ssh} =
ssh_packet(#ssh_msg_kex_dh_gex_group{p = P, g = G}, Ssh0),
@@ -517,22 +508,18 @@ handle_kex_dh_gex_request(_, _) ->
adjust_gex_min_max(Min0, Max0, Opts) ->
- case proplists:get_value(dh_gex_limits, Opts) of
- undefined ->
- {Min0, Max0};
- {Min1, Max1} ->
- Min2 = max(Min0, Min1),
- Max2 = min(Max0, Max1),
- if
- Min2 =< Max2 ->
- {Min2, Max2};
- Max2 < Min2 ->
- ssh_connection_handler:disconnect(
- #ssh_msg_disconnect{
- code = ?SSH_DISCONNECT_PROTOCOL_ERROR,
- description = "No possible diffie-hellman-group-exchange group possible"
- })
- end
+ {Min1, Max1} = ?GET_OPT(dh_gex_limits, Opts),
+ Min2 = max(Min0, Min1),
+ Max2 = min(Max0, Max1),
+ if
+ Min2 =< Max2 ->
+ {Min2, Max2};
+ Max2 < Min2 ->
+ ssh_connection_handler:disconnect(
+ #ssh_msg_disconnect{
+ code = ?SSH_DISCONNECT_PROTOCOL_ERROR,
+ description = "No possible diffie-hellman-group-exchange group possible"
+ })
end.
@@ -719,9 +706,9 @@ sid(#ssh{session_id = Id}, _) ->
%% The host key should be read from storage
%%
get_host_key(SSH) ->
- #ssh{key_cb = Mod, opts = Opts, algorithms = ALG} = SSH,
-
- case Mod:host_key(ALG#alg.hkey, Opts) of
+ #ssh{key_cb = {KeyCb,KeyCbOpts}, opts = Opts, algorithms = ALG} = SSH,
+ UserOpts = ?GET_OPT(user_options, Opts),
+ case KeyCb:host_key(ALG#alg.hkey, [{key_cb_private,KeyCbOpts}|UserOpts]) of
{ok, #'RSAPrivateKey'{} = Key} -> Key;
{ok, #'DSAPrivateKey'{} = Key} -> Key;
{ok, #'ECPrivateKey'{} = Key} -> Key;
@@ -767,7 +754,7 @@ public_algo({#'ECPoint'{},{namedCurve,OID}}) ->
accepted_host(Ssh, PeerName, Public, Opts) ->
- case proplists:get_value(silently_accept_hosts, Opts, false) of
+ case ?GET_OPT(silently_accept_hosts, Opts) of
F when is_function(F,2) ->
true == (catch F(PeerName, public_key:ssh_hostkey_fingerprint(Public)));
{DigestAlg,F} when is_function(F,2) ->
@@ -778,15 +765,16 @@ accepted_host(Ssh, PeerName, Public, Opts) ->
yes == yes_no(Ssh, "New host " ++ PeerName ++ " accept")
end.
-known_host_key(#ssh{opts = Opts, key_cb = Mod, peer = {PeerName,_}} = Ssh,
+known_host_key(#ssh{opts = Opts, key_cb = {KeyCb,KeyCbOpts}, peer = {PeerName,_}} = Ssh,
Public, Alg) ->
- case Mod:is_host_key(Public, PeerName, Alg, Opts) of
+ UserOpts = ?GET_OPT(user_options, Opts),
+ case KeyCb:is_host_key(Public, PeerName, Alg, [{key_cb_private,KeyCbOpts}|UserOpts]) of
true ->
ok;
false ->
case accepted_host(Ssh, PeerName, Public, Opts) of
true ->
- Mod:add_host_key(PeerName, Public, Opts);
+ KeyCb:add_host_key(PeerName, Public, [{key_cb_private,KeyCbOpts}|UserOpts]);
false ->
{error, rejected}
end
@@ -1822,10 +1810,6 @@ len_supported(Name, Len) ->
same(Algs) -> [{client2server,Algs}, {server2client,Algs}].
-
-%% default_algorithms(kex) -> % Example of how to disable an algorithm
-%% supported_algorithms(kex, ['ecdh-sha2-nistp521']);
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Other utils
diff --git a/lib/ssh/src/sshd_sup.erl b/lib/ssh/src/sshd_sup.erl
index 04d2df30f7..14f1937abd 100644
--- a/lib/ssh/src/sshd_sup.erl
+++ b/lib/ssh/src/sshd_sup.erl
@@ -41,13 +41,13 @@
start_link(Servers) ->
supervisor:start_link({local, ?MODULE}, ?MODULE, [Servers]).
-start_child(ServerOpts) ->
- Address = proplists:get_value(address, ServerOpts),
- Port = proplists:get_value(port, ServerOpts),
- Profile = proplists:get_value(profile, proplists:get_value(ssh_opts, ServerOpts), ?DEFAULT_PROFILE),
+start_child(Options) ->
+ Address = ?GET_INTERNAL_OPT(address, Options),
+ Port = ?GET_INTERNAL_OPT(port, Options),
+ Profile = ?GET_OPT(profile, Options),
case ssh_system_sup:system_supervisor(Address, Port, Profile) of
undefined ->
- Spec = child_spec(Address, Port, ServerOpts),
+ Spec = child_spec(Address, Port, Options),
case supervisor:start_child(?MODULE, Spec) of
{error, already_present} ->
Name = id(Address, Port, Profile),
@@ -58,7 +58,7 @@ start_child(ServerOpts) ->
end;
Pid ->
AccPid = ssh_system_sup:acceptor_supervisor(Pid),
- ssh_acceptor_sup:start_child(AccPid, ServerOpts)
+ ssh_acceptor_sup:start_child(AccPid, Options)
end.
stop_child(Name) ->
@@ -82,8 +82,8 @@ init([Servers]) ->
MaxR = 10,
MaxT = 3600,
Fun = fun(ServerOpts) ->
- Address = proplists:get_value(address, ServerOpts),
- Port = proplists:get_value(port, ServerOpts),
+ Address = ?GET_INTERNAL_OPT(address, ServerOpts),
+ Port = ?GET_INTERNAL_OPT(port, ServerOpts),
child_spec(Address, Port, ServerOpts)
end,
Children = lists:map(Fun, Servers),
@@ -92,10 +92,10 @@ init([Servers]) ->
%%%=========================================================================
%%% Internal functions
%%%=========================================================================
-child_spec(Address, Port, ServerOpts) ->
- Profile = proplists:get_value(profile, proplists:get_value(ssh_opts, ServerOpts), ?DEFAULT_PROFILE),
+child_spec(Address, Port, Options) ->
+ Profile = ?GET_OPT(profile, Options),
Name = id(Address, Port,Profile),
- StartFunc = {ssh_system_sup, start_link, [ServerOpts]},
+ StartFunc = {ssh_system_sup, start_link, [Options]},
Restart = temporary,
Shutdown = infinity,
Modules = [ssh_system_sup],
diff --git a/lib/ssh/test/ssh_trpt_test_lib.erl b/lib/ssh/test/ssh_trpt_test_lib.erl
index 0fa0f0c0e4..261239c152 100644
--- a/lib/ssh/test/ssh_trpt_test_lib.erl
+++ b/lib/ssh/test/ssh_trpt_test_lib.erl
@@ -85,18 +85,18 @@ exec(Op, S0=#s{}) ->
throw:Term ->
report_trace(throw, Term, S1),
- throw(Term);
+ throw({Term,Op});
error:Error ->
report_trace(error, Error, S1),
- error(Error);
+ error({Error,Op});
exit:Exit ->
report_trace(exit, Exit, S1),
- exit(Exit);
+ exit({Exit,Op});
Cls:Err ->
ct:pal("Class=~p, Error=~p", [Cls,Err]),
- error("fooooooO")
+ error({"fooooooO",Op})
end;
exec(Op, {ok,S=#s{}}) -> exec(Op, S);
exec(_, Error) -> Error.
@@ -114,20 +114,20 @@ op({accept,Opts}, S) when ?role(S) == server ->
{ok,Socket} = gen_tcp:accept(S#s.listen_socket, S#s.timeout),
{Host,_Port} = ok(inet:sockname(Socket)),
S#s{socket = Socket,
- ssh = init_ssh(server,Socket,[{host,host(Host)}|Opts]),
+ ssh = init_ssh(server, Socket, host(Host), Opts),
return_value = ok};
%%%---- Client ops
op({connect,Host,Port,Opts}, S) when ?role(S) == undefined ->
Socket = ok(gen_tcp:connect(host(Host), Port, mangle_opts([]))),
S#s{socket = Socket,
- ssh = init_ssh(client, Socket, [{host,host(Host)}|Opts]),
+ ssh = init_ssh(client, Socket, host(Host), Opts),
return_value = ok};
%%%---- ops for both client and server
op(close_socket, S) ->
- catch tcp_gen:close(S#s.socket),
- catch tcp_gen:close(S#s.listen_socket),
+ catch gen_tcp:close(S#s.socket),
+ catch gen_tcp:close(S#s.listen_socket),
S#s{socket = undefined,
listen_socket = undefined,
return_value = ok};
@@ -296,12 +296,14 @@ instantiate(X, _S) ->
%%%================================================================
%%%
-init_ssh(Role, Socket, Options0) ->
- Options = [{user_interaction, false},
- {vsn, {2,0}},
- {id_string, "ErlangTestLib"}
- | Options0],
- ssh_connection_handler:init_ssh_record(Role, Socket, Options).
+init_ssh(Role, Socket, Host, UserOptions0) ->
+ UserOptions = [{user_interaction, false},
+ {vsn, {2,0}},
+ {id_string, "ErlangTestLib"}
+ | UserOptions0],
+ Opts = ?PUT_INTERNAL_OPT({host,Host},
+ ssh_options:handle_options(Role, UserOptions)),
+ ssh_connection_handler:init_ssh_record(Role, Socket, Opts).
mangle_opts(Options) ->
SysOpts = [{reuseaddr, true},
--
cgit v1.2.3
From 7e2ceb5d44dc5004ea4d8271ee1e961bfa4987fd Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 23 Feb 2017 15:57:12 +0100
Subject: ssh: Types and spec fixes to conform to the ref manual
---
lib/ssh/src/ssh.erl | 34 ++++++++++++++++++++++++----------
lib/ssh/src/ssh.hrl | 18 ++++++++++++++++++
lib/ssh/src/ssh_connect.hrl | 4 ++--
lib/ssh/src/ssh_connection.erl | 30 +++++++++++++++---------------
lib/ssh/src/ssh_options.erl | 2 --
5 files changed, 59 insertions(+), 29 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 0186ac7922..53aba14458 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -40,11 +40,24 @@
]).
%%% Type exports
--export_type([connection_ref/0,
- channel_id/0,
- role/0
+-export_type([ssh_daemon_ref/0,
+ ssh_connection_ref/0,
+ ssh_channel_id/0,
+ role/0,
+ subsystem_spec/0,
+ subsystem_name/0,
+ channel_callback/0,
+ channel_init_args/0,
+ algs_list/0,
+ alg_entry/0,
+ simple_algs/0,
+ double_algs/0
]).
+-opaque ssh_daemon_ref() :: daemon_ref() .
+-opaque ssh_connection_ref() :: connection_ref() .
+-opaque ssh_channel_id() :: channel_id().
+
%%--------------------------------------------------------------------
-spec start() -> ok | {error, term()}.
-spec start(permanent | transient | temporary) -> ok | {error, term()}.
@@ -157,10 +170,10 @@ channel_info(ConnectionRef, ChannelId, Options) ->
ssh_connection_handler:channel_info(ConnectionRef, ChannelId, Options).
%%--------------------------------------------------------------------
--spec daemon(inet:port_number()) -> ok_error(pid()).
--spec daemon(inet:port_number()|inet:socket(), proplists:proplist()) -> ok_error(pid()).
--spec daemon(any | inet:ip_address(), inet:port_number(), proplists:proplist()) -> ok_error(pid())
- ;(socket, inet:socket(), proplists:proplist()) -> ok_error(pid())
+-spec daemon(inet:port_number()) -> ok_error(daemon_ref()).
+-spec daemon(inet:port_number()|inet:socket(), proplists:proplist()) -> ok_error(daemon_ref()).
+-spec daemon(any | inet:ip_address(), inet:port_number(), proplists:proplist()) -> ok_error(daemon_ref())
+ ;(socket, inet:socket(), proplists:proplist()) -> ok_error(daemon_ref())
.
%% Description: Starts a server listening for SSH connections
@@ -182,7 +195,7 @@ daemon(Host0, Port, UserOptions0) ->
start_daemon(Host, Port, ssh_options:handle_options(server, UserOptions)).
%%--------------------------------------------------------------------
--spec daemon_info(pid()) -> ok_error( [{atom(), term()}] ).
+-spec daemon_info(daemon_ref()) -> ok_error( [{atom(), term()}] ).
daemon_info(Pid) ->
case catch ssh_system_sup:acceptor_supervisor(Pid) of
@@ -197,7 +210,7 @@ daemon_info(Pid) ->
end.
%%--------------------------------------------------------------------
--spec stop_listener(pid()) -> ok.
+-spec stop_listener(daemon_ref()) -> ok.
-spec stop_listener(inet:ip_address(), inet:port_number()) -> ok.
%%
%% Description: Stops the listener, but leaves
@@ -211,7 +224,7 @@ stop_listener(Address, Port, Profile) ->
ssh_system_sup:stop_listener(Address, Port, Profile).
%%--------------------------------------------------------------------
--spec stop_daemon(pid()) -> ok.
+-spec stop_daemon(daemon_ref()) -> ok.
-spec stop_daemon(inet:ip_address(), inet:port_number()) -> ok.
-spec stop_daemon(inet:ip_address(), inet:port_number(), atom()) -> ok.
%%
@@ -269,6 +282,7 @@ start_shell(Error) ->
Error.
%%--------------------------------------------------------------------
+-spec default_algorithms() -> algs_list() .
%%--------------------------------------------------------------------
default_algorithms() ->
ssh_transport:default_algorithms().
diff --git a/lib/ssh/src/ssh.hrl b/lib/ssh/src/ssh.hrl
index 475534f572..c1ba58ed40 100644
--- a/lib/ssh/src/ssh.hrl
+++ b/lib/ssh/src/ssh.hrl
@@ -90,7 +90,25 @@
-define(PUT_SOCKET_OPT(KeyVal,Opts), ?do_put_opt(socket_options, KeyVal,Opts) ).
%% Types
+-type role() :: client | server .
-type ok_error(SuccessType) :: {ok, SuccessType} | {error, any()} .
+-type daemon_ref() :: pid() .
+
+-type subsystem_spec() :: {subsystem_name(), {channel_callback(), channel_init_args()}} .
+-type subsystem_name() :: string() .
+-type channel_callback() :: atom() .
+-type channel_init_args() :: list() .
+
+-type algs_list() :: list( alg_entry() ).
+-type alg_entry() :: {kex, simple_algs()}
+ | {public_key, simple_algs()}
+ | {cipher, double_algs()}
+ | {mac, double_algs()}
+ | {compression, double_algs()} .
+-type simple_algs() :: list( atom() ) .
+-type double_algs() :: list( {client2serverlist,simple_algs()} | {server2client,simple_algs()} )
+ | simple_algs() .
+
%% Records
-record(ssh,
diff --git a/lib/ssh/src/ssh_connect.hrl b/lib/ssh/src/ssh_connect.hrl
index 4fb6bc39f3..c91c56435e 100644
--- a/lib/ssh/src/ssh_connect.hrl
+++ b/lib/ssh/src/ssh_connect.hrl
@@ -22,9 +22,9 @@
%%% Description : SSH connection protocol
--type role() :: client | server .
--type connection_ref() :: pid().
-type channel_id() :: pos_integer().
+-type connection_ref() :: pid().
+
-define(DEFAULT_PACKET_SIZE, 65536).
-define(DEFAULT_WINDOW_SIZE, 10*?DEFAULT_PACKET_SIZE).
diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl
index 6a48ed581c..930ccecb4c 100644
--- a/lib/ssh/src/ssh_connection.erl
+++ b/lib/ssh/src/ssh_connection.erl
@@ -56,8 +56,8 @@
%%--------------------------------------------------------------------
%%--------------------------------------------------------------------
--spec session_channel(pid(), timeout()) -> {ok, channel_id()} | {error, timeout | closed}.
--spec session_channel(pid(), integer(), integer(), timeout()) -> {ok, channel_id()} | {error, timeout | closed}.
+-spec session_channel(connection_ref(), timeout()) -> {ok, channel_id()} | {error, timeout | closed}.
+-spec session_channel(connection_ref(), integer(), integer(), timeout()) -> {ok, channel_id()} | {error, timeout | closed}.
%% Description: Opens a channel for a ssh session. A session is a
%% remote execution of a program. The program may be a shell, an
@@ -81,7 +81,7 @@ session_channel(ConnectionHandler, InitialWindowSize,
end.
%%--------------------------------------------------------------------
--spec exec(pid(), channel_id(), string(), timeout()) ->
+-spec exec(connection_ref(), channel_id(), string(), timeout()) ->
success | failure | {error, timeout | closed}.
%% Description: Will request that the server start the
@@ -92,7 +92,7 @@ exec(ConnectionHandler, ChannelId, Command, TimeOut) ->
true, [?string(Command)], TimeOut).
%%--------------------------------------------------------------------
--spec shell(pid(), channel_id()) -> _.
+-spec shell(connection_ref(), channel_id()) -> _.
%% Description: Will request that the user's default shell (typically
%% defined in /etc/passwd in UNIX systems) be started at the other
@@ -102,7 +102,7 @@ shell(ConnectionHandler, ChannelId) ->
ssh_connection_handler:request(ConnectionHandler, self(), ChannelId,
"shell", false, <<>>, 0).
%%--------------------------------------------------------------------
--spec subsystem(pid(), channel_id(), string(), timeout()) ->
+-spec subsystem(connection_ref(), channel_id(), string(), timeout()) ->
success | failure | {error, timeout | closed}.
%%
%% Description: Executes a predefined subsystem.
@@ -112,11 +112,11 @@ subsystem(ConnectionHandler, ChannelId, SubSystem, TimeOut) ->
ChannelId, "subsystem",
true, [?string(SubSystem)], TimeOut).
%%--------------------------------------------------------------------
--spec send(pid(), channel_id(), iodata()) ->
+-spec send(connection_ref(), channel_id(), iodata()) ->
ok | {error, closed}.
--spec send(pid(), channel_id(), integer()| iodata(), timeout() | iodata()) ->
+-spec send(connection_ref(), channel_id(), integer()| iodata(), timeout() | iodata()) ->
ok | {error, timeout} | {error, closed}.
--spec send(pid(), channel_id(), integer(), iodata(), timeout()) ->
+-spec send(connection_ref(), channel_id(), integer(), iodata(), timeout()) ->
ok | {error, timeout} | {error, closed}.
%%
%%
@@ -134,7 +134,7 @@ send(ConnectionHandler, ChannelId, Type, Data, TimeOut) ->
ssh_connection_handler:send(ConnectionHandler, ChannelId,
Type, Data, TimeOut).
%%--------------------------------------------------------------------
--spec send_eof(pid(), channel_id()) -> ok | {error, closed}.
+-spec send_eof(connection_ref(), channel_id()) -> ok | {error, closed}.
%%
%%
%% Description: Sends eof on the channel .
@@ -143,7 +143,7 @@ send_eof(ConnectionHandler, Channel) ->
ssh_connection_handler:send_eof(ConnectionHandler, Channel).
%%--------------------------------------------------------------------
--spec adjust_window(pid(), channel_id(), integer()) -> ok | {error, closed}.
+-spec adjust_window(connection_ref(), channel_id(), integer()) -> ok | {error, closed}.
%%
%%
%% Description: Adjusts the ssh flowcontrol window.
@@ -152,7 +152,7 @@ adjust_window(ConnectionHandler, Channel, Bytes) ->
ssh_connection_handler:adjust_window(ConnectionHandler, Channel, Bytes).
%%--------------------------------------------------------------------
--spec setenv(pid(), channel_id(), string(), string(), timeout()) ->
+-spec setenv(connection_ref(), channel_id(), string(), string(), timeout()) ->
success | failure | {error, timeout | closed}.
%%
%%
@@ -165,7 +165,7 @@ setenv(ConnectionHandler, ChannelId, Var, Value, TimeOut) ->
%%--------------------------------------------------------------------
--spec close(pid(), channel_id()) -> ok.
+-spec close(connection_ref(), channel_id()) -> ok.
%%
%%
%% Description: Sends a close message on the channel .
@@ -174,7 +174,7 @@ close(ConnectionHandler, ChannelId) ->
ssh_connection_handler:close(ConnectionHandler, ChannelId).
%%--------------------------------------------------------------------
--spec reply_request(pid(), boolean(), success | failure, channel_id()) -> ok.
+-spec reply_request(connection_ref(), boolean(), success | failure, channel_id()) -> ok.
%%
%%
%% Description: Send status replies to requests that want such replies.
@@ -185,9 +185,9 @@ reply_request(_,false, _, _) ->
ok.
%%--------------------------------------------------------------------
--spec ptty_alloc(pid(), channel_id(), proplists:proplist()) ->
+-spec ptty_alloc(connection_ref(), channel_id(), proplists:proplist()) ->
success | failiure | {error, closed}.
--spec ptty_alloc(pid(), channel_id(), proplists:proplist(), timeout()) ->
+-spec ptty_alloc(connection_ref(), channel_id(), proplists:proplist(), timeout()) ->
success | failiure | {error, timeout} | {error, closed}.
%%
diff --git a/lib/ssh/src/ssh_options.erl b/lib/ssh/src/ssh_options.erl
index 52dea5d183..395be6b220 100644
--- a/lib/ssh/src/ssh_options.erl
+++ b/lib/ssh/src/ssh_options.erl
@@ -58,8 +58,6 @@
-type option_declarations() :: #{ {option_key(),def} := option_declaration() }.
--type role() :: client | server .
-
-type error() :: {error,{eoptions,any()}} .
%%%================================================================
--
cgit v1.2.3
From b06e71e0ff39050eb538352a7b7ca6df8f62eed3 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 17 Feb 2017 19:18:58 +0100
Subject: ssh: Remove missplaced options in test suites
Removed daemon-only options from client and client-only options from daemon.
---
lib/ssh/test/ssh_benchmark_SUITE.erl | 2 --
lib/ssh/test/ssh_sftpd_SUITE.erl | 3 +--
lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl | 1 -
lib/ssh/test/ssh_to_openssh_SUITE.erl | 2 --
4 files changed, 1 insertion(+), 7 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_benchmark_SUITE.erl b/lib/ssh/test/ssh_benchmark_SUITE.erl
index 85750f8fbd..fc90750455 100644
--- a/lib/ssh/test/ssh_benchmark_SUITE.erl
+++ b/lib/ssh/test/ssh_benchmark_SUITE.erl
@@ -139,7 +139,6 @@ openssh_client_shell(Config, Options) ->
{ok, TracerPid} = erlang_trace(),
{ServerPid, _Host, Port} =
ssh_test_lib:daemon([{system_dir, SystemDir},
- {public_key_alg, ssh_dsa},
{failfun, fun ssh_test_lib:failfun/2} |
Options]),
ct:sleep(500),
@@ -215,7 +214,6 @@ openssh_client_sftp(Config, Options) ->
{ok, TracerPid} = erlang_trace(),
{ServerPid, _Host, Port} =
ssh_test_lib:daemon([{system_dir, SystemDir},
- {public_key_alg, ssh_dsa},
{subsystems,[ssh_sftpd:subsystem_spec([%{cwd, SftpSrcDir},
{root, SftpSrcDir}])]},
{failfun, fun ssh_test_lib:failfun/2}
diff --git a/lib/ssh/test/ssh_sftpd_SUITE.erl b/lib/ssh/test/ssh_sftpd_SUITE.erl
index 6d18a980ee..b167f98ac8 100644
--- a/lib/ssh/test/ssh_sftpd_SUITE.erl
+++ b/lib/ssh/test/ssh_sftpd_SUITE.erl
@@ -158,8 +158,7 @@ init_per_testcase(TestCase, Config) ->
[{user_dir, ClientUserDir},
{user, ?USER}, {password, ?PASSWD},
{user_interaction, false},
- {silently_accept_hosts, true},
- {pwdfun, fun(_,_) -> true end}]),
+ {silently_accept_hosts, true}]),
{ok, Channel} =
ssh_connection:session_channel(Cm, ?XFER_WINDOW_SIZE,
?XFER_PACKET_SIZE, ?TIMEOUT),
diff --git a/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl b/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl
index fd5157d603..b4d7eadfa4 100644
--- a/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl
+++ b/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl
@@ -189,7 +189,6 @@ quit(Config) when is_list(Config) ->
timer:sleep(5000),
{ok, NewSftp, _Conn} = ssh_sftp:start_channel(Host, Port,
[{silently_accept_hosts, true},
- {pwdfun, fun(_,_) -> true end},
{user_dir, UserDir},
{user, ?USER}, {password, ?PASSWD}]),
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl
index cd5ba6ecd2..687e6efaf3 100644
--- a/lib/ssh/test/ssh_to_openssh_SUITE.erl
+++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl
@@ -381,7 +381,6 @@ erlang_server_openssh_client_public_key_X(Config, PubKeyAlg) ->
PrivDir = proplists:get_value(priv_dir, Config),
KnownHosts = filename:join(PrivDir, "known_hosts"),
{Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
- {public_key_alg, PubKeyAlg},
{failfun, fun ssh_test_lib:failfun/2}]),
ct:sleep(500),
@@ -402,7 +401,6 @@ erlang_server_openssh_client_renegotiate(Config) ->
KnownHosts = filename:join(PrivDir, "known_hosts"),
{Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
- {public_key_alg, PubKeyAlg},
{failfun, fun ssh_test_lib:failfun/2}]),
ct:sleep(500),
--
cgit v1.2.3
From 931df53bc431c47140620864b04d4622f9e41421 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 23 Feb 2017 17:53:46 +0100
Subject: ssh: Simplify calling of user's callback funs
Since the Options now are initialized with a correct fun (that does nothing), we can just call it without tests
---
lib/ssh/src/ssh_connection_handler.erl | 45 +++++++++-------------------------
1 file changed, 11 insertions(+), 34 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 706b68d78b..b9c643c77e 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -1769,47 +1769,24 @@ get_repl(X, Acc) ->
exit({get_repl,X,Acc}).
%%%----------------------------------------------------------------
-disconnect_fun({disconnect,Msg}, D) ->
- disconnect_fun(Msg, D);
-disconnect_fun(Reason, #data{opts=Opts}) ->
- case ?GET_OPT(disconnectfun, Opts) of
- undefined ->
- ok;
- Fun ->
- catch Fun(Reason)
- end.
-
-unexpected_fun(UnexpectedMessage, #data{opts = Opts,
- ssh_params = #ssh{peer = {_,Peer} }
- } ) ->
- case ?GET_OPT(unexpectedfun, Opts) of
- undefined ->
- report;
- Fun ->
- catch Fun(UnexpectedMessage, Peer)
- end.
+-define(CALL_FUN(Key,D), catch (?GET_OPT(Key, D#data.opts)) ).
+
+disconnect_fun({disconnect,Msg}, D) -> ?CALL_FUN(disconnectfun,D)(Msg);
+disconnect_fun(Reason, D) -> ?CALL_FUN(disconnectfun,D)(Reason).
+unexpected_fun(UnexpectedMessage, #data{ssh_params = #ssh{peer = {_,Peer} }} = D) ->
+ ?CALL_FUN(unexpectedfun,D)(UnexpectedMessage, Peer).
debug_fun(#ssh_msg_debug{always_display = Display,
message = DbgMsg,
language = Lang},
- #data{opts = Opts}) ->
- case ?GET_OPT(ssh_msg_debug_fun, Opts) of
- undefined ->
- ok;
- Fun ->
- catch Fun(self(), Display, DbgMsg, Lang)
- end.
+ D) ->
+ ?CALL_FUN(ssh_msg_debug_fun,D)(self(), Display, DbgMsg, Lang).
-connected_fun(User, Method, #data{ssh_params = #ssh{peer = {_,Peer}},
- opts = Opts}) ->
- case ?GET_OPT(connectfun, Opts) of
- undefined ->
- ok;
- Fun ->
- catch Fun(User, Peer, Method)
- end.
+connected_fun(User, Method, #data{ssh_params = #ssh{peer = {_,Peer}}} = D) ->
+ ?CALL_FUN(connectfun,D)(User, Peer, Method).
+
retry_fun(_, undefined, _) ->
ok;
--
cgit v1.2.3
From 6fb1523e86bc3561f3fd397b3b9cbad5e3ca90a0 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 8 Mar 2017 16:45:08 +0100
Subject: ssh: Update .app file
---
lib/ssh/src/ssh.app.src | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh.app.src b/lib/ssh/src/ssh.app.src
index 2bb7491b0c..7859ab4064 100644
--- a/lib/ssh/src/ssh.app.src
+++ b/lib/ssh/src/ssh.app.src
@@ -41,10 +41,10 @@
{env, []},
{mod, {ssh_app, []}},
{runtime_dependencies, [
- "crypto-3.3",
+ "crypto-3.7.3",
"erts-6.0",
"kernel-3.0",
- "public_key-1.1",
- "stdlib-3.1"
+ "public_key-1.4",
+ "stdlib-3.3"
]}]}.
--
cgit v1.2.3
From 1af346afd2d8cabc48bf9673dc62672e36b7b8a2 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 6 Mar 2017 16:24:03 +0100
Subject: ssh: Host and Profile info returned in ssh:daemon_info
---
lib/ssh/src/ssh.erl | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 53aba14458..e2a289d737 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -200,11 +200,13 @@ daemon(Host0, Port, UserOptions0) ->
daemon_info(Pid) ->
case catch ssh_system_sup:acceptor_supervisor(Pid) of
AsupPid when is_pid(AsupPid) ->
- [Port] =
- [Prt || {{ssh_acceptor_sup,any,Prt,default},
+ [{ListenAddr,Port,Profile}] =
+ [{LA,Prt,Prf} || {{ssh_acceptor_sup,LA,Prt,Prf},
_WorkerPid,worker,[ssh_acceptor]} <- supervisor:which_children(AsupPid)],
- {ok, [{port,Port}]};
-
+ {ok, [{port,Port},
+ {listen_address,ListenAddr},
+ {profile,Profile}
+ ]};
_ ->
{error,bad_daemon_ref}
end.
--
cgit v1.2.3
From 5d560441709eb1faa6a223b237da65f1d70da6d2 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 8 Mar 2017 18:34:43 +0100
Subject: ssh: documents ssh:daemon_info/1
---
lib/ssh/doc/src/ssh.xml | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index f6e26f5ee8..1f07e826ce 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -726,9 +726,10 @@
- daemon_info(Daemon) -> {ok, [{port,Port}]} | {error,Error}
+ daemon_info(Daemon) -> {ok, [DaemonInfo]} | {error,Error}
Get info about a daemon
+ DaemonInfo = {port,Port::pos_integer()} | {listen_address, any|ip_address()} | {profile,atom()}
Port = integer()
Error = bad_daemon_ref
--
cgit v1.2.3
From 26c3cd82529836cb5b6eefbf7f92f318fd91f847 Mon Sep 17 00:00:00 2001
From: Rickard Green
Date: Fri, 10 Mar 2017 15:00:46 +0100
Subject: Update copyright year
---
lib/ssh/doc/src/ssh.xml | 2 +-
lib/ssh/doc/src/using_ssh.xml | 2 +-
lib/ssh/src/ssh.erl | 2 +-
lib/ssh/src/ssh_cli.erl | 2 +-
lib/ssh/src/ssh_connection_handler.erl | 2 +-
lib/ssh/src/ssh_dbg.erl | 2 +-
lib/ssh/src/ssh_sftpd.erl | 2 +-
lib/ssh/src/ssh_sftpd_file_api.erl | 2 +-
lib/ssh/src/ssh_transport.erl | 2 +-
lib/ssh/test/property_test/ssh_eqc_encode_decode.erl | 2 +-
lib/ssh/test/ssh_algorithms_SUITE.erl | 2 +-
lib/ssh/test/ssh_benchmark_SUITE.erl | 2 +-
lib/ssh/test/ssh_options_SUITE.erl | 2 +-
lib/ssh/test/ssh_protocol_SUITE.erl | 2 +-
lib/ssh/test/ssh_sftpd_SUITE.erl | 2 +-
lib/ssh/test/ssh_test_lib.erl | 2 +-
lib/ssh/test/ssh_to_openssh_SUITE.erl | 2 +-
17 files changed, 17 insertions(+), 17 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index f6e26f5ee8..604b9f5bbb 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -4,7 +4,7 @@
- 20042016
+ 20042017
Ericsson AB. All Rights Reserved.
diff --git a/lib/ssh/doc/src/using_ssh.xml b/lib/ssh/doc/src/using_ssh.xml
index 864378b640..ab307624e6 100644
--- a/lib/ssh/doc/src/using_ssh.xml
+++ b/lib/ssh/doc/src/using_ssh.xml
@@ -5,7 +5,7 @@
2012
- 2016
+ 2017
Ericsson AB. All Rights Reserved.
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 68d98d3875..1f3f77a4e4 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -1,7 +1,7 @@
%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_cli.erl b/lib/ssh/src/ssh_cli.erl
index 6f8c050486..7c7b9e7922 100644
--- a/lib/ssh/src/ssh_cli.erl
+++ b/lib/ssh/src/ssh_cli.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 4496c657c3..fc75945a5b 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_dbg.erl b/lib/ssh/src/ssh_dbg.erl
index 0345bbdea7..251741da7e 100644
--- a/lib/ssh/src/ssh_dbg.erl
+++ b/lib/ssh/src/ssh_dbg.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_sftpd.erl b/lib/ssh/src/ssh_sftpd.erl
index 9352046795..fb680fe11c 100644
--- a/lib/ssh/src/ssh_sftpd.erl
+++ b/lib/ssh/src/ssh_sftpd.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_sftpd_file_api.erl b/lib/ssh/src/ssh_sftpd_file_api.erl
index e444e52ac0..81f181f1fc 100644
--- a/lib/ssh/src/ssh_sftpd_file_api.erl
+++ b/lib/ssh/src/ssh_sftpd_file_api.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index a7cc4cd52c..9bebaf2d9b 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl b/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl
index 8ca29b9399..410a9ea983 100644
--- a/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl
+++ b/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_algorithms_SUITE.erl b/lib/ssh/test/ssh_algorithms_SUITE.erl
index 6f75d83c4a..28a013ea33 100644
--- a/lib/ssh/test/ssh_algorithms_SUITE.erl
+++ b/lib/ssh/test/ssh_algorithms_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_benchmark_SUITE.erl b/lib/ssh/test/ssh_benchmark_SUITE.erl
index c5a6447839..f3ed6a5b9b 100644
--- a/lib/ssh/test/ssh_benchmark_SUITE.erl
+++ b/lib/ssh/test/ssh_benchmark_SUITE.erl
@@ -1,7 +1,7 @@
%%%-------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_options_SUITE.erl b/lib/ssh/test/ssh_options_SUITE.erl
index d07c596411..eedb2b389d 100644
--- a/lib/ssh/test/ssh_options_SUITE.erl
+++ b/lib/ssh/test/ssh_options_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_protocol_SUITE.erl b/lib/ssh/test/ssh_protocol_SUITE.erl
index f9edc5bfc2..619ff5e27a 100644
--- a/lib/ssh/test/ssh_protocol_SUITE.erl
+++ b/lib/ssh/test/ssh_protocol_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. 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
diff --git a/lib/ssh/test/ssh_sftpd_SUITE.erl b/lib/ssh/test/ssh_sftpd_SUITE.erl
index 6d18a980ee..2c6eaeee0d 100644
--- a/lib/ssh/test/ssh_sftpd_SUITE.erl
+++ b/lib/ssh/test/ssh_sftpd_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl
index 1673f52821..643ff8e41d 100644
--- a/lib/ssh/test/ssh_test_lib.erl
+++ b/lib/ssh/test/ssh_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl
index 0b9b7acde8..547f759a00 100644
--- a/lib/ssh/test/ssh_to_openssh_SUITE.erl
+++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
--
cgit v1.2.3
From 4d658008be5a08ddadbe75ebadb9ef124436b76e Mon Sep 17 00:00:00 2001
From: Erlang/OTP
Date: Tue, 14 Mar 2017 15:59:23 +0100
Subject: Prepare release
---
lib/ssh/doc/src/notes.xml | 80 +++++++++++++++++++++++++++++++++++++++++++++++
lib/ssh/vsn.mk | 2 +-
2 files changed, 81 insertions(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index 1837350284..02a39f030c 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -30,6 +30,86 @@
notes.xml
+Ssh 4.4.1
+
+ Fixed Bugs and Malfunctions
+
+ -
+
+ Fix bug when opening connections. If the tcp setup
+ failed, that would in some cases not result in an error
+ return value.
+
+ Own Id: OTP-14108
+
+ -
+
+ Reduce information leakage in case of decryption errors.
+
+ Own Id: OTP-14109
+
+ -
+
+ The key exchange algorithm
+ diffie-hellman-group-exchange-sha* has a server-option
+ {dh_gex_limits,{Min,Max}}. There was a hostkey
+ signature validation error on the client side if the
+ option was used and the Min or the Max
+ differed from the corresponding values obtained from the
+ client.
+
+ This bug is now corrected.
+
+ Own Id: OTP-14166
+
+ -
+
+ The sftpd server now correctly uses root_dir and
+ cwd when resolving file paths if both are
+ provided. The cwd handling is also corrected.
+
+ Thanks to kape1395!
+
+ Own Id: OTP-14225 Aux Id: PR-1331, PR-1335
+
+ -
+
+ Ssh_cli used a function that does not handle non-utf8
+ unicode correctly.
+
+ Own Id: OTP-14230 Aux Id: ERL-364
+
+
+
+
+
+ Improvements and New Features
+
+ -
+
+ The implementation of the key exchange algorithms
+ diffie-hellman-group-exchange-sha* are optimized, up to a
+ factor of 11 for the slowest ( = biggest and safest)
+ group size.
+
+ Own Id: OTP-14169 Aux Id: seq-13261
+
+ -
+
+ The ssh host key fingerprint generation now also takes a
+ list of algorithms and returns a list of corresponding
+ fingerprints. See
+ public_key:ssh_hostkey_fingerprint/2 and the
+ option silently_accept_hosts in
+ ssh:connect.
+
+ Own Id: OTP-14223
+
+
+
+
+
+
Ssh 4.4
Fixed Bugs and Malfunctions
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index c6a5990f41..96c83cb0f7 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,5 +1,5 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 4.4
+SSH_VSN = 4.4.1
APP_VSN = "ssh-$(SSH_VSN)"
--
cgit v1.2.3
From a4edbd619c624d2ca2f343da19a88fba74470e93 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 17 Mar 2017 13:23:42 +0100
Subject: ssh: remove from code
---
lib/ssh/src/ssh_options.erl | 11 -----------
1 file changed, 11 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_options.erl b/lib/ssh/src/ssh_options.erl
index 395be6b220..a882a01eaf 100644
--- a/lib/ssh/src/ssh_options.erl
+++ b/lib/ssh/src/ssh_options.erl
@@ -200,17 +200,6 @@ save({K,V}, _, _) when K == reuseaddr ;
save({allow_user_interaction,V}, Opts, Vals) ->
save({user_interaction,V}, Opts, Vals);
-save({public_key_alg,V}, Defs, Vals) -> % To remove in OTP-20
- New = case V of
- 'ssh-rsa' -> ['ssh-rsa', 'ssh-dss'];
- ssh_rsa -> ['ssh-rsa', 'ssh-dss'];
- 'ssh-dss' -> ['ssh-dss', 'ssh-rsa'];
- ssh_dsa -> ['ssh-dss', 'ssh-rsa'];
- _ -> error({eoptions, {public_key_alg,V},
- "Unknown algorithm, try pref_public_key_algs instead"})
- end,
- save({pref_public_key_algs,New}, Defs, Vals);
-
%% Special case for socket options 'inet' and 'inet6'
save(Inet, Defs, OptMap) when Inet==inet ; Inet==inet6 ->
save({inet,Inet}, Defs, OptMap);
--
cgit v1.2.3
From eeac5af66b94596ba9a6c765c5f30383f7ed117a Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 17 Mar 2017 13:23:59 +0100
Subject: ssh: remove from doc
---
lib/ssh/doc/src/ssh.xml | 15 ---------------
1 file changed, 15 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index 1f07e826ce..968983c862 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -243,21 +243,6 @@
Peer is in the format of {Host,Port}.
-
- -
-
-
This option will be removed in OTP 20, but is kept for compatibility. It is ignored if
- the preferred pref_public_key_algs option is used.
-
- Sets the preferred public key algorithm to use for user
- authentication. If the preferred algorithm fails,
- the other algorithm is tried. If {public_key_alg, 'ssh-rsa'} is set, it is translated
- to {pref_public_key_algs, ['ssh-rsa','ssh-dss']}. If it is
- {public_key_alg, 'ssh-dss'}, it is translated
- to {pref_public_key_algs, ['ssh-dss','ssh-rsa']}.
-
-
-
-
List of user (client) public key algorithms to try to use.
--
cgit v1.2.3
From 304e2939256d2d1d8e3ef7ccf66b3ce058b04d44 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 17 Mar 2017 13:27:42 +0100
Subject: ssh: remove from test
---
lib/ssh/test/ssh_to_openssh_SUITE.erl | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl
index 687e6efaf3..7eda009552 100644
--- a/lib/ssh/test/ssh_to_openssh_SUITE.erl
+++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl
@@ -333,7 +333,7 @@ erlang_client_openssh_server_publickey_rsa(Config) when is_list(Config) ->
[{_,_, not_encrypted}] ->
ConnectionRef =
ssh_test_lib:connect(?SSH_DEFAULT_PORT,
- [{public_key_alg, ssh_rsa},
+ [{pref_public_key_algs, ['ssh-rsa','ssh-dss']},
{user_interaction, false},
silently_accept_hosts]),
{ok, Channel} =
@@ -354,7 +354,7 @@ erlang_client_openssh_server_publickey_dsa() ->
erlang_client_openssh_server_publickey_dsa(Config) when is_list(Config) ->
ConnectionRef =
ssh_test_lib:connect(?SSH_DEFAULT_PORT,
- [{public_key_alg, ssh_dsa},
+ [{pref_public_key_algs, ['ssh-dss','ssh-rsa']},
{user_interaction, false},
silently_accept_hosts]),
{ok, Channel} =
--
cgit v1.2.3
From 6d91c5cbe19e8ed9e7548d5e90d236c603977f08 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Tue, 7 Mar 2017 15:25:16 +0100
Subject: ssh: remove old ssh_benchmark_SUITE
Seem to draw much resources (time & prim mem)
---
lib/ssh/test/Makefile | 1 -
lib/ssh/test/ssh.spec | 3 +-
lib/ssh/test/ssh_bench.spec | 3 +-
lib/ssh/test/ssh_benchmark_SUITE.erl | 571 ---------------------
lib/ssh/test/ssh_benchmark_SUITE_data/id_dsa | 13 -
lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa256 | 5 -
.../test/ssh_benchmark_SUITE_data/id_ecdsa256.pub | 1 -
lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa384 | 6 -
.../test/ssh_benchmark_SUITE_data/id_ecdsa384.pub | 1 -
lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa521 | 7 -
.../test/ssh_benchmark_SUITE_data/id_ecdsa521.pub | 1 -
lib/ssh/test/ssh_benchmark_SUITE_data/id_rsa | 15 -
.../test/ssh_benchmark_SUITE_data/ssh_host_dsa_key | 13 -
.../ssh_benchmark_SUITE_data/ssh_host_dsa_key.pub | 11 -
.../ssh_benchmark_SUITE_data/ssh_host_ecdsa_key256 | 5 -
.../ssh_host_ecdsa_key256.pub | 1 -
.../ssh_benchmark_SUITE_data/ssh_host_ecdsa_key384 | 6 -
.../ssh_host_ecdsa_key384.pub | 1 -
.../ssh_benchmark_SUITE_data/ssh_host_ecdsa_key521 | 7 -
.../ssh_host_ecdsa_key521.pub | 1 -
.../test/ssh_benchmark_SUITE_data/ssh_host_rsa_key | 16 -
.../ssh_benchmark_SUITE_data/ssh_host_rsa_key.pub | 5 -
22 files changed, 4 insertions(+), 689 deletions(-)
delete mode 100644 lib/ssh/test/ssh_benchmark_SUITE.erl
delete mode 100644 lib/ssh/test/ssh_benchmark_SUITE_data/id_dsa
delete mode 100644 lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa256
delete mode 100644 lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa256.pub
delete mode 100644 lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa384
delete mode 100644 lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa384.pub
delete mode 100644 lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa521
delete mode 100644 lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa521.pub
delete mode 100644 lib/ssh/test/ssh_benchmark_SUITE_data/id_rsa
delete mode 100644 lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_dsa_key
delete mode 100644 lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_dsa_key.pub
delete mode 100644 lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key256
delete mode 100644 lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key256.pub
delete mode 100644 lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key384
delete mode 100644 lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key384.pub
delete mode 100644 lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key521
delete mode 100644 lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key521.pub
delete mode 100644 lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_rsa_key
delete mode 100644 lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_rsa_key.pub
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/Makefile b/lib/ssh/test/Makefile
index 3fca78237c..512e429962 100644
--- a/lib/ssh/test/Makefile
+++ b/lib/ssh/test/Makefile
@@ -36,7 +36,6 @@ MODULES= \
ssh_options_SUITE \
ssh_renegotiate_SUITE \
ssh_basic_SUITE \
- ssh_benchmark_SUITE \
ssh_connection_SUITE \
ssh_protocol_SUITE \
ssh_sftp_SUITE \
diff --git a/lib/ssh/test/ssh.spec b/lib/ssh/test/ssh.spec
index 0076fc275e..92351f3ed1 100644
--- a/lib/ssh/test/ssh.spec
+++ b/lib/ssh/test/ssh.spec
@@ -1,6 +1,7 @@
{suites,"../ssh_test",all}.
-{skip_suites, "../ssh_test", [ssh_benchmark_SUITE],
+{skip_suites, "../ssh_test", [
+ ],
"Benchmarks run separately"}.
diff --git a/lib/ssh/test/ssh_bench.spec b/lib/ssh/test/ssh_bench.spec
index 029f0bd074..7204073cea 100644
--- a/lib/ssh/test/ssh_bench.spec
+++ b/lib/ssh/test/ssh_bench.spec
@@ -1 +1,2 @@
-{suites,"../ssh_test",[ssh_benchmark_SUITE]}.
+{suites,"../ssh_test",[
+ ]}.
diff --git a/lib/ssh/test/ssh_benchmark_SUITE.erl b/lib/ssh/test/ssh_benchmark_SUITE.erl
deleted file mode 100644
index fc90750455..0000000000
--- a/lib/ssh/test/ssh_benchmark_SUITE.erl
+++ /dev/null
@@ -1,571 +0,0 @@
-%%%-------------------------------------------------------------------
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
--module(ssh_benchmark_SUITE).
--compile(export_all).
-
--include_lib("common_test/include/ct_event.hrl").
--include_lib("common_test/include/ct.hrl").
-
--include_lib("ssh/src/ssh.hrl").
--include_lib("ssh/src/ssh_transport.hrl").
--include_lib("ssh/src/ssh_connect.hrl").
--include_lib("ssh/src/ssh_userauth.hrl").
-
-
-suite() -> [{ct_hooks,[{ts_install_cth,[{nodenames,2}]}]},
- {timetrap,{minutes,6}}
- ].
-%%suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() -> [{group, opensshc_erld}
-%% {group, erlc_opensshd}
- ].
-
-groups() ->
- [{opensshc_erld, [{repeat, 3}], [openssh_client_shell,
- openssh_client_sftp]}
- ].
-
-
-init_per_suite(Config) ->
- catch ssh:stop(),
- try
- report_client_algorithms(),
- ok = ssh:start(),
- {ok,TracerPid} = erlang_trace(),
- [{tracer_pid,TracerPid} | init_sftp_dirs(Config)]
- catch
- C:E ->
- {skip, io_lib:format("Couldn't start ~p:~p",[C,E])}
- end.
-
-end_per_suite(_Config) ->
- catch ssh:stop(),
- ok.
-
-
-
-init_per_group(opensshc_erld, Config) ->
- case ssh_test_lib:ssh_type() of
- openSSH ->
- DataDir = proplists:get_value(data_dir, Config),
- UserDir = proplists:get_value(priv_dir, Config),
- ssh_test_lib:setup_dsa(DataDir, UserDir),
- ssh_test_lib:setup_rsa(DataDir, UserDir),
- ssh_test_lib:setup_ecdsa("256", DataDir, UserDir),
- AlgsD = ssh:default_algorithms(),
- AlgsC = ssh_test_lib:default_algorithms(sshc),
- Common = ssh_test_lib:intersect_bi_dir(
- ssh_test_lib:intersection(AlgsD, AlgsC)),
- ct:pal("~p~n~nErld:~n~p~n~nOpenSSHc:~n~p~n~nCommon:~n~p",
- [inet:gethostname(), AlgsD, AlgsC, Common]),
- [{c_kexs, ssh_test_lib:sshc(kex)},
- {c_ciphers, ssh_test_lib:sshc(cipher)},
- {common_algs, Common}
- | Config];
- _ ->
- {skip, "No OpenSsh client found"}
- end;
-
-init_per_group(erlc_opensshd, _) ->
- {skip, "Group erlc_opensshd not implemented"};
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, _Config) ->
- ok.
-
-
-init_per_testcase(_Func, Conf) ->
- Conf.
-
-end_per_testcase(_Func, _Conf) ->
- ok.
-
-
-init_sftp_dirs(Config) ->
- UserDir = proplists:get_value(priv_dir, Config),
- SrcDir = filename:join(UserDir, "sftp_src"),
- ok = file:make_dir(SrcDir),
- SrcFile = "big_data",
- DstDir = filename:join(UserDir, "sftp_dst"),
- ok = file:make_dir(DstDir),
- N = 100 * 1024*1024,
- ok = file:write_file(filename:join(SrcDir,SrcFile), crypto:strong_rand_bytes(N)),
- [{sftp_src_dir,SrcDir}, {sftp_dst_dir,DstDir}, {src_file,SrcFile}, {sftp_size,N}
- | Config].
-
-%%%================================================================
-openssh_client_shell(Config) ->
- lists:foreach(
- fun(PrefAlgs=[{kex,[Kex]}]) when Kex == 'diffie-hellman-group-exchange-sha256' ->
- lists:foreach(
- fun(Grp) ->
- openssh_client_shell(Config,
- [{preferred_algorithms, PrefAlgs},
- {dh_gex_groups, [Grp]}
- ])
- end, moduli());
- (PrefAlgs) ->
- openssh_client_shell(Config,
- [{preferred_algorithms, PrefAlgs}])
- end, variants(kex,Config) ++ variants(cipher,Config)
- ).
-
-
-openssh_client_shell(Config, Options) ->
- SystemDir = proplists:get_value(data_dir, Config),
- UserDir = proplists:get_value(priv_dir, Config),
- KnownHosts = filename:join(UserDir, "known_hosts"),
-
- {ok, TracerPid} = erlang_trace(),
- {ServerPid, _Host, Port} =
- ssh_test_lib:daemon([{system_dir, SystemDir},
- {failfun, fun ssh_test_lib:failfun/2} |
- Options]),
- ct:sleep(500),
-
- Data = lists:duplicate(100000, $a),
- Cmd = lists:concat(["ssh -p ",Port,
- " -o UserKnownHostsFile=", KnownHosts,
- " -o \"StrictHostKeyChecking no\"",
- " localhost '\"",Data,"\"'."]),
-%% ct:pal("Cmd ="++Cmd),
-
- Parent = self(),
- SlavePid = spawn(fun() ->
- Parent ! {self(),os:cmd(Cmd)}
- end),
- receive
- {SlavePid, _ClientResponse} ->
-%% ct:pal("ClientResponse = ~p",[_ClientResponse]),
- {ok, List} = get_trace_list(TracerPid),
- Times = find_times(List, [accept_to_hello, kex, kex_to_auth, auth, to_prompt]),
- Algs = find_algs(List),
- ct:pal("Algorithms = ~p~n~nTimes = ~p",[Algs,Times]),
- lists:foreach(
- fun({Tag,Value,Unit}) ->
- EventData =
- case Tag of
- {A,B} when A==encrypt ; A==decrypt ->
- [{value, Value},
- {suite, ?MODULE},
- {name, mk_name(["Cipher ",A," ",B," [",Unit,"]"])}
- ];
- kex ->
- KexAlgStr = fmt_alg(Algs#alg.kex, List),
- [{value, Value},
- {suite, ?MODULE},
- {name, mk_name(["Erl server kex ",KexAlgStr," [",Unit,"]"])}
- ];
- _ when is_atom(Tag) ->
- [{value, Value},
- {suite, ?MODULE},
- {name, mk_name(["Erl server ",Tag," [",Unit,"]"])}
- ]
- end,
- ct:pal("ct_event:notify ~p",[EventData]),
- ct_event:notify(#event{name = benchmark_data,
- data = EventData})
- end, Times),
- ssh:stop_daemon(ServerPid),
- ok
- after 60*1000 ->
- ssh:stop_daemon(ServerPid),
- exit(SlavePid, kill),
- {fail, timeout}
- end.
-
-
-%%%================================================================
-openssh_client_sftp(Config) ->
- lists:foreach(
- fun(PrefAlgs) ->
- openssh_client_sftp(Config, [{preferred_algorithms,PrefAlgs}])
- end, variants(cipher,Config)).
-
-
-openssh_client_sftp(Config, Options) ->
- SystemDir = proplists:get_value(data_dir, Config),
- UserDir = proplists:get_value(priv_dir, Config),
- SftpSrcDir = proplists:get_value(sftp_src_dir, Config),
- SrcFile = proplists:get_value(src_file, Config),
- SrcSize = proplists:get_value(sftp_size, Config),
- KnownHosts = filename:join(UserDir, "known_hosts"),
-
- {ok, TracerPid} = erlang_trace(),
- {ServerPid, _Host, Port} =
- ssh_test_lib:daemon([{system_dir, SystemDir},
- {subsystems,[ssh_sftpd:subsystem_spec([%{cwd, SftpSrcDir},
- {root, SftpSrcDir}])]},
- {failfun, fun ssh_test_lib:failfun/2}
- | Options]),
- ct:pal("ServerPid = ~p",[ServerPid]),
- ct:sleep(500),
- Cmd = lists:concat(["sftp",
- " -b -",
- " -P ",Port,
- " -o UserKnownHostsFile=", KnownHosts,
- " -o \"StrictHostKeyChecking no\"",
- " localhost:",SrcFile
- ]),
-%% ct:pal("Cmd = ~p",[Cmd]),
-
- Parent = self(),
- SlavePid = spawn(fun() ->
- Parent ! {self(),os:cmd(Cmd)}
- end),
- receive
- {SlavePid, _ClientResponse} ->
- ct:pal("ClientResponse = ~p~nServerPid = ~p",[_ClientResponse,ServerPid]),
- {ok, List} = get_trace_list(TracerPid),
-%%ct:pal("List=~p",[List]),
- Times = find_times(List, [channel_open_close]),
- Algs = find_algs(List),
- ct:pal("Algorithms = ~p~n~nTimes = ~p",[Algs,Times]),
- lists:foreach(
- fun({{A,B},Value,Unit}) when A==encrypt ; A==decrypt ->
- Data = [{value, Value},
- {suite, ?MODULE},
- {name, mk_name(["Sftp Cipher ",A," ",B," [",Unit,"]"])}
- ],
- ct:pal("sftp ct_event:notify ~p",[Data]),
- ct_event:notify(#event{name = benchmark_data,
- data = Data});
- ({channel_open_close,Value,Unit}) ->
- Cipher = fmt_alg(Algs#alg.encrypt, List),
- Data = [{value, round( (1024*Value) / SrcSize )},
- {suite, ?MODULE},
- {name, mk_name(["Sftp transfer ",Cipher," [",Unit," per kbyte]"])}
- ],
- ct:pal("sftp ct_event:notify ~p",[Data]),
- ct_event:notify(#event{name = benchmark_data,
- data = Data});
- (_) ->
- skip
- end, Times),
- ssh:stop_daemon(ServerPid),
- ok
- after 2*60*1000 ->
- ssh:stop_daemon(ServerPid),
- exit(SlavePid, kill),
- {fail, timeout}
- end.
-
-%%%================================================================
-variants(Tag, Config) ->
- TagType =
- case proplists:get_value(Tag, ssh:default_algorithms()) of
- [{_,_}|_] -> one_way;
- [A|_] when is_atom(A) -> two_way
- end,
- [ [{Tag,tag_value(TagType,Alg)}]
- || Alg <- proplists:get_value(Tag, proplists:get_value(common_algs,Config))
- ].
-
-tag_value(two_way, Alg) -> [Alg];
-tag_value(one_way, Alg) -> [{client2server,[Alg]},
- {server2client,[Alg]}].
-
-%%%----------------------------------------------------------------
-fmt_alg(Alg, List) when is_atom(Alg) ->
- fmt_alg(atom_to_list(Alg), List);
-fmt_alg(Alg = "diffie-hellman-group-exchange-sha" ++ _, List) ->
- try
- integer_to_list(find_gex_size_string(List))
- of
- GexSize -> lists:concat([Alg," ",GexSize])
- catch
- _:_ -> Alg
- end;
-fmt_alg(Alg, _List) ->
- Alg.
-
-%%%----------------------------------------------------------------
-mk_name(Name) -> [char(C) || C <- lists:concat(Name)].
-
-char($-) -> $_;
-char(C) -> C.
-
-%%%----------------------------------------------------------------
-find_times(L, Xs) ->
- [find_time(X,L) || X <- Xs] ++
- function_algs_times_sizes([{ssh_transport,encrypt,2},
- {ssh_transport,decrypt,2},
- {ssh_message,decode,1},
- {ssh_message,encode,1}], L).
-
--record(call, {
- mfa,
- pid,
- t_call,
- t_return,
- args,
- result
- }).
-
-%%%----------------
--define(send(M), fun(C=#call{mfa = {ssh_message,encode,1},
- args = [M]}) ->
- C#call.t_return
- end).
-
--define(recv(M), fun(C=#call{mfa = {ssh_message,decode,1},
- result = M}) ->
- C#call.t_call
- end).
-
-find_time(accept_to_hello, L) ->
- [T0,T1] = find([fun(C=#call{mfa = {ssh_acceptor,handle_connection,5}}) ->
- C#call.t_call
- end,
- ?LINE,
- fun(C=#call{mfa = {ssh_connection_handler,handle_event,4},
- args = [_, {version_exchange,_}, {hello,_}, _]}) ->
- C#call.t_call
- end,
- ?LINE
- ], L, []),
- {accept_to_hello, now2micro_sec(now_diff(T1,T0)), microsec};
-find_time(kex, L) ->
- [T0,T1] = find([fun(C=#call{mfa = {ssh_connection_handler,handle_event,4},
- args = [_, {version_exchange,_}, {hello,_}, _]}) ->
- C#call.t_call
- end,
- ?LINE,
- ?send(#ssh_msg_newkeys{}),
- ?LINE
- ], L, []),
- {kex, now2micro_sec(now_diff(T1,T0)), microsec};
-find_time(kex_to_auth, L) ->
- [T0,T1] = find([?send(#ssh_msg_newkeys{}),
- ?LINE,
- ?recv(#ssh_msg_userauth_request{}),
- ?LINE
- ], L, []),
- {kex_to_auth, now2micro_sec(now_diff(T1,T0)), microsec};
-find_time(auth, L) ->
- [T0,T1] = find([?recv(#ssh_msg_userauth_request{}),
- ?LINE,
- ?send(#ssh_msg_userauth_success{}),
- ?LINE
- ], L, []),
- {auth, now2micro_sec(now_diff(T1,T0)), microsec};
-find_time(to_prompt, L) ->
- [T0,T1] = find([fun(C=#call{mfa = {ssh_acceptor,handle_connection,5}}) ->
- C#call.t_call
- end,
- ?LINE,
- ?recv(#ssh_msg_channel_request{request_type="env"}),
- ?LINE
- ], L, []),
- {to_prompt, now2micro_sec(now_diff(T1,T0)), microsec};
-find_time(channel_open_close, L) ->
- [T0,T1] = find([?recv(#ssh_msg_channel_request{request_type="subsystem"}),
- ?LINE,
- ?send(#ssh_msg_channel_close{}),
- ?LINE
- ], L, []),
- {channel_open_close, now2micro_sec(now_diff(T1,T0)), microsec}.
-
-
-
-find([F,Id|Fs], [C|Cs], Acc) when is_function(F,1) ->
- try
- F(C)
- of
- T -> find(Fs, Cs, [T|Acc])
- catch
- _:_ -> find([F,Id|Fs], Cs, Acc)
- end;
-find([], _, Acc) ->
- lists:reverse(Acc).
-
-
-find_algs(L) ->
- {value, #call{result={ok,Algs}}} =
- lists:keysearch({ssh_transport,select_algorithm,3}, #call.mfa, L),
- Algs.
-
-find_gex_size_string(L) ->
- %% server
- {value, #call{result={ok,{Size, _}}}} =
- lists:keysearch({public_key,dh_gex_group,4}, #call.mfa, L),
- Size.
-
-%%%----------------
-function_algs_times_sizes(EncDecs, L) ->
- Raw = [begin
- {Tag,Size} = function_ats_result(EncDec, C),
- {Tag, Size, now2micro_sec(now_diff(T1,T0))}
- end
- || EncDec <- EncDecs,
- C = #call{mfa = ED,
- % args = Args, %%[S,Data],
- t_call = T0,
- t_return = T1} <- L,
- ED == EncDec
- ],
- [{Alg, round(1024*Time/Size), "microsec per kbyte"} % Microseconds per 1k bytes.
- || {Alg,Size,Time} <- lists:foldl(fun increment/2, [], Raw)].
-
-function_ats_result({ssh_transport,encrypt,2}, #call{args=[S,Data]}) ->
- {{encrypt,S#ssh.encrypt}, binsize(Data)};
-function_ats_result({ssh_transport,decrypt,2}, #call{args=[S,Data]}) ->
- {{decrypt,S#ssh.decrypt}, binsize(Data)};
-function_ats_result({ssh_message,encode,1}, #call{result=Data}) ->
- {encode, size(Data)};
-function_ats_result({ssh_message,decode,1}, #call{args=[Data]}) ->
- {decode, size(Data)}.
-
-binsize(B) when is_binary(B) -> size(B);
-binsize({B1,B2}) when is_binary(B1), is_binary(B2) -> size(B1) + size(B2);
-binsize({B1,B2,_}) when is_binary(B1), is_binary(B2) -> size(B1) + size(B2).
-
-
-
-
-
-increment({Alg,Sz,T}, [{Alg,SumSz,SumT}|Acc]) ->
- [{Alg,SumSz+Sz,SumT+T} | Acc];
-increment(Spec, [X|Acc]) ->
- [X | increment(Spec,Acc)]; % Not so many Alg, 2 or 3
-increment({Alg,Sz,T},[]) ->
- [{Alg,Sz,T}].
-
-%%%----------------------------------------------------------------
-%%%
-%%% API for the traceing
-%%%
-get_trace_list(TracerPid) ->
- MonRef = monitor(process, TracerPid),
- TracerPid ! {get_trace_list,self()},
- receive
- {trace_list,L} ->
- demonitor(MonRef),
- {ok, pair_events(lists:reverse(L))};
- {'DOWN', MonRef, process, TracerPid, Info} ->
- {error, {tracer_down,Info}}
-
- after 3*60*1000 ->
- demonitor(MonRef),
- {error,no_reply}
- end.
-
-erlang_trace() ->
- TracerPid = spawn(fun trace_loop/0),
- 0 = erlang:trace(new, true, [call,timestamp,{tracer,TracerPid}]),
- [init_trace(MFA, tp(MFA))
- || MFA <- [{ssh_acceptor,handle_connection,5},
-%% {ssh_connection_handler,hello,2},
- {ssh_message,encode,1},
- {ssh_message,decode,1},
- {ssh_transport,select_algorithm,3},
- {ssh_transport,encrypt,2},
- {ssh_transport,decrypt,2},
- {ssh_message,encode,1},
- {ssh_message,decode,1},
- {public_key,dh_gex_group,4} % To find dh_gex group size
- ]],
- init_trace({ssh_connection_handler,handle_event,4},
- [{['_', {version_exchange,'_'}, {hello,'_'}, '_'],
- [],
- [return_trace]}]),
- {ok, TracerPid}.
-
-tp({_M,_F,Arity}) ->
- [{lists:duplicate(Arity,'_'), [], [{return_trace}]}].
-
-%%%----------------------------------------------------------------
-init_trace(MFA = {Module,_,_}, TP) ->
- case code:is_loaded(Module) of
- false -> code:load_file(Module);
- _ -> ok
- end,
- erlang:trace_pattern(MFA, TP, [local]).
-
-
-trace_loop() ->
- trace_loop([]).
-
-trace_loop(L) ->
- receive
- {get_trace_list, From} ->
- From ! {trace_list, L},
- trace_loop(L);
- Ev ->
- trace_loop([Ev|L])
- end.
-
-pair_events(L) ->
- pair_events(L, []).
-
-pair_events([{trace_ts,Pid,call,{M,F,Args},TS0} | L], Acc) ->
- Arity = length(Args),
- {ReturnValue,TS1} = find_return(Pid, {M,F,Arity}, L),
- pair_events(L, [#call{mfa = {M,F,Arity},
- pid = Pid,
- t_call = TS0,
- t_return = TS1,
- args = Args,
- result = ReturnValue} | Acc]);
-pair_events([_|L], Acc) ->
- pair_events(L, Acc);
-pair_events([], Acc) ->
- lists:reverse(Acc).
-
-
-find_return(Pid, MFA,
- [{trace_ts, Pid, return_from, MFA, ReturnValue, TS}|_]) ->
- {ReturnValue, TS};
-find_return(Pid, MFA, [_|L]) ->
- find_return(Pid, MFA, L);
-find_return(_, _, []) ->
- {undefined, undefined}.
-
-%%%----------------------------------------------------------------
-report_client_algorithms() ->
- try
- ssh_test_lib:extract_algos( ssh_test_lib:default_algorithms(sshc) )
- of
- ClientAlgs ->
- ct:pal("The client supports:~n~p",[ClientAlgs])
- catch
- Cls:Err ->
- ct:pal("Testing client about algorithms failed:~n~p ~p",[Cls,Err])
- end.
-
-%%%----------------------------------------------------------------
-
-
-now2sec({A,B,C}) -> A*1000000 + B + C/1000000.
-
-now2micro_sec({A,B,C}) -> (A*1000000 + B)*1000000 + C.
-
-now_diff({A1,B1,C1}, {A0,B0,C0}) -> {A1-A0, B1-B0, C1-C0}.
-
-%%%================================================================
-moduli() ->
- [{1023, 5, 16#CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D182EB7},
- {2047, 5, 16#F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE5E381EF},
- {4095, 2, 16#C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156BA7321EB},
- {6143, 5, 16#FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23C3BEB637},
- {8191, 2, 16#DC61EF13E4F3FC10CC946EEABC33F83EFCB35E0F47E4EC25C1CCBB2C7B502B2EFB0691AA231C8476DD51BA73204E6EA10B1A970FE2CF14AF01E72E1AEA87519A91D00D1499189F94A6CDA9E29C05F11F17FE74A4919A710A2787E180744465DF81C62AA65662FDA46FA6175E8A31E5B29E66DED6701C8FC4217E91D733FE94380F046680967D4CEA7BAC8F3916CDF96AA2C474FAD9650F48403FD0B5B756D34667D36A07767FA33027AE55484D0F701C3CA16632F413A14E4B8645AFAF15B78978C19A7661EDC569BEC72394B1204B166A48FCD5F56BE29840C7794CA6D3440356F15858CDCA9B429C7EA92E17242893FDC8C9C63841A382C32F20CFAB121B4BCAFD7BF9EF07FBF7CDFFECA0CEF3A49C3E2B24FA836F3318435255655E1B281071F62D5E4CD63361299B7828F72936E3FEA9E8044562A6F6ADD5321187C3101E4669C6271598FE1A866C93FE2870A4CEB9254BA32A4719E439317EA42200A335B5CFFA7946A7D0F1BD1A69AA11288B73C71C80B77FE3707CB077DDDEA5CA36A449FAB230C9625A0B12F8275D3FF82F5DA380E7A3F11B6F155FE7E91AC960BD95D9B13F7423AB9B15CC3C4DC34EF296033F009468EA16A721AD659F56C18516025050749ABF05E6D3EBD9778142A530979291F46DAA399A86B7BCDF09CC3E6EEF101419762A306DB45AEFC96C64E83F28338D55905F6A387E0F515E580C3A9B35330E21C32198CDEE3AFB355967A098F635FCA7C49CB4E1E82464B2B390EF1F259E40B9A06235C0273F76284FE6BD534EF3AF7CB01A4A5252B8B94CADC2850B2E56D53F9A31D7C029DF967D0A30C05BC64E119BED6076818FABC8CDD93F3255693E14EFC1A740A5D63A5E847FFE87BAB1DDE0506E1762EA61EFA9F9756151ECCCADD91B98A961A901A2D8B01ABDDD29EC804E8C8D28214BBA26048F924CA66316696E51A49D02FF034D20E44914B1115339CAD3819E0CB1640F0084886FEDDE5E28C29DC48ED30A8C3D789734338F5A9DF42584326E536FD1CF30BC85B8DCBD6120D127C98FE4B3614074F13C2CA4854E6D794156C185C40EB3DA7619CE96ADAF0941BD5499848B034C2B11DFECC0BDFA81C594241F759EF53FC7CDE7F2DE4F23CF81A5A0B7D62E31DABB9198D40307F7824DD130B7D1B80E9B6D322FEEDB5ACE34944F0BFB7D016762A9B2E173BFDD69303766AFBAB45FAB75D05430B4A3515858C4B7F04E23414E4AD03842CB0A20D8FF4B59B7C852BA9A5BE982A8ADA5CB70C36CE2A4D2C31A7015C9F3275E43D192C1B2924424088907A057DA7F2D32A2149922AB2E33F2147D637A3508911CB3FEA5E1AAB4525BACF27B6DD7A3E0AFA978FC3A39DE8882FB22688C3CCC92B6E69ACB0BBF575AB3368E51A2F6A20C414C6F146727CC0045F29061E695D29F7C030CE6929EB3AD11A5CBD0CDEE37347869A3}].
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/id_dsa b/lib/ssh/test/ssh_benchmark_SUITE_data/id_dsa
deleted file mode 100644
index d306f8b26e..0000000000
--- a/lib/ssh/test/ssh_benchmark_SUITE_data/id_dsa
+++ /dev/null
@@ -1,13 +0,0 @@
------BEGIN DSA PRIVATE KEY-----
-MIIBvAIBAAKBgQDfi2flSTZZofwT4yQT0NikX/LGNT7UPeB/XEWe/xovEYCElfaQ
-APFixXvEgXwoojmZ5kiQRKzLM39wBP0jPERLbnZXfOOD0PDnw0haMh7dD7XKVMod
-/EigVgHf/qBdM2M8yz1s/rRF7n1UpLSypziKjkzCm7JoSQ2zbWIPdmBIXwIVAMgP
-kpr7Sq3O7sHdb8D601DRjoExAoGAMOQxDfB2Fd8ouz6G96f/UOzRMI/Kdv8kYYKW
-JIGY+pRYrLPyYzUeJznwZreOJgrczAX+luHnKFWJ2Dnk5CyeXk67Wsr7pJ/4MBMD
-OKeIS0S8qoSBN8+Krp79fgA+yS3IfqbkJLtLu4EBaCX4mKQIX4++k44d4U5lc8pt
-+9hlEI8CgYEAznKxx9kyC6bVo7LUYKaGhofRFt0SYFc5PVmT2VUGRs1R6+6DPD+e
-uEO6IhFct7JFSRbP9p0JD4Uk+3zlZF+XX6b2PsZkeV8f/02xlNGUSmEzCSiNg1AX
-Cy/WusYhul0MncWCHMcOZB5rIvU/aP5EJJtn3xrRaz6u0SThF6AnT34CFQC63czE
-ZU8w8Q+H7z0j+a+70x2iAw==
------END DSA PRIVATE KEY-----
-
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa256 b/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa256
deleted file mode 100644
index 4b1eb12eaa..0000000000
--- a/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa256
+++ /dev/null
@@ -1,5 +0,0 @@
------BEGIN EC PRIVATE KEY-----
-MHcCAQEEIJfCaBKIIKhjbJl5F8BedqlXOQYDX5ba9Skypllmx/w+oAoGCCqGSM49
-AwEHoUQDQgAE49RbK2xQ/19ji3uDPM7uT4692LbwWF1TiaA9vUuebMGazoW/98br
-N9xZu0L1AWwtEjs3kmJDTB7eJEGXnjUAcQ==
------END EC PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa256.pub b/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa256.pub
deleted file mode 100644
index a0147e60fa..0000000000
--- a/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa256.pub
+++ /dev/null
@@ -1 +0,0 @@
-ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOPUWytsUP9fY4t7gzzO7k+Ovdi28FhdU4mgPb1LnmzBms6Fv/fG6zfcWbtC9QFsLRI7N5JiQ0we3iRBl541AHE= uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa384 b/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa384
deleted file mode 100644
index 4e8aa40959..0000000000
--- a/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa384
+++ /dev/null
@@ -1,6 +0,0 @@
------BEGIN EC PRIVATE KEY-----
-MIGkAgEBBDCYXb6OSAZyXRfLXOtMo43za197Hdc/T0YKjgQQjwDt6rlRwqTh7v7S
-PV2kXwNGdWigBwYFK4EEACKhZANiAARN2khlJUOOIiwsWHEALwDieeZR96qL4pUd
-ci7aeGaczdUK5jOA9D9zmBZtSYTfO8Cr7ekVghDlcWAIJ/BXcswgQwSEQ6wyfaTF
-8FYfyr4l3u9IirsnyaFzeIgeoNis8Gw=
------END EC PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa384.pub b/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa384.pub
deleted file mode 100644
index 41e722e545..0000000000
--- a/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa384.pub
+++ /dev/null
@@ -1 +0,0 @@
-ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBE3aSGUlQ44iLCxYcQAvAOJ55lH3qovilR1yLtp4ZpzN1QrmM4D0P3OYFm1JhN87wKvt6RWCEOVxYAgn8FdyzCBDBIRDrDJ9pMXwVh/KviXe70iKuyfJoXN4iB6g2KzwbA== uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa521 b/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa521
deleted file mode 100644
index 7196f46e97..0000000000
--- a/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa521
+++ /dev/null
@@ -1,7 +0,0 @@
------BEGIN EC PRIVATE KEY-----
-MIHbAgEBBEFMadoz4ckEcClfqXa2tiUuYkJdDfwq+/iFQcpt8ESuEd26IY/vm47Q
-9UzbPkO4ou8xkNsQ3WvCRQBBWtn5O2kUU6AHBgUrgQQAI6GBiQOBhgAEAde5BRu5
-01/jS0jRk212xsb2DxPrxNpgp6IMCV8TA4Eps+8bSqHB091nLiBcP422HXYfuCd7
-XDjSs8ihcmhp0hCRASLqZR9EzW9W/SOt876May1Huj5X+WSO6RLe7vPn9vmf7kHf
-pip6m7M7qp2qGgQ3q2vRwS2K/O6156ohiOlmuuFs
------END EC PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa521.pub b/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa521.pub
deleted file mode 100644
index 8f059120bc..0000000000
--- a/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa521.pub
+++ /dev/null
@@ -1 +0,0 @@
-ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAHXuQUbudNf40tI0ZNtdsbG9g8T68TaYKeiDAlfEwOBKbPvG0qhwdPdZy4gXD+Nth12H7gne1w40rPIoXJoadIQkQEi6mUfRM1vVv0jrfO+jGstR7o+V/lkjukS3u7z5/b5n+5B36YqepuzO6qdqhoEN6tr0cEtivzuteeqIYjpZrrhbA== uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/id_rsa b/lib/ssh/test/ssh_benchmark_SUITE_data/id_rsa
deleted file mode 100644
index 9d7e0dd5fb..0000000000
--- a/lib/ssh/test/ssh_benchmark_SUITE_data/id_rsa
+++ /dev/null
@@ -1,15 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIICXAIBAAKBgQD1OET+3O/Bvj/dtjxDTXmj1oiJt4sIph5kGy0RfjoPrZfaS+CU
-DhakCmS6t2ivxWFgtpKWaoGMZMJqWj6F6ZsumyFl3FPBtujwY/35cgifrI9Ns4Tl
-zR1uuengNBmV+WRQ5cd9F2qS6Z8aDQihzt0r8JUqLcK+VQbrmNzboCCQQwIDAQAB
-AoGAPQEyqPTt8JUT7mRXuaacjFXiweAXhp9NEDpyi9eLOjtFe9lElZCrsUOkq47V
-TGUeRKEm9qSodfTbKPoqc8YaBJGJPhUaTAcha+7QcDdfHBvIsgxvU7ePVnlpXRp3
-CCUEMPhlnx6xBoTYP+fRU0e3+xJIPVyVCqX1jAdUMkzfRoECQQD6ux7B1QJAIWyK
-SGkbDUbBilNmzCFNgIpOP6PA+bwfi5d16diTpra5AX09keQABAo/KaP1PdV8Vg0p
-z4P3A7G3AkEA+l+AKG6m0kQTTBMJDqOdVPYwe+5GxunMaqmhokpEbuGsrZBl5Dvd
-WpcBjR7jmenrhKZRIuA+Fz5HPo/UQJPl1QJBAKxstDkeED8j/S2XoFhPKAJ+6t39
-sUVICVTIZQeXdmzHJXCcUSkw8+WEhakqw/3SyW0oaK2FSWQJFWJUZ+8eJj8CQEh3
-xeduB5kKnS9CvzdeghZqX6QvVosSdtlUmfUYW/BgH5PpHKTP8wTaeld3XldZTpMJ
-dKiMkUw2+XYROVUrubUCQD+Na1LhULlpn4ISEtIEfqpdlUhxDgO15Wg8USmsng+x
-ICliVOSQtwaZjm8kwaFt0W7XnpnDxbRs37vIEbIMWak=
------END RSA PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_dsa_key b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_dsa_key
deleted file mode 100644
index 51ab6fbd88..0000000000
--- a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_dsa_key
+++ /dev/null
@@ -1,13 +0,0 @@
------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_benchmark_SUITE_data/ssh_host_dsa_key.pub b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_dsa_key.pub
deleted file mode 100644
index 4dbb1305b0..0000000000
--- a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_dsa_key.pub
+++ /dev/null
@@ -1,11 +0,0 @@
----- 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/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key256 b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key256
deleted file mode 100644
index 2979ea88ed..0000000000
--- a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key256
+++ /dev/null
@@ -1,5 +0,0 @@
------BEGIN EC PRIVATE KEY-----
-MHcCAQEEIMe4MDoit0t8RzSVPwkCBemQ9fhXL+xnTSAWISw8HNCioAoGCCqGSM49
-AwEHoUQDQgAEo2q7U3P6r0W5WGOLtM78UQtofM9UalEhiZeDdiyylsR/RR17Op0s
-VPGSADLmzzgcucLEKy17j2S+oz42VUJy5A==
------END EC PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key256.pub b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key256.pub
deleted file mode 100644
index 85dc419345..0000000000
--- a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key256.pub
+++ /dev/null
@@ -1 +0,0 @@
-ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKNqu1Nz+q9FuVhji7TO/FELaHzPVGpRIYmXg3YsspbEf0UdezqdLFTxkgAy5s84HLnCxCste49kvqM+NlVCcuQ= uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key384 b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key384
deleted file mode 100644
index fb1a862ded..0000000000
--- a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key384
+++ /dev/null
@@ -1,6 +0,0 @@
------BEGIN EC PRIVATE KEY-----
-MIGkAgEBBDArxbDfh3p1okrD9wQw6jJ4d4DdlBPD5GqXE8bIeRJiK41Sh40LgvPw
-mkqEDSXK++CgBwYFK4EEACKhZANiAAScl43Ih2lWTDKrSox5ve5uiTXil4smsup3
-CfS1XPjKxgBAmlfBim8izbdrT0BFdQzz2joduNMtpt61wO4rGs6jm0UP7Kim9PC7
-Hneb/99fIYopdMH5NMnk60zGO1uZ2vc=
------END EC PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key384.pub b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key384.pub
deleted file mode 100644
index 428d5fb7d7..0000000000
--- a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key384.pub
+++ /dev/null
@@ -1 +0,0 @@
-ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBJyXjciHaVZMMqtKjHm97m6JNeKXiyay6ncJ9LVc+MrGAECaV8GKbyLNt2tPQEV1DPPaOh240y2m3rXA7isazqObRQ/sqKb08Lsed5v/318hiil0wfk0yeTrTMY7W5na9w== uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key521 b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key521
deleted file mode 100644
index 3e51ec2ecd..0000000000
--- a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key521
+++ /dev/null
@@ -1,7 +0,0 @@
------BEGIN EC PRIVATE KEY-----
-MIHcAgEBBEIB8O1BFkl2HQjQLRLonEZ97da/h39DMa9/0/hvPZWAI8gUPEQcHxRx
-U7b09p3Zh+EBbMFq8+1ae9ds+ZTxE4WFSvKgBwYFK4EEACOhgYkDgYYABAAlWVjq
-Bzg7Wt4gE6UNb1lRE2cnlmH2L/A5uo6qZRx5lPnSKOxEhxSb/Oay1+9d6KRdrh6/
-vlhd9SHDBhLcAPDvWgBnJIEj92Q3pXX4JtoitL0yl+SvvU+vUh966mzHShHzj8p5
-ccOgPkPNoA70yrpGzkIhPezpZOQdCaOXj/jFqNCTDg==
------END EC PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key521.pub b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key521.pub
deleted file mode 100644
index 017a29f4da..0000000000
--- a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key521.pub
+++ /dev/null
@@ -1 +0,0 @@
-ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAAlWVjqBzg7Wt4gE6UNb1lRE2cnlmH2L/A5uo6qZRx5lPnSKOxEhxSb/Oay1+9d6KRdrh6/vlhd9SHDBhLcAPDvWgBnJIEj92Q3pXX4JtoitL0yl+SvvU+vUh966mzHShHzj8p5ccOgPkPNoA70yrpGzkIhPezpZOQdCaOXj/jFqNCTDg== uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_rsa_key b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_rsa_key
deleted file mode 100644
index 79968bdd7d..0000000000
--- a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_rsa_key
+++ /dev/null
@@ -1,16 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIICXQIBAAKBgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8semM4q843337
-zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RWRWzjaxSB
-6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4QIDAQAB
-AoGANmvJzJO5hkLuvyDZHKfAnGTtpifcR1wtSa9DjdKUyn8vhKF0mIimnbnYQEmW
-NUUb3gXCZLi9PvkpRSVRrASDOZwcjoU/Kvww163vBUVb2cOZfFhyn6o2Sk88Tt++
-udH3hdjpf9i7jTtUkUe+QYPsia+wgvvrmn4QrahLAH86+kECQQDx5gFeXTME3cnW
-WMpFz3PPumduzjqgqMMWEccX4FtQkMX/gyGa5UC7OHFyh0N/gSWvPbRHa8A6YgIt
-n8DO+fh5AkEAzbqX4DOn8NY6xJIi42q7l/2jIA0RkB6P7YugW5NblhqBZ0XDnpA5
-sMt+rz+K07u9XZtxgh1xi7mNfwY6lEAMqQJBAJBEauCKmRj35Z6OyeQku59SPsnY
-+SJEREVvSNw2lH9SOKQQ4wPsYlTGbvKtNVZgAcen91L5MmYfeckYE/fdIZECQQCt
-64zxsTnM1I8iFxj/gP/OYlJBikrKt8udWmjaghzvLMEw+T2DExJyb9ZNeT53+UMB
-m6O+B/4xzU/djvp+0hbhAkAemIt+rA5kTmYlFndhpvzkSSM8a2EXsO4XIPgGWCTT
-tQKS/tTly0ADMjN/TVy11+9d6zcqadNVuHXHGtR4W0GR
------END RSA PRIVATE KEY-----
-
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_rsa_key.pub b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_rsa_key.pub
deleted file mode 100644
index 75d2025c71..0000000000
--- a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_rsa_key.pub
+++ /dev/null
@@ -1,5 +0,0 @@
----- BEGIN SSH2 PUBLIC KEY ----
-AAAAB3NzaC1yc2EAAAADAQABAAAAgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8
-semM4q843337zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RW
-RWzjaxSB6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4Q==
----- END SSH2 PUBLIC KEY ----
--
cgit v1.2.3
From 405ce6b57ecf527017fd9066a962b6f3aaa00c09 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 27 Feb 2017 16:09:27 +0100
Subject: ssh: new benchmark suite: ssh_bench_SUITE
---
lib/ssh/test/Makefile | 2 +
lib/ssh/test/ssh.spec | 2 +-
lib/ssh/test/ssh_bench.spec | 4 +-
lib/ssh/test/ssh_bench_SUITE.erl | 252 +++++++++++++++++++++
lib/ssh/test/ssh_bench_SUITE_data/id_dsa | 13 ++
lib/ssh/test/ssh_bench_SUITE_data/id_ecdsa256 | 5 +
lib/ssh/test/ssh_bench_SUITE_data/id_ecdsa256.pub | 1 +
lib/ssh/test/ssh_bench_SUITE_data/id_ecdsa384 | 6 +
lib/ssh/test/ssh_bench_SUITE_data/id_ecdsa384.pub | 1 +
lib/ssh/test/ssh_bench_SUITE_data/id_ecdsa521 | 7 +
lib/ssh/test/ssh_bench_SUITE_data/id_ecdsa521.pub | 1 +
lib/ssh/test/ssh_bench_SUITE_data/id_rsa | 15 ++
lib/ssh/test/ssh_bench_SUITE_data/ssh_host_dsa_key | 13 ++
.../test/ssh_bench_SUITE_data/ssh_host_dsa_key.pub | 11 +
.../ssh_bench_SUITE_data/ssh_host_ecdsa_key256 | 5 +
.../ssh_bench_SUITE_data/ssh_host_ecdsa_key256.pub | 1 +
.../ssh_bench_SUITE_data/ssh_host_ecdsa_key384 | 6 +
.../ssh_bench_SUITE_data/ssh_host_ecdsa_key384.pub | 1 +
.../ssh_bench_SUITE_data/ssh_host_ecdsa_key521 | 7 +
.../ssh_bench_SUITE_data/ssh_host_ecdsa_key521.pub | 1 +
lib/ssh/test/ssh_bench_SUITE_data/ssh_host_rsa_key | 16 ++
.../test/ssh_bench_SUITE_data/ssh_host_rsa_key.pub | 5 +
lib/ssh/test/ssh_bench_dev_null.erl | 58 +++++
23 files changed, 430 insertions(+), 3 deletions(-)
create mode 100644 lib/ssh/test/ssh_bench_SUITE.erl
create mode 100644 lib/ssh/test/ssh_bench_SUITE_data/id_dsa
create mode 100644 lib/ssh/test/ssh_bench_SUITE_data/id_ecdsa256
create mode 100644 lib/ssh/test/ssh_bench_SUITE_data/id_ecdsa256.pub
create mode 100644 lib/ssh/test/ssh_bench_SUITE_data/id_ecdsa384
create mode 100644 lib/ssh/test/ssh_bench_SUITE_data/id_ecdsa384.pub
create mode 100644 lib/ssh/test/ssh_bench_SUITE_data/id_ecdsa521
create mode 100644 lib/ssh/test/ssh_bench_SUITE_data/id_ecdsa521.pub
create mode 100644 lib/ssh/test/ssh_bench_SUITE_data/id_rsa
create mode 100644 lib/ssh/test/ssh_bench_SUITE_data/ssh_host_dsa_key
create mode 100644 lib/ssh/test/ssh_bench_SUITE_data/ssh_host_dsa_key.pub
create mode 100644 lib/ssh/test/ssh_bench_SUITE_data/ssh_host_ecdsa_key256
create mode 100644 lib/ssh/test/ssh_bench_SUITE_data/ssh_host_ecdsa_key256.pub
create mode 100644 lib/ssh/test/ssh_bench_SUITE_data/ssh_host_ecdsa_key384
create mode 100644 lib/ssh/test/ssh_bench_SUITE_data/ssh_host_ecdsa_key384.pub
create mode 100644 lib/ssh/test/ssh_bench_SUITE_data/ssh_host_ecdsa_key521
create mode 100644 lib/ssh/test/ssh_bench_SUITE_data/ssh_host_ecdsa_key521.pub
create mode 100644 lib/ssh/test/ssh_bench_SUITE_data/ssh_host_rsa_key
create mode 100644 lib/ssh/test/ssh_bench_SUITE_data/ssh_host_rsa_key.pub
create mode 100644 lib/ssh/test/ssh_bench_dev_null.erl
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/Makefile b/lib/ssh/test/Makefile
index 512e429962..fab79a7a43 100644
--- a/lib/ssh/test/Makefile
+++ b/lib/ssh/test/Makefile
@@ -36,6 +36,7 @@ MODULES= \
ssh_options_SUITE \
ssh_renegotiate_SUITE \
ssh_basic_SUITE \
+ ssh_bench_SUITE \
ssh_connection_SUITE \
ssh_protocol_SUITE \
ssh_sftp_SUITE \
@@ -49,6 +50,7 @@ MODULES= \
ssh_key_cb_options \
ssh_trpt_test_lib \
ssh_echo_server \
+ ssh_bench_dev_null \
ssh_peername_sockname_server \
ssh_test_cli \
ssh_relay \
diff --git a/lib/ssh/test/ssh.spec b/lib/ssh/test/ssh.spec
index 92351f3ed1..68268cb20d 100644
--- a/lib/ssh/test/ssh.spec
+++ b/lib/ssh/test/ssh.spec
@@ -1,6 +1,6 @@
{suites,"../ssh_test",all}.
-{skip_suites, "../ssh_test", [
+{skip_suites, "../ssh_test", [ssh_bench_SUITE
],
"Benchmarks run separately"}.
diff --git a/lib/ssh/test/ssh_bench.spec b/lib/ssh/test/ssh_bench.spec
index 7204073cea..b0b64713cf 100644
--- a/lib/ssh/test/ssh_bench.spec
+++ b/lib/ssh/test/ssh_bench.spec
@@ -1,2 +1,2 @@
-{suites,"../ssh_test",[
- ]}.
+{suites,"../ssh_test",[ssh_bench_SUITE
+ ]}.
diff --git a/lib/ssh/test/ssh_bench_SUITE.erl b/lib/ssh/test/ssh_bench_SUITE.erl
new file mode 100644
index 0000000000..d2ba8afa1a
--- /dev/null
+++ b/lib/ssh/test/ssh_bench_SUITE.erl
@@ -0,0 +1,252 @@
+%%%-------------------------------------------------------------------
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(ssh_bench_SUITE).
+-compile(export_all).
+
+-include_lib("common_test/include/ct_event.hrl").
+-include_lib("common_test/include/ct.hrl").
+
+-include_lib("ssh/src/ssh.hrl").
+-include_lib("ssh/src/ssh_transport.hrl").
+-include_lib("ssh/src/ssh_connect.hrl").
+-include_lib("ssh/src/ssh_userauth.hrl").
+
+%%%================================================================
+%%%
+%%% Suite declarations
+%%%
+
+suite() -> [{ct_hooks,[{ts_install_cth,[{nodenames,2}]}]},
+ {timetrap,{minutes,1}}
+ ].
+all() -> [connect,
+ transfer_text
+ ].
+
+-define(UID, "foo").
+-define(PWD, "bar").
+-define(Nruns, 8).
+
+%%%================================================================
+%%%
+%%% Init per suite
+%%%
+
+init_per_suite(Config) ->
+ catch ssh:stop(),
+ try
+ ok = ssh:start()
+ of
+ ok ->
+ DataSize = 1000000,
+ SystemDir = proplists:get_value(data_dir, Config),
+ Algs = insert_none(ssh:default_algorithms()),
+ {_ServerPid, _Host, Port} =
+ ssh_test_lib:daemon([{system_dir, SystemDir},
+ {user_passwords, [{?UID,?PWD}]},
+ {failfun, fun ssh_test_lib:failfun/2},
+ {preferred_algorithms, Algs},
+ {max_random_length_padding, 0},
+ {subsystems, [{"/dev/null", {ssh_bench_dev_null,[DataSize]}}]}
+ ]),
+ [{host,"localhost"}, {port,Port}, {uid,?UID}, {pwd,?PWD}, {data_size,DataSize} | Config]
+ catch
+ C:E ->
+ {skip, io_lib:format("Couldn't start ~p:~p",[C,E])}
+ end.
+
+end_per_suite(_Config) ->
+ catch ssh:stop(),
+ ok.
+
+%%%================================================================
+%%%
+%%% Init per testcase
+%%%
+
+init_per_testcase(_Func, Conf) ->
+ Conf.
+
+end_per_testcase(_Func, _Conf) ->
+ ok.
+
+%%%================================================================
+%%%
+%%% Testcases
+%%%
+
+%%%----------------------------------------------------------------
+%%% Measure the time for an Erlang client to connect to an Erlang
+%%% server on the localhost
+
+connect(Config) ->
+ KexAlgs = proplists:get_value(kex, ssh:default_algorithms()),
+ ct:pal("KexAlgs = ~p",[KexAlgs]),
+ lists:foreach(
+ fun(KexAlg) ->
+ PrefAlgs = preferred_algorithms(KexAlg),
+ report([{value, measure_connect(Config,
+ [{preferred_algorithms,PrefAlgs}])},
+ {suite, ?MODULE},
+ {name, mk_name(["Connect erlc erld ",KexAlg," [µs]"])}
+ ])
+ end, KexAlgs).
+
+
+measure_connect(Config, Opts) ->
+ Port = proplists:get_value(port, Config),
+ ConnectOptions = [{user, proplists:get_value(uid, Config)},
+ {password, proplists:get_value(pwd, Config)},
+ {user_dir, proplists:get_value(priv_dir, Config)},
+ {silently_accept_hosts, true},
+ {user_interaction, false},
+ {max_random_length_padding, 0}
+ ] ++ Opts,
+ median(
+ [begin
+ {Time, {ok,Pid}} = timer:tc(ssh,connect,["localhost", Port, ConnectOptions]),
+ ssh:close(Pid),
+ Time
+ end || _ <- lists:seq(1,?Nruns)]).
+
+%%%----------------------------------------------------------------
+%%% Measure the time to transfer a set of data with
+%%% and without crypto
+
+transfer_text(Config) ->
+ Port = proplists:get_value(port, Config),
+ Options = [{user, proplists:get_value(uid, Config)},
+ {password, proplists:get_value(pwd, Config)},
+ {user_dir, proplists:get_value(priv_dir, Config)},
+ {silently_accept_hosts, true},
+ {user_interaction, false},
+ {max_random_length_padding, 0}
+ ],
+ Data = gen_data(proplists:get_value(data_size,Config)),
+
+ [connect_measure(Port, Crypto, Mac, Data, Options)
+ || {Crypto,Mac} <- [{ none, none},
+ {'aes128-ctr', 'hmac-sha1'},
+ {'aes256-ctr', 'hmac-sha1'},
+ {'aes128-gcm@openssh.com', 'hmac-sha1'},
+ {'aes128-cbc', 'hmac-sha1'},
+ {'3des-cbc', 'hmac-sha1'},
+ {'aes128-ctr', 'hmac-sha2-256'},
+ {'aes128-ctr', 'hmac-sha2-512'}
+ ],
+ crypto_mac_supported(Crypto,Mac)].
+
+
+crypto_mac_supported(none, none) ->
+ true;
+crypto_mac_supported(C, M) ->
+ Algs = ssh:default_algorithms(),
+ [{_,Cs},_] = proplists:get_value(cipher, Algs),
+ [{_,Ms},_] = proplists:get_value(mac, Algs),
+ lists:member(C,Cs) andalso lists:member(M,Ms).
+
+
+gen_data(DataSz) ->
+ Data0 = << <> || _ <- lists:seq(1,DataSz div 256),
+ C <- lists:seq(0,255) >>,
+ Data1 = << <> || C <- lists:seq(0,(DataSz rem 256) - 1) >>,
+ <>.
+
+
+%% connect_measure(Port, Cipher, Mac, Data, Options) ->
+%% report([{value, 1},
+%% {suite, ?MODULE},
+%% {name, mk_name(["Transfer 1M bytes ",Cipher,"/",Mac," [µs]"])}]);
+connect_measure(Port, Cipher, Mac, Data, Options) ->
+ Times =
+ [begin
+ {ok,C} = ssh:connect("localhost", Port, [{preferred_algorithms, [{cipher,[Cipher]},
+ {mac,[Mac]}]}
+ |Options]),
+ {ok,Ch} = ssh_connection:session_channel(C, 10000),
+ success = ssh_connection:subsystem(C, Ch, "/dev/null", 10000),
+ {Time,ok} = timer:tc(?MODULE, send_wait_acc, [C, Ch, Data]),
+ ok = ssh_connection:send_eof(C, Ch),
+ ssh:close(C),
+ Time
+ end || _ <- lists:seq(1,?Nruns)],
+
+ report([{value, median(Times)},
+ {suite, ?MODULE},
+ {name, mk_name(["Transfer 1M bytes ",Cipher,"/",Mac," [µs]"])}]).
+
+send_wait_acc(C, Ch, Data) ->
+ ssh_connection:send(C, Ch, Data),
+ receive
+ {ssh_cm, C, {data, Ch, 0, <<"READY">>}} -> ok
+ end.
+
+
+%%%================================================================
+%%%
+%%% Private
+%%%
+
+%%%----------------------------------------------------------------
+insert_none(L) ->
+ lists:foldl(fun insert_none/2, [], L).
+
+insert_none({T,L}, Acc) when T==cipher ;
+ T==mac ->
+ [{T, [{T1,L1++[none]} || {T1,L1} <- L]} | Acc];
+insert_none(_, Acc) ->
+ Acc.
+
+%%%----------------------------------------------------------------
+mk_name(Name) -> [char(C) || C <- lists:concat(Name)].
+
+char($-) -> $_;
+char(C) -> C.
+
+%%%----------------------------------------------------------------
+preferred_algorithms(KexAlg) ->
+ [{kex, [KexAlg]},
+ {public_key, ['ssh-rsa']},
+ {cipher, ['aes128-ctr']},
+ {mac, ['hmac-sha1']},
+ {compression, [none]}
+ ].
+
+%%%----------------------------------------------------------------
+median(Data) when is_list(Data) ->
+ SortedData = lists:sort(Data),
+ N = length(Data),
+ Median =
+ case N rem 2 of
+ 0 ->
+ MeanOfMiddle = (lists:nth(N div 2, SortedData) +
+ lists:nth(N div 2 + 1, SortedData)) / 2,
+ round(MeanOfMiddle);
+ 1 ->
+ lists:nth(N div 2 + 1, SortedData)
+ end,
+ ct:pal("median(~p) = ~p",[SortedData,Median]),
+ Median.
+
+
+report(Data) ->
+ ct:pal("EventData = ~p",[Data]),
+ ct_event:notify(#event{name = benchmark_data,
+ data = Data}).
diff --git a/lib/ssh/test/ssh_bench_SUITE_data/id_dsa b/lib/ssh/test/ssh_bench_SUITE_data/id_dsa
new file mode 100644
index 0000000000..d306f8b26e
--- /dev/null
+++ b/lib/ssh/test/ssh_bench_SUITE_data/id_dsa
@@ -0,0 +1,13 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIBvAIBAAKBgQDfi2flSTZZofwT4yQT0NikX/LGNT7UPeB/XEWe/xovEYCElfaQ
+APFixXvEgXwoojmZ5kiQRKzLM39wBP0jPERLbnZXfOOD0PDnw0haMh7dD7XKVMod
+/EigVgHf/qBdM2M8yz1s/rRF7n1UpLSypziKjkzCm7JoSQ2zbWIPdmBIXwIVAMgP
+kpr7Sq3O7sHdb8D601DRjoExAoGAMOQxDfB2Fd8ouz6G96f/UOzRMI/Kdv8kYYKW
+JIGY+pRYrLPyYzUeJznwZreOJgrczAX+luHnKFWJ2Dnk5CyeXk67Wsr7pJ/4MBMD
+OKeIS0S8qoSBN8+Krp79fgA+yS3IfqbkJLtLu4EBaCX4mKQIX4++k44d4U5lc8pt
++9hlEI8CgYEAznKxx9kyC6bVo7LUYKaGhofRFt0SYFc5PVmT2VUGRs1R6+6DPD+e
+uEO6IhFct7JFSRbP9p0JD4Uk+3zlZF+XX6b2PsZkeV8f/02xlNGUSmEzCSiNg1AX
+Cy/WusYhul0MncWCHMcOZB5rIvU/aP5EJJtn3xrRaz6u0SThF6AnT34CFQC63czE
+ZU8w8Q+H7z0j+a+70x2iAw==
+-----END DSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_bench_SUITE_data/id_ecdsa256 b/lib/ssh/test/ssh_bench_SUITE_data/id_ecdsa256
new file mode 100644
index 0000000000..4b1eb12eaa
--- /dev/null
+++ b/lib/ssh/test/ssh_bench_SUITE_data/id_ecdsa256
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIJfCaBKIIKhjbJl5F8BedqlXOQYDX5ba9Skypllmx/w+oAoGCCqGSM49
+AwEHoUQDQgAE49RbK2xQ/19ji3uDPM7uT4692LbwWF1TiaA9vUuebMGazoW/98br
+N9xZu0L1AWwtEjs3kmJDTB7eJEGXnjUAcQ==
+-----END EC PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_bench_SUITE_data/id_ecdsa256.pub b/lib/ssh/test/ssh_bench_SUITE_data/id_ecdsa256.pub
new file mode 100644
index 0000000000..a0147e60fa
--- /dev/null
+++ b/lib/ssh/test/ssh_bench_SUITE_data/id_ecdsa256.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOPUWytsUP9fY4t7gzzO7k+Ovdi28FhdU4mgPb1LnmzBms6Fv/fG6zfcWbtC9QFsLRI7N5JiQ0we3iRBl541AHE= uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_bench_SUITE_data/id_ecdsa384 b/lib/ssh/test/ssh_bench_SUITE_data/id_ecdsa384
new file mode 100644
index 0000000000..4e8aa40959
--- /dev/null
+++ b/lib/ssh/test/ssh_bench_SUITE_data/id_ecdsa384
@@ -0,0 +1,6 @@
+-----BEGIN EC PRIVATE KEY-----
+MIGkAgEBBDCYXb6OSAZyXRfLXOtMo43za197Hdc/T0YKjgQQjwDt6rlRwqTh7v7S
+PV2kXwNGdWigBwYFK4EEACKhZANiAARN2khlJUOOIiwsWHEALwDieeZR96qL4pUd
+ci7aeGaczdUK5jOA9D9zmBZtSYTfO8Cr7ekVghDlcWAIJ/BXcswgQwSEQ6wyfaTF
+8FYfyr4l3u9IirsnyaFzeIgeoNis8Gw=
+-----END EC PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_bench_SUITE_data/id_ecdsa384.pub b/lib/ssh/test/ssh_bench_SUITE_data/id_ecdsa384.pub
new file mode 100644
index 0000000000..41e722e545
--- /dev/null
+++ b/lib/ssh/test/ssh_bench_SUITE_data/id_ecdsa384.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBE3aSGUlQ44iLCxYcQAvAOJ55lH3qovilR1yLtp4ZpzN1QrmM4D0P3OYFm1JhN87wKvt6RWCEOVxYAgn8FdyzCBDBIRDrDJ9pMXwVh/KviXe70iKuyfJoXN4iB6g2KzwbA== uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_bench_SUITE_data/id_ecdsa521 b/lib/ssh/test/ssh_bench_SUITE_data/id_ecdsa521
new file mode 100644
index 0000000000..7196f46e97
--- /dev/null
+++ b/lib/ssh/test/ssh_bench_SUITE_data/id_ecdsa521
@@ -0,0 +1,7 @@
+-----BEGIN EC PRIVATE KEY-----
+MIHbAgEBBEFMadoz4ckEcClfqXa2tiUuYkJdDfwq+/iFQcpt8ESuEd26IY/vm47Q
+9UzbPkO4ou8xkNsQ3WvCRQBBWtn5O2kUU6AHBgUrgQQAI6GBiQOBhgAEAde5BRu5
+01/jS0jRk212xsb2DxPrxNpgp6IMCV8TA4Eps+8bSqHB091nLiBcP422HXYfuCd7
+XDjSs8ihcmhp0hCRASLqZR9EzW9W/SOt876May1Huj5X+WSO6RLe7vPn9vmf7kHf
+pip6m7M7qp2qGgQ3q2vRwS2K/O6156ohiOlmuuFs
+-----END EC PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_bench_SUITE_data/id_ecdsa521.pub b/lib/ssh/test/ssh_bench_SUITE_data/id_ecdsa521.pub
new file mode 100644
index 0000000000..8f059120bc
--- /dev/null
+++ b/lib/ssh/test/ssh_bench_SUITE_data/id_ecdsa521.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAHXuQUbudNf40tI0ZNtdsbG9g8T68TaYKeiDAlfEwOBKbPvG0qhwdPdZy4gXD+Nth12H7gne1w40rPIoXJoadIQkQEi6mUfRM1vVv0jrfO+jGstR7o+V/lkjukS3u7z5/b5n+5B36YqepuzO6qdqhoEN6tr0cEtivzuteeqIYjpZrrhbA== uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_bench_SUITE_data/id_rsa b/lib/ssh/test/ssh_bench_SUITE_data/id_rsa
new file mode 100644
index 0000000000..9d7e0dd5fb
--- /dev/null
+++ b/lib/ssh/test/ssh_bench_SUITE_data/id_rsa
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQD1OET+3O/Bvj/dtjxDTXmj1oiJt4sIph5kGy0RfjoPrZfaS+CU
+DhakCmS6t2ivxWFgtpKWaoGMZMJqWj6F6ZsumyFl3FPBtujwY/35cgifrI9Ns4Tl
+zR1uuengNBmV+WRQ5cd9F2qS6Z8aDQihzt0r8JUqLcK+VQbrmNzboCCQQwIDAQAB
+AoGAPQEyqPTt8JUT7mRXuaacjFXiweAXhp9NEDpyi9eLOjtFe9lElZCrsUOkq47V
+TGUeRKEm9qSodfTbKPoqc8YaBJGJPhUaTAcha+7QcDdfHBvIsgxvU7ePVnlpXRp3
+CCUEMPhlnx6xBoTYP+fRU0e3+xJIPVyVCqX1jAdUMkzfRoECQQD6ux7B1QJAIWyK
+SGkbDUbBilNmzCFNgIpOP6PA+bwfi5d16diTpra5AX09keQABAo/KaP1PdV8Vg0p
+z4P3A7G3AkEA+l+AKG6m0kQTTBMJDqOdVPYwe+5GxunMaqmhokpEbuGsrZBl5Dvd
+WpcBjR7jmenrhKZRIuA+Fz5HPo/UQJPl1QJBAKxstDkeED8j/S2XoFhPKAJ+6t39
+sUVICVTIZQeXdmzHJXCcUSkw8+WEhakqw/3SyW0oaK2FSWQJFWJUZ+8eJj8CQEh3
+xeduB5kKnS9CvzdeghZqX6QvVosSdtlUmfUYW/BgH5PpHKTP8wTaeld3XldZTpMJ
+dKiMkUw2+XYROVUrubUCQD+Na1LhULlpn4ISEtIEfqpdlUhxDgO15Wg8USmsng+x
+ICliVOSQtwaZjm8kwaFt0W7XnpnDxbRs37vIEbIMWak=
+-----END RSA PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_bench_SUITE_data/ssh_host_dsa_key b/lib/ssh/test/ssh_bench_SUITE_data/ssh_host_dsa_key
new file mode 100644
index 0000000000..51ab6fbd88
--- /dev/null
+++ b/lib/ssh/test/ssh_bench_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_bench_SUITE_data/ssh_host_dsa_key.pub b/lib/ssh/test/ssh_bench_SUITE_data/ssh_host_dsa_key.pub
new file mode 100644
index 0000000000..4dbb1305b0
--- /dev/null
+++ b/lib/ssh/test/ssh_bench_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/test/ssh_bench_SUITE_data/ssh_host_ecdsa_key256 b/lib/ssh/test/ssh_bench_SUITE_data/ssh_host_ecdsa_key256
new file mode 100644
index 0000000000..2979ea88ed
--- /dev/null
+++ b/lib/ssh/test/ssh_bench_SUITE_data/ssh_host_ecdsa_key256
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIMe4MDoit0t8RzSVPwkCBemQ9fhXL+xnTSAWISw8HNCioAoGCCqGSM49
+AwEHoUQDQgAEo2q7U3P6r0W5WGOLtM78UQtofM9UalEhiZeDdiyylsR/RR17Op0s
+VPGSADLmzzgcucLEKy17j2S+oz42VUJy5A==
+-----END EC PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_bench_SUITE_data/ssh_host_ecdsa_key256.pub b/lib/ssh/test/ssh_bench_SUITE_data/ssh_host_ecdsa_key256.pub
new file mode 100644
index 0000000000..85dc419345
--- /dev/null
+++ b/lib/ssh/test/ssh_bench_SUITE_data/ssh_host_ecdsa_key256.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKNqu1Nz+q9FuVhji7TO/FELaHzPVGpRIYmXg3YsspbEf0UdezqdLFTxkgAy5s84HLnCxCste49kvqM+NlVCcuQ= uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_bench_SUITE_data/ssh_host_ecdsa_key384 b/lib/ssh/test/ssh_bench_SUITE_data/ssh_host_ecdsa_key384
new file mode 100644
index 0000000000..fb1a862ded
--- /dev/null
+++ b/lib/ssh/test/ssh_bench_SUITE_data/ssh_host_ecdsa_key384
@@ -0,0 +1,6 @@
+-----BEGIN EC PRIVATE KEY-----
+MIGkAgEBBDArxbDfh3p1okrD9wQw6jJ4d4DdlBPD5GqXE8bIeRJiK41Sh40LgvPw
+mkqEDSXK++CgBwYFK4EEACKhZANiAAScl43Ih2lWTDKrSox5ve5uiTXil4smsup3
+CfS1XPjKxgBAmlfBim8izbdrT0BFdQzz2joduNMtpt61wO4rGs6jm0UP7Kim9PC7
+Hneb/99fIYopdMH5NMnk60zGO1uZ2vc=
+-----END EC PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_bench_SUITE_data/ssh_host_ecdsa_key384.pub b/lib/ssh/test/ssh_bench_SUITE_data/ssh_host_ecdsa_key384.pub
new file mode 100644
index 0000000000..428d5fb7d7
--- /dev/null
+++ b/lib/ssh/test/ssh_bench_SUITE_data/ssh_host_ecdsa_key384.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBJyXjciHaVZMMqtKjHm97m6JNeKXiyay6ncJ9LVc+MrGAECaV8GKbyLNt2tPQEV1DPPaOh240y2m3rXA7isazqObRQ/sqKb08Lsed5v/318hiil0wfk0yeTrTMY7W5na9w== uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_bench_SUITE_data/ssh_host_ecdsa_key521 b/lib/ssh/test/ssh_bench_SUITE_data/ssh_host_ecdsa_key521
new file mode 100644
index 0000000000..3e51ec2ecd
--- /dev/null
+++ b/lib/ssh/test/ssh_bench_SUITE_data/ssh_host_ecdsa_key521
@@ -0,0 +1,7 @@
+-----BEGIN EC PRIVATE KEY-----
+MIHcAgEBBEIB8O1BFkl2HQjQLRLonEZ97da/h39DMa9/0/hvPZWAI8gUPEQcHxRx
+U7b09p3Zh+EBbMFq8+1ae9ds+ZTxE4WFSvKgBwYFK4EEACOhgYkDgYYABAAlWVjq
+Bzg7Wt4gE6UNb1lRE2cnlmH2L/A5uo6qZRx5lPnSKOxEhxSb/Oay1+9d6KRdrh6/
+vlhd9SHDBhLcAPDvWgBnJIEj92Q3pXX4JtoitL0yl+SvvU+vUh966mzHShHzj8p5
+ccOgPkPNoA70yrpGzkIhPezpZOQdCaOXj/jFqNCTDg==
+-----END EC PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_bench_SUITE_data/ssh_host_ecdsa_key521.pub b/lib/ssh/test/ssh_bench_SUITE_data/ssh_host_ecdsa_key521.pub
new file mode 100644
index 0000000000..017a29f4da
--- /dev/null
+++ b/lib/ssh/test/ssh_bench_SUITE_data/ssh_host_ecdsa_key521.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAAlWVjqBzg7Wt4gE6UNb1lRE2cnlmH2L/A5uo6qZRx5lPnSKOxEhxSb/Oay1+9d6KRdrh6/vlhd9SHDBhLcAPDvWgBnJIEj92Q3pXX4JtoitL0yl+SvvU+vUh966mzHShHzj8p5ccOgPkPNoA70yrpGzkIhPezpZOQdCaOXj/jFqNCTDg== uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_bench_SUITE_data/ssh_host_rsa_key b/lib/ssh/test/ssh_bench_SUITE_data/ssh_host_rsa_key
new file mode 100644
index 0000000000..79968bdd7d
--- /dev/null
+++ b/lib/ssh/test/ssh_bench_SUITE_data/ssh_host_rsa_key
@@ -0,0 +1,16 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8semM4q843337
+zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RWRWzjaxSB
+6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4QIDAQAB
+AoGANmvJzJO5hkLuvyDZHKfAnGTtpifcR1wtSa9DjdKUyn8vhKF0mIimnbnYQEmW
+NUUb3gXCZLi9PvkpRSVRrASDOZwcjoU/Kvww163vBUVb2cOZfFhyn6o2Sk88Tt++
+udH3hdjpf9i7jTtUkUe+QYPsia+wgvvrmn4QrahLAH86+kECQQDx5gFeXTME3cnW
+WMpFz3PPumduzjqgqMMWEccX4FtQkMX/gyGa5UC7OHFyh0N/gSWvPbRHa8A6YgIt
+n8DO+fh5AkEAzbqX4DOn8NY6xJIi42q7l/2jIA0RkB6P7YugW5NblhqBZ0XDnpA5
+sMt+rz+K07u9XZtxgh1xi7mNfwY6lEAMqQJBAJBEauCKmRj35Z6OyeQku59SPsnY
++SJEREVvSNw2lH9SOKQQ4wPsYlTGbvKtNVZgAcen91L5MmYfeckYE/fdIZECQQCt
+64zxsTnM1I8iFxj/gP/OYlJBikrKt8udWmjaghzvLMEw+T2DExJyb9ZNeT53+UMB
+m6O+B/4xzU/djvp+0hbhAkAemIt+rA5kTmYlFndhpvzkSSM8a2EXsO4XIPgGWCTT
+tQKS/tTly0ADMjN/TVy11+9d6zcqadNVuHXHGtR4W0GR
+-----END RSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_bench_SUITE_data/ssh_host_rsa_key.pub b/lib/ssh/test/ssh_bench_SUITE_data/ssh_host_rsa_key.pub
new file mode 100644
index 0000000000..75d2025c71
--- /dev/null
+++ b/lib/ssh/test/ssh_bench_SUITE_data/ssh_host_rsa_key.pub
@@ -0,0 +1,5 @@
+---- BEGIN SSH2 PUBLIC KEY ----
+AAAAB3NzaC1yc2EAAAADAQABAAAAgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8
+semM4q843337zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RW
+RWzjaxSB6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4Q==
+---- END SSH2 PUBLIC KEY ----
diff --git a/lib/ssh/test/ssh_bench_dev_null.erl b/lib/ssh/test/ssh_bench_dev_null.erl
new file mode 100644
index 0000000000..0e390b7712
--- /dev/null
+++ b/lib/ssh/test/ssh_bench_dev_null.erl
@@ -0,0 +1,58 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+
+%%% Description: Example ssh server
+-module(ssh_bench_dev_null).
+-behaviour(ssh_daemon_channel).
+
+-record(state, {
+ cm,
+ chid,
+ n,
+ sum = 0
+ }).
+
+-export([init/1, handle_msg/2, handle_ssh_msg/2, terminate/2]).
+
+init([N]) -> {ok, #state{n=N}}.
+
+handle_msg({ssh_channel_up, ChId, CM}, S) ->
+ {ok, S#state{cm = CM,
+ chid = ChId}}.
+
+
+
+handle_ssh_msg({ssh_cm, CM, {data,ChId,0,Data}}, #state{n=N, sum=Sum0, cm=CM, chid=ChId} = S) ->
+ Sum = Sum0 + size(Data),
+ if Sum == N ->
+ %% Got all
+ ssh_connection:send(CM, ChId, <<"READY">>),
+ {ok, S#state{sum=Sum}};
+ Sum < N ->
+ %% Expects more
+ {ok, S#state{sum=Sum}}
+ end;
+handle_ssh_msg({ssh_cm, _, {exit_signal,ChId,_,_,_}}, S) -> {stop, ChId, S};
+handle_ssh_msg({ssh_cm, _, {exit_status,ChId,_} }, S) -> {stop, ChId, S};
+handle_ssh_msg({ssh_cm, _, _ }, S) -> {ok, S}.
+
+terminate(_, _) -> ok.
--
cgit v1.2.3
From 445cc27d2af3a45ebcd0afdea5ae0408a5d7c04a Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 16 Mar 2017 19:29:32 +0100
Subject: ssh: disable problematic crypto in ssh_bench_SUITE
---
lib/ssh/test/ssh_bench_SUITE.erl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_bench_SUITE.erl b/lib/ssh/test/ssh_bench_SUITE.erl
index d2ba8afa1a..ac52bb7e28 100644
--- a/lib/ssh/test/ssh_bench_SUITE.erl
+++ b/lib/ssh/test/ssh_bench_SUITE.erl
@@ -145,7 +145,7 @@ transfer_text(Config) ->
|| {Crypto,Mac} <- [{ none, none},
{'aes128-ctr', 'hmac-sha1'},
{'aes256-ctr', 'hmac-sha1'},
- {'aes128-gcm@openssh.com', 'hmac-sha1'},
+%% {'aes128-gcm@openssh.com', 'hmac-sha1'},
{'aes128-cbc', 'hmac-sha1'},
{'3des-cbc', 'hmac-sha1'},
{'aes128-ctr', 'hmac-sha2-256'},
--
cgit v1.2.3
From 7f5d5119d59e1741aac6b622880dbc2f08b394de Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 24 Mar 2017 16:02:15 +0100
Subject: ssh: fixed crash in ssh:daemon_info
---
lib/ssh/src/ssh.erl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 1f3f77a4e4..290525cec0 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -175,7 +175,7 @@ daemon_info(Pid) ->
case catch ssh_system_sup:acceptor_supervisor(Pid) of
AsupPid when is_pid(AsupPid) ->
[Port] =
- [Prt || {{ssh_acceptor_sup,any,Prt,default},
+ [Prt || {{ssh_acceptor_sup,_,Prt,_},
_WorkerPid,worker,[ssh_acceptor]} <- supervisor:which_children(AsupPid)],
{ok, [{port,Port}]};
--
cgit v1.2.3
From 71f7e9155c4867f4e8036704337c21127f508dfb Mon Sep 17 00:00:00 2001
From: Erlang/OTP
Date: Fri, 31 Mar 2017 12:58:36 +0200
Subject: Update version numbers
---
lib/ssh/vsn.mk | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index 96c83cb0f7..48332d2e5a 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,5 +1,5 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 4.4.1
+SSH_VSN = 4.4.2
APP_VSN = "ssh-$(SSH_VSN)"
--
cgit v1.2.3
From 19427107ca9305a931dcaea8c2134017aa385fbd Mon Sep 17 00:00:00 2001
From: Erlang/OTP
Date: Fri, 31 Mar 2017 12:59:07 +0200
Subject: Update release notes
---
lib/ssh/doc/src/notes.xml | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index 02a39f030c..c8c6e61cc8 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -30,6 +30,22 @@
notes.xml
+Ssh 4.4.2
+
+ Fixed Bugs and Malfunctions
+
+ -
+
+ ssh:daemon_info/1 crashed if the listening IP was not
+ 'any'
+
+ Own Id: OTP-14298 Aux Id: seq13294
+
+
+
+
+
+
Ssh 4.4.1
Fixed Bugs and Malfunctions
--
cgit v1.2.3
From bcbf77633dbd145e01d657ba8626c34f838f0727 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 30 Mar 2017 17:16:59 +0200
Subject: ssh: idle_timer on daemon - test case
---
lib/ssh/test/ssh_basic_SUITE.erl | 31 +++++++++++++++++++++++++++----
1 file changed, 27 insertions(+), 4 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index cdf6cf9ae1..a9b6be222e 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -46,7 +46,8 @@
exec_key_differs2/1,
exec_key_differs3/1,
exec_key_differs_fail/1,
- idle_time/1,
+ idle_time_client/1,
+ idle_time_server/1,
inet6_option/1,
inet_option/1,
internal_error/1,
@@ -139,7 +140,7 @@ basic_tests() ->
exec, exec_compressed,
shell, shell_no_unicode, shell_unicode_string,
cli, known_hosts,
- idle_time, openssh_zlib_basic_test,
+ idle_time_client, idle_time_server, openssh_zlib_basic_test,
misc_ssh_options, inet_option, inet6_option].
@@ -522,8 +523,8 @@ exec_compressed(Config) when is_list(Config) ->
end.
%%--------------------------------------------------------------------
-%%% Idle timeout test
-idle_time(Config) ->
+%%% Idle timeout test, client
+idle_time_client(Config) ->
SystemDir = filename:join(proplists:get_value(priv_dir, Config), system),
UserDir = proplists:get_value(priv_dir, Config),
@@ -543,6 +544,28 @@ idle_time(Config) ->
end,
ssh:stop_daemon(Pid).
+%%--------------------------------------------------------------------
+%%% Idle timeout test, server
+idle_time_server(Config) ->
+ SystemDir = filename:join(proplists:get_value(priv_dir, Config), system),
+ UserDir = proplists:get_value(priv_dir, Config),
+
+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ {user_dir, UserDir},
+ {idle_time, 2000},
+ {failfun, fun ssh_test_lib:failfun/2}]),
+ ConnectionRef =
+ ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
+ {user_dir, UserDir},
+ {user_interaction, false}]),
+ {ok, Id} = ssh_connection:session_channel(ConnectionRef, 1000),
+ ssh_connection:close(ConnectionRef, Id),
+ receive
+ after 10000 ->
+ {error, closed} = ssh_connection:session_channel(ConnectionRef, 1000)
+ end,
+ ssh:stop_daemon(Pid).
+
%%--------------------------------------------------------------------
%%% Test that ssh:shell/2 works
shell(Config) when is_list(Config) ->
--
cgit v1.2.3
From 31e9b9c4d3ace33b03eec13d2d0ed22de7a865ab Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 30 Mar 2017 17:17:16 +0200
Subject: ssh: idle_timer on daemon - documentation
---
lib/ssh/doc/src/ssh.xml | 6 ++++++
1 file changed, 6 insertions(+)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index 968983c862..88d402cf38 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -699,6 +699,12 @@
Peer is in the format of {Host,Port}.
+
+ -
+
Sets a time-out on a connection when no channels are active.
+ Defaults to infinity.
+
+
_}]]>
-
Provide a fun to implement your own logging of the SSH message SSH_MSG_DEBUG. The last three parameters are from the message, see RFC4253, section 11.3. The ConnectionRef is the reference to the connection on which the message arrived. The return value from the fun is not checked.
--
cgit v1.2.3
From 1cc5affef1dee69e5cb4b7d4aca0465e1072d4d9 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 30 Mar 2017 17:17:34 +0200
Subject: ssh: idle_timer on daemon - implementation
---
lib/ssh/src/ssh_connection_handler.erl | 8 +++++++-
lib/ssh/src/ssh_options.erl | 12 ++++++------
2 files changed, 13 insertions(+), 7 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index b9c643c77e..15a05a1b85 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -400,7 +400,9 @@ init_process_state(Role, Socket, Opts) ->
timer:apply_after(?REKEY_DATA_TIMOUT, gen_statem, cast, [self(), data_size]),
cache_init_idle_timer(D);
server ->
- D#data{connection_state = init_connection(Role, C, Opts)}
+ cache_init_idle_timer(
+ D#data{connection_state = init_connection(Role, C, Opts)}
+ )
end.
@@ -919,6 +921,9 @@ handle_event(internal, Msg=#ssh_msg_channel_extended_data{}, StateName, D) -
handle_event(internal, Msg=#ssh_msg_channel_eof{}, StateName, D) ->
handle_connection_msg(Msg, StateName, D);
+handle_event(internal, Msg=#ssh_msg_channel_close{}, {connected,server} = StateName, D) ->
+ handle_connection_msg(Msg, StateName, cache_request_idle_timer_check(D));
+
handle_event(internal, Msg=#ssh_msg_channel_close{}, StateName, D) ->
handle_connection_msg(Msg, StateName, D);
@@ -1280,6 +1285,7 @@ handle_event(info, {'EXIT', _Sup, Reason}, _, _) ->
{stop, {shutdown, Reason}};
handle_event(info, check_cache, _, D) ->
+ct:pal("check_cache",[]),
{keep_state, cache_check_set_idle_timer(D)};
handle_event(info, UnexpectedMessage, StateName, D = #data{ssh_params = Ssh}) ->
diff --git a/lib/ssh/src/ssh_options.erl b/lib/ssh/src/ssh_options.erl
index a882a01eaf..55f9c6bdc8 100644
--- a/lib/ssh/src/ssh_options.erl
+++ b/lib/ssh/src/ssh_options.erl
@@ -490,12 +490,6 @@ default(client) ->
class => user_options
},
- {idle_time, def} =>
- #{default => infinity,
- chk => fun check_timeout/1,
- class => user_options
- },
-
%%%%% Undocumented
{keyboard_interact_fun, def} =>
#{default => undefined,
@@ -548,6 +542,12 @@ default(common) ->
class => user_options
},
+ {idle_time, def} =>
+ #{default => infinity,
+ chk => fun check_timeout/1,
+ class => user_options
+ },
+
%% This is a "SocketOption"...
%% {fd, def} =>
%% #{default => undefined,
--
cgit v1.2.3
From 9d174dd62112ec5129b66ffafc1d99650f037d54 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 6 Apr 2017 15:50:38 +0200
Subject: ssh: remove log printout
---
lib/ssh/src/ssh_connection_handler.erl | 1 -
1 file changed, 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 15a05a1b85..5a13209ae3 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -1285,7 +1285,6 @@ handle_event(info, {'EXIT', _Sup, Reason}, _, _) ->
{stop, {shutdown, Reason}};
handle_event(info, check_cache, _, D) ->
-ct:pal("check_cache",[]),
{keep_state, cache_check_set_idle_timer(D)};
handle_event(info, UnexpectedMessage, StateName, D = #data{ssh_params = Ssh}) ->
--
cgit v1.2.3
From 57c1794af74ce0155d8282c4e9d0e47a5b0fb5e3 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Tue, 4 Apr 2017 19:30:18 +0200
Subject: ssh: DSA was not retired
It was erroneously stated in 2e25e7890af04d9001fa777d848ebce6d059edf2 that it was retired
---
lib/ssh/doc/src/ssh_app.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/ssh_app.xml b/lib/ssh/doc/src/ssh_app.xml
index 5f710decc1..f07c335d3f 100644
--- a/lib/ssh/doc/src/ssh_app.xml
+++ b/lib/ssh/doc/src/ssh_app.xml
@@ -160,7 +160,7 @@
- ecdsa-sha2-nistp384
- ecdsa-sha2-nistp521
- ssh-rsa
- - (ssh-dss, retired: can be enabled with the preferred_algorithms option)
+ - ssh-dss
--
cgit v1.2.3
From 5bc3907ae599d57af0d6b58278c8708b620f3108 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Tue, 4 Apr 2017 19:31:11 +0200
Subject: ssh: ECDSA host keys *are* supported
---
lib/ssh/doc/src/ssh_app.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/ssh_app.xml b/lib/ssh/doc/src/ssh_app.xml
index f07c335d3f..515b0639d5 100644
--- a/lib/ssh/doc/src/ssh_app.xml
+++ b/lib/ssh/doc/src/ssh_app.xml
@@ -109,7 +109,7 @@
Host Keys
- RSA and DSA host keys are supported and are
+
RSA, DSA and ECDSA host keys are supported and are
expected to be found in files named ssh_host_rsa_key,
ssh_host_dsa_key and ssh_host_ecdsa_key.
--
cgit v1.2.3
From 7b21b7b5fa0b6da173080bc8322e99eead905191 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 10 Mar 2017 12:56:33 +0100
Subject: ssh: Bug fix when calling ssh_io:yes_no This was introduced by the
new option handling in commit 89a829f32d855610b0bc0c3ea53e7c05454b7a24
---
lib/ssh/src/ssh_transport.erl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 02c995399a..5d896e02a2 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -201,7 +201,7 @@ is_valid_mac(Mac, Data, #ssh{recv_mac = Algorithm,
Mac == mac(Algorithm, Key, SeqNum, Data).
yes_no(Ssh, Prompt) ->
- (Ssh#ssh.io_cb):yes_no(Prompt, Ssh).
+ (Ssh#ssh.io_cb):yes_no(Prompt, Ssh#ssh.opts).
format_version({Major,Minor}, SoftwareVersion) ->
"SSH-" ++ integer_to_list(Major) ++ "." ++
--
cgit v1.2.3
From 7925b59450dd6f34b756da7b10dd10af95304d94 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Tue, 28 Feb 2017 12:19:37 +0100
Subject: ssh: Option pruning
---
lib/ssh/src/ssh.erl | 3 +--
lib/ssh/src/ssh_acceptor.erl | 1 -
lib/ssh/src/ssh_system_sup.erl | 2 +-
3 files changed, 2 insertions(+), 4 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 369a00ac40..c1be9f732d 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -368,8 +368,7 @@ do_start_daemon(Socket, Options) ->
_:_ -> throw(bad_socket)
end,
Host = fmt_host(IP),
- Opts = ?PUT_INTERNAL_OPT([{asocket, Socket},
- {asock_owner,self()},
+ Opts = ?PUT_INTERNAL_OPT([{connected_socket, Socket},
{address, Host},
{port, Port},
{role, server}], Options),
diff --git a/lib/ssh/src/ssh_acceptor.erl b/lib/ssh/src/ssh_acceptor.erl
index 42be18f2ad..4943f062b4 100644
--- a/lib/ssh/src/ssh_acceptor.erl
+++ b/lib/ssh/src/ssh_acceptor.erl
@@ -66,7 +66,6 @@ acceptor_init(Parent, Port, Address, Opts, AcceptTimeout) ->
of
{ok, ListenSocket} ->
proc_lib:init_ack(Parent, {ok, self()}),
- {_, Callback, _} = ?GET_OPT(transport, Opts),
acceptor_loop(Callback,
Port, Address, Opts, ListenSocket, AcceptTimeout);
{error,Error} ->
diff --git a/lib/ssh/src/ssh_system_sup.erl b/lib/ssh/src/ssh_system_sup.erl
index b0bbd3aae5..5a58ef1c44 100644
--- a/lib/ssh/src/ssh_system_sup.erl
+++ b/lib/ssh/src/ssh_system_sup.erl
@@ -131,7 +131,7 @@ init([Options]) ->
RestartStrategy = one_for_one,
MaxR = 0,
MaxT = 3600,
- Children = case ?GET_INTERNAL_OPT(asocket,Options,undefined) of
+ Children = case ?GET_INTERNAL_OPT(connected_socket,Options,undefined) of
undefined -> child_specs(Options);
_ -> []
end,
--
cgit v1.2.3
From ccef9f6e379a2cee828a9b914a49a4ebc831f936 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 2 Mar 2017 20:02:50 +0100
Subject: ssh: Make an internal option delete function
---
lib/ssh/src/ssh.hrl | 4 ++++
lib/ssh/src/ssh_options.erl | 16 ++++++++++++++--
2 files changed, 18 insertions(+), 2 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh.hrl b/lib/ssh/src/ssh.hrl
index c1ba58ed40..63eeb0bd0a 100644
--- a/lib/ssh/src/ssh.hrl
+++ b/lib/ssh/src/ssh.hrl
@@ -89,6 +89,10 @@
-define(PUT_INTERNAL_OPT(KeyVal,Opts), ?do_put_opt(internal_options,KeyVal,Opts) ).
-define(PUT_SOCKET_OPT(KeyVal,Opts), ?do_put_opt(socket_options, KeyVal,Opts) ).
+-define(do_del_opt(C,K,O), ssh_options:delete_key(C,K,O, ?MODULE,?LINE)).
+-define(DELETE_INTERNAL_OPT(Key,Opts), ?do_del_opt(internal_options,Key,Opts) ).
+
+
%% Types
-type role() :: client | server .
-type ok_error(SuccessType) :: {ok, SuccessType} | {error, any()} .
diff --git a/lib/ssh/src/ssh_options.erl b/lib/ssh/src/ssh_options.erl
index 55f9c6bdc8..512aefa76d 100644
--- a/lib/ssh/src/ssh_options.erl
+++ b/lib/ssh/src/ssh_options.erl
@@ -28,6 +28,7 @@
-export([default/1,
get_value/5, get_value/6,
put_value/5,
+ delete_key/5,
handle_options/2
]).
@@ -75,7 +76,6 @@ get_value(Class, Key, Opts, _CallerMod, _CallerLine) when is_map(Opts) ->
user_options -> maps:get(Key, Opts)
end;
get_value(Class, Key, Opts, _CallerMod, _CallerLine) ->
- io:format("*** Bad Opts GET OPT ~p ~p:~p Key=~p,~n Opts=~p~n",[Class,_CallerMod,_CallerLine,Key,Opts]),
error({bad_options,Class, Key, Opts, _CallerMod, _CallerLine}).
@@ -90,7 +90,6 @@ get_value(Class, Key, Opts, Def, CallerMod, CallerLine) when is_map(Opts) ->
error:{badkey,Key} -> Def
end;
get_value(Class, Key, Opts, _Def, _CallerMod, _CallerLine) ->
- io:format("*** Bad Opts GET OPT ~p ~p:~p Key=~p,~n Opts=~p~n",[Class,_CallerMod,_CallerLine,Key,Opts]),
error({bad_options,Class, Key, Opts, _CallerMod, _CallerLine}).
@@ -134,6 +133,19 @@ put_socket_value({Key,Value}, SockOpts) ->
put_socket_value(A, SockOpts) when is_atom(A) ->
[A | SockOpts].
+%%%================================================================
+%%%
+%%% Delete an option
+%%%
+
+-spec delete_key(option_class(), option_key(), options(),
+ atom(), non_neg_integer()) -> options().
+
+delete_key(internal_options, Key, Opts, _CallerMod, _CallerLine) when is_map(Opts) ->
+ InternalOpts = maps:get(internal_options,Opts),
+ Opts#{internal_options := maps:remove(Key, InternalOpts)}.
+
+
%%%================================================================
%%%
%%% Initialize the options
--
cgit v1.2.3
From 2f212c1a3e8bc3070b51dfc5607f30e501ba24ea Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 10 Mar 2017 13:08:08 +0100
Subject: ssh: option 'silently_accept_hosts' reworked New (yet) undocumented
option value {false,Alg} where Alg :: md5 | sha | sha224 | sha256 | sha384 |
sha512 This option includes the fingerprint value in the accept question to
the user. The fingerprint is calculated with the Alg provided
---
lib/ssh/src/ssh_options.erl | 21 ++++++++++-----------
lib/ssh/src/ssh_transport.erl | 43 ++++++++++++++++++++++++++++++++++---------
2 files changed, 44 insertions(+), 20 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_options.erl b/lib/ssh/src/ssh_options.erl
index 512aefa76d..6a2e7ce696 100644
--- a/lib/ssh/src/ssh_options.erl
+++ b/lib/ssh/src/ssh_options.erl
@@ -431,7 +431,7 @@ default(client) ->
},
{silently_accept_hosts, def} =>
- #{default => false,
+ #{default => {false,none},
chk => fun check_silently_accept_hosts/1,
class => user_options
},
@@ -804,18 +804,17 @@ read_moduli_file(D, I, Acc) ->
check_silently_accept_hosts(B) when is_boolean(B) -> true;
check_silently_accept_hosts(F) when is_function(F,2) -> true;
-check_silently_accept_hosts({S,F}) when is_atom(S),
- is_function(F,2) ->
- lists:member(S, ?SHAs) andalso
- lists:member(S, proplists:get_value(hashs,crypto:supports()));
-check_silently_accept_hosts({L,F}) when is_list(L),
- is_function(F,2) ->
- lists:all(fun(S) ->
- lists:member(S, ?SHAs) andalso
- lists:member(S, proplists:get_value(hashs,crypto:supports()))
- end, L);
+check_silently_accept_hosts({false,S}) when is_atom(S) -> valid_hash(S);
+check_silently_accept_hosts({S,F}) when is_function(F,2) -> valid_hash(S);
check_silently_accept_hosts(_) -> false.
+
+valid_hash(S) -> valid_hash(S, proplists:get_value(hashs,crypto:supports())).
+
+valid_hash(S, Ss) when is_atom(S) -> lists:member(S, ?SHAs) andalso lists:member(S, Ss);
+valid_hash(L, Ss) when is_list(L) -> lists:all(fun(S) -> valid_hash(S,Ss) end, L);
+valid_hash(X, _) -> error_in_check(X, "Expect atom or list in fingerprint spec").
+
%%%----------------------------------------------------------------
check_preferred_algorithms(Algs) ->
try alg_duplicates(Algs, [], [])
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 5d896e02a2..54ea80c727 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -200,9 +200,6 @@ is_valid_mac(Mac, Data, #ssh{recv_mac = Algorithm,
recv_mac_key = Key, recv_sequence = SeqNum}) ->
Mac == mac(Algorithm, Key, SeqNum, Data).
-yes_no(Ssh, Prompt) ->
- (Ssh#ssh.io_cb):yes_no(Prompt, Ssh#ssh.opts).
-
format_version({Major,Minor}, SoftwareVersion) ->
"SSH-" ++ integer_to_list(Major) ++ "." ++
integer_to_list(Minor) ++ "-" ++ SoftwareVersion.
@@ -755,16 +752,44 @@ public_algo({#'ECPoint'{},{namedCurve,OID}}) ->
accepted_host(Ssh, PeerName, Public, Opts) ->
case ?GET_OPT(silently_accept_hosts, Opts) of
- F when is_function(F,2) ->
+
+ %% Original option values; User question and no host key fingerprints known.
+ %% Keep the original question unchanged:
+ false -> yes == yes_no(Ssh, "New host " ++ PeerName ++ " accept");
+ true -> true;
+
+ %% Variant: User question but with host key fingerprint in the question:
+ {false,Alg} ->
+ HostKeyAlg = (Ssh#ssh.algorithms)#alg.hkey,
+ Prompt = io_lib:format("The authenticity of the host can't be established.~n"
+ "~s host key fingerprint is ~s.~n"
+ "New host ~p accept",
+ [fmt_hostkey(HostKeyAlg),
+ public_key:ssh_hostkey_fingerprint(Alg,Public),
+ PeerName]),
+ yes == yes_no(Ssh, Prompt);
+
+ %% Call-back alternatives: A user provided fun is called for the decision:
+ F when is_function(F,2) ->
true == (catch F(PeerName, public_key:ssh_hostkey_fingerprint(Public)));
+
{DigestAlg,F} when is_function(F,2) ->
- true == (catch F(PeerName, public_key:ssh_hostkey_fingerprint(DigestAlg,Public)));
- true ->
- true;
- false ->
- yes == yes_no(Ssh, "New host " ++ PeerName ++ " accept")
+ true == (catch F(PeerName, public_key:ssh_hostkey_fingerprint(DigestAlg,Public)))
+
end.
+
+yes_no(Ssh, Prompt) ->
+ (Ssh#ssh.io_cb):yes_no(Prompt, Ssh#ssh.opts).
+
+
+fmt_hostkey('ssh-rsa') -> "RSA";
+fmt_hostkey('ssh-dss') -> "DSA";
+fmt_hostkey(A) when is_atom(A) -> fmt_hostkey(atom_to_list(A));
+fmt_hostkey("ecdsa"++_) -> "ECDSA";
+fmt_hostkey(X) -> X.
+
+
known_host_key(#ssh{opts = Opts, key_cb = {KeyCb,KeyCbOpts}, peer = {PeerName,_}} = Ssh,
Public, Alg) ->
UserOpts = ?GET_OPT(user_options, Opts),
--
cgit v1.2.3
From 6ff33b1548a24d9f195c27a1ee5bcfcdb1b892d8 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 16 Mar 2017 14:42:30 +0100
Subject: ssh: enable 'none' as a secret accepted value in negotiation
This is for testing only to disable e.g. encryption/decryption is measurements. The value must be explicitly enabled like {preferred_algorithms,[{cipher,[none]}]}
---
lib/ssh/src/ssh_options.erl | 1 +
1 file changed, 1 insertion(+)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_options.erl b/lib/ssh/src/ssh_options.erl
index 6a2e7ce696..cb3f63103c 100644
--- a/lib/ssh/src/ssh_options.erl
+++ b/lib/ssh/src/ssh_options.erl
@@ -882,6 +882,7 @@ handle_pref_alg(Key, Vs, _) ->
chk_alg_vs(OptKey, Values, SupportedValues) ->
case (Values -- SupportedValues) of
[] -> Values;
+ [none] -> [none]; % for testing only
Bad -> error_in_check({OptKey,Bad}, "Unsupported value(s) found")
end.
--
cgit v1.2.3
From da7902412f1e77b8241c0bacbeac2d6013e8f345 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 2 Mar 2017 16:37:54 +0100
Subject: ssh: Unified way of starting listening sockets
---
lib/ssh/src/ssh.erl | 215 ++++++++++++++++++-------------------------
lib/ssh/src/ssh_acceptor.erl | 106 ++++++++++-----------
2 files changed, 136 insertions(+), 185 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index c1be9f732d..c139556791 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -132,13 +132,12 @@ connect(Host, Port, UserOptions, Timeout) when is_integer(Port),
SocketOpts = [{active,false} | ?GET_OPT(socket_options,Options)],
try Transport:connect(Host, Port, SocketOpts, ConnectionTimeout) of
{ok, Socket} ->
- Opts = ?PUT_INTERNAL_OPT([{user_pid,self()}, {host,Host}], Options),
+ Opts = ?PUT_INTERNAL_OPT([{user_pid,self()}, {host,fmt_host(Host)}], Options),
ssh_connection_handler:start_connection(client, Socket, Opts, Timeout);
{error, Reason} ->
{error, Reason}
catch
exit:{function_clause, _F} ->
- io:format('function_clause ~p~n',[_F]),
{error, {options, {transport, TransportOpts}}};
exit:badarg ->
{error, {options, {socket_options, SocketOpts}}}
@@ -311,16 +310,15 @@ handle_daemon_args(Host, UserOptions0) ->
%%%----------------------------------------------------------------
valid_socket_to_use(Socket, {tcp,_,_}) ->
%% Is this tcp-socket a valid socket?
- case {is_tcp_socket(Socket),
- {ok,[{active,false}]} == inet:getopts(Socket, [active])
- }
+ try {is_tcp_socket(Socket),
+ {ok,[{active,false}]} == inet:getopts(Socket, [active])
+ }
of
- {true, true} ->
- ok;
- {true, false} ->
- {error, not_passive_mode};
- _ ->
- {error, not_tcp_socket}
+ {true, true} -> ok;
+ {true, false} -> {error, not_passive_mode};
+ _ -> {error, not_tcp_socket}
+ catch
+ _:_ -> {error, bad_socket}
end;
valid_socket_to_use(_, {L4,_,_}) ->
@@ -340,13 +338,7 @@ start_daemon(_, _, {error,Error}) ->
start_daemon(socket, Socket, Options) ->
case valid_socket_to_use(Socket, ?GET_OPT(transport,Options)) of
ok ->
- try
- do_start_daemon(Socket, Options)
- catch
- throw:bad_fd -> {error,bad_fd};
- throw:bad_socket -> {error,bad_socket};
- _C:_E -> {error,{cannot_start_daemon,_C,_E}}
- end;
+ start_daemon(inet:sockname(Socket), Socket, Options);
{error,SockError} ->
{error,SockError}
end;
@@ -355,136 +347,107 @@ start_daemon(Host, Port, Options) ->
try
do_start_daemon(Host, Port, Options)
catch
- throw:bad_fd -> {error,bad_fd};
- throw:bad_socket -> {error,bad_socket};
- _C:_E -> {error,{cannot_start_daemon,_C,_E}}
+ throw:bad_fd ->
+ {error,bad_fd};
+ throw:bad_socket ->
+ {error,bad_socket};
+ error:{badmatch,{error,Error}} ->
+ {error,Error};
+ _C:_E ->
+ {error,{cannot_start_daemon,_C,_E}}
end.
+%%%----------------------------------------------------------------
+do_start_daemon({error,Error}, _, _) ->
+ {error,Error};
-do_start_daemon(Socket, Options) ->
- {ok, {IP,Port}} =
- try {ok,_} = inet:sockname(Socket)
- catch
- _:_ -> throw(bad_socket)
- end,
- Host = fmt_host(IP),
- Opts = ?PUT_INTERNAL_OPT([{connected_socket, Socket},
- {address, Host},
- {port, Port},
- {role, server}], Options),
-
- Profile = ?GET_OPT(profile, Options),
- case ssh_system_sup:system_supervisor(Host, Port, Profile) of
- undefined ->
- try sshd_sup:start_child(Opts) of
- {error, {already_started, _}} ->
- {error, eaddrinuse};
- Result = {ok,_} ->
- call_ssh_acceptor_handle_connection(Host, Port, Opts, Socket, Result);
- Result = {error, _} ->
- Result
- catch
- exit:{noproc, _} ->
- {error, ssh_not_started}
- end;
- Sup ->
- AccPid = ssh_system_sup:acceptor_supervisor(Sup),
- case ssh_acceptor_sup:start_child(AccPid, Opts) of
- {error, {already_started, _}} ->
- {error, eaddrinuse};
- {ok, _} ->
- call_ssh_acceptor_handle_connection(Host, Port, Opts, Socket, {ok,Sup});
- Other ->
- Other
- end
- end.
+do_start_daemon({ok, {IP,Port}}, Socket, Options0) ->
+ finalize_start(fmt_host(IP),
+ Port,
+ ?PUT_INTERNAL_OPT({connected_socket, Socket}, Options0),
+ fun(Opts, DefaultResult) ->
+ try ssh_acceptor:handle_established_connection(
+ ?GET_INTERNAL_OPT(address, Opts),
+ ?GET_INTERNAL_OPT(port, Opts),
+ Opts,
+ Socket)
+ of
+ {error,Error} ->
+ {error,Error};
+ _ ->
+ DefaultResult
+ catch
+ C:R ->
+ {error,{could_not_start_connection,{C,R}}}
+ end
+ end);
do_start_daemon(Host0, Port0, Options0) ->
- {Host,Port1} =
- try
- case ?GET_SOCKET_OPT(fd, Options0) of
- undefined ->
- {Host0,Port0};
- Fd when Port0==0 ->
- find_hostport(Fd)
- end
- catch
- _:_ -> throw(bad_fd)
- end,
- {Port, WaitRequestControl, Options1} =
- case Port1 of
- 0 -> %% Allocate the socket here to get the port number...
- {ok,LSock} = ssh_acceptor:callback_listen(0, Options0),
- {ok,{_,LPort}} = inet:sockname(LSock),
- {LPort,
- LSock,
- ?PUT_INTERNAL_OPT({lsocket,{LSock,self()}}, Options0)
- };
- _ ->
- {Port1, false, Options0}
- end,
+ {{Host,Port}, ListenSocket} =
+ open_listen_socket(Host0, Port0, Options0),
+
+ %% Now Host,Port is what to use for the supervisor to register its name,
+ %% and ListenSocket is for listening on connections. But it is still owned
+ %% by self()...
+
+ finalize_start(Host, Port,
+ ?PUT_INTERNAL_OPT({lsocket,{ListenSocket,self()}}, Options0),
+ fun(Opts, Result) ->
+ {_, Callback, _} = ?GET_OPT(transport, Opts),
+ receive
+ {request_control, ListenSocket, ReqPid} ->
+ ok = Callback:controlling_process(ListenSocket, ReqPid),
+ ReqPid ! {its_yours,ListenSocket},
+ Result
+ end
+ end).
+
+
+open_listen_socket(Host0, Port0, Options0) ->
+ case ?GET_SOCKET_OPT(fd, Options0) of
+ undefined ->
+ {ok,LSock} = ssh_acceptor:listen(Port0, Options0),
+ {ok,{_,LPort}} = inet:sockname(LSock),
+ {{fmt_host(Host0),LPort}, LSock};
+
+ Fd when is_integer(Fd) ->
+ %% Do gen_tcp:listen with the option {fd,Fd}:
+ {ok,LSock} = ssh_acceptor:listen(0, Options0),
+ {ok,{LHost,LPort}} = inet:sockname(LSock),
+ {{fmt_host(LHost),LPort}, LSock}
+ end.
+
+%%%----------------------------------------------------------------
+finalize_start(Host, Port, Options0, F) ->
Options = ?PUT_INTERNAL_OPT([{address, Host},
{port, Port},
- {role, server}], Options1),
- Profile = ?GET_OPT(profile, Options0),
+ {role, server}], Options0),
+ Profile = ?GET_OPT(profile, Options),
case ssh_system_sup:system_supervisor(Host, Port, Profile) of
undefined ->
try sshd_sup:start_child(Options) of
{error, {already_started, _}} ->
{error, eaddrinuse};
+ {error, Error} ->
+ {error, Error};
Result = {ok,_} ->
- sync_request_control(WaitRequestControl, Options),
- Result;
- Result = {error, _} ->
- Result
+ F(Options, Result)
catch
exit:{noproc, _} ->
{error, ssh_not_started}
end;
- Sup ->
+ Sup ->
AccPid = ssh_system_sup:acceptor_supervisor(Sup),
case ssh_acceptor_sup:start_child(AccPid, Options) of
{error, {already_started, _}} ->
{error, eaddrinuse};
+ {error, Error} ->
+ {error, Error};
{ok, _} ->
- sync_request_control(WaitRequestControl, Options),
- {ok, Sup};
- Other ->
- Other
+ F(Options, {ok,Sup})
end
end.
-call_ssh_acceptor_handle_connection(Host, Port, Options, Socket, DefaultResult) ->
- {_, Callback, _} = ?GET_OPT(transport, Options),
- try ssh_acceptor:handle_connection(Callback, Host, Port, Options, Socket)
- of
- {error,Error} -> {error,Error};
- _ -> DefaultResult
- catch
- C:R -> {error,{could_not_start_connection,{C,R}}}
- end.
-
-
-sync_request_control(false, _Options) ->
- ok;
-sync_request_control(LSock, Options) ->
- {_, Callback, _} = ?GET_OPT(transport, Options),
- receive
- {request_control,LSock,ReqPid} ->
- ok = Callback:controlling_process(LSock, ReqPid),
- ReqPid ! {its_yours,LSock},
- ok
- end.
-
-find_hostport(Fd) ->
- %% Using internal functions inet:open/8 and inet:close/0.
- %% Don't try this at home unless you know what you are doing!
- {ok,S} = inet:open(Fd, {0,0,0,0}, 0, [], tcp, inet, stream, inet_tcp),
- {ok, HostPort} = inet:sockname(S),
- ok = inet:close(S),
- HostPort.
-
-fmt_host({A,B,C,D}) ->
- lists:concat([A,".",B,".",C,".",D]);
-fmt_host(T={_,_,_,_,_,_,_,_}) ->
- lists:flatten(string:join([io_lib:format("~.16B",[A]) || A <- tuple_to_list(T)], ":")).
+%%%----------------------------------------------------------------
+fmt_host(IP) when is_tuple(IP) -> inet:ntoa(IP);
+fmt_host(Str) when is_list(Str) -> Str.
diff --git a/lib/ssh/src/ssh_acceptor.erl b/lib/ssh/src/ssh_acceptor.erl
index 4943f062b4..f9e2280212 100644
--- a/lib/ssh/src/ssh_acceptor.erl
+++ b/lib/ssh/src/ssh_acceptor.erl
@@ -27,8 +27,8 @@
%% Internal application API
-export([start_link/4,
number_of_connections/1,
- callback_listen/2,
- handle_connection/5]).
+ listen/2,
+ handle_established_connection/4]).
%% spawn export
-export([acceptor_init/5, acceptor_loop/6]).
@@ -42,40 +42,57 @@ start_link(Port, Address, Options, AcceptTimeout) ->
Args = [self(), Port, Address, Options, AcceptTimeout],
proc_lib:start_link(?MODULE, acceptor_init, Args).
+%%%----------------------------------------------------------------
+number_of_connections(SystemSup) ->
+ length([X ||
+ {R,X,supervisor,[ssh_subsystem_sup]} <- supervisor:which_children(SystemSup),
+ is_pid(X),
+ is_reference(R)
+ ]).
+
+%%%----------------------------------------------------------------
+listen(Port, Options) ->
+ {_, Callback, _} = ?GET_OPT(transport, Options),
+ SockOpts = [{active, false}, {reuseaddr,true} | ?GET_OPT(socket_options, Options)],
+ case Callback:listen(Port, SockOpts) of
+ {error, nxdomain} ->
+ Callback:listen(Port, lists:delete(inet6, SockOpts));
+ {error, enetunreach} ->
+ Callback:listen(Port, lists:delete(inet6, SockOpts));
+ {error, eafnosupport} ->
+ Callback:listen(Port, lists:delete(inet6, SockOpts));
+ Other ->
+ Other
+ end.
+
+%%%----------------------------------------------------------------
+handle_established_connection(Address, Port, Options, Socket) ->
+ {_, Callback, _} = ?GET_OPT(transport, Options),
+ handle_connection(Callback, Address, Port, Options, Socket).
+
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
acceptor_init(Parent, Port, Address, Opts, AcceptTimeout) ->
- {_, Callback, _} = ?GET_OPT(transport, Opts),
try
- {LSock0,SockOwner0} = ?GET_INTERNAL_OPT(lsocket, Opts),
- true = is_pid(SockOwner0),
- {ok,{_,Port}} = inet:sockname(LSock0),
- {LSock0, SockOwner0}
+ ?GET_INTERNAL_OPT(lsocket, Opts)
of
{LSock, SockOwner} ->
- %% Use existing socket
- proc_lib:init_ack(Parent, {ok, self()}),
- request_ownership(LSock, SockOwner),
- acceptor_loop(Callback, Port, Address, Opts, LSock, AcceptTimeout)
- catch
- error:{badkey,lsocket} ->
- %% Open new socket
- try
- socket_listen(Port, Opts)
- of
- {ok, ListenSocket} ->
+ case inet:sockname(LSock) of
+ {ok,{_,Port}} -> % A usable, open LSock
proc_lib:init_ack(Parent, {ok, self()}),
- acceptor_loop(Callback,
- Port, Address, Opts, ListenSocket, AcceptTimeout);
- {error,Error} ->
- proc_lib:init_ack(Parent, Error),
- {error,Error}
- catch
- _:_ ->
- {error,listen_socket_failed}
- end;
+ request_ownership(LSock, SockOwner),
+ {_, Callback, _} = ?GET_OPT(transport, Opts),
+ acceptor_loop(Callback, Port, Address, Opts, LSock, AcceptTimeout);
+ {error,_} -> % Not open, a restart
+ {ok,NewLSock} = listen(Port, Opts),
+ proc_lib:init_ack(Parent, {ok, self()}),
+ Opts1 = ?DELETE_INTERNAL_OPT(lsocket, Opts),
+ {_, Callback, _} = ?GET_OPT(transport, Opts1),
+ acceptor_loop(Callback, Port, Address, Opts1, NewLSock, AcceptTimeout)
+ end
+ catch
_:_ ->
{error,use_existing_socket_failed}
end.
@@ -87,30 +104,7 @@ request_ownership(LSock, SockOwner) ->
{its_yours,LSock} -> ok
end.
-
-socket_listen(Port0, Opts) ->
- Port = case ?GET_SOCKET_OPT(fd, Opts) of
- undefined -> Port0;
- _ -> 0
- end,
- callback_listen(Port, Opts).
-
-
-callback_listen(Port, Opts0) ->
- {_, Callback, _} = ?GET_OPT(transport, Opts0),
- Opts = ?PUT_SOCKET_OPT([{active, false}, {reuseaddr,true}], Opts0),
- SockOpts = ?GET_OPT(socket_options, Opts),
- case Callback:listen(Port, SockOpts) of
- {error, nxdomain} ->
- Callback:listen(Port, lists:delete(inet6, SockOpts));
- {error, enetunreach} ->
- Callback:listen(Port, lists:delete(inet6, SockOpts));
- {error, eafnosupport} ->
- Callback:listen(Port, lists:delete(inet6, SockOpts));
- Other ->
- Other
- end.
-
+%%%----------------------------------------------------------------
acceptor_loop(Callback, Port, Address, Opts, ListenSocket, AcceptTimeout) ->
case (catch Callback:accept(ListenSocket, AcceptTimeout)) of
{ok, Socket} ->
@@ -127,6 +121,7 @@ acceptor_loop(Callback, Port, Address, Opts, ListenSocket, AcceptTimeout) ->
ListenSocket, AcceptTimeout)
end.
+%%%----------------------------------------------------------------
handle_connection(Callback, Address, Port, Options, Socket) ->
Profile = ?GET_OPT(profile, Options),
SystemSup = ssh_system_sup:system_supervisor(Address, Port, Profile),
@@ -158,7 +153,7 @@ handle_connection(Callback, Address, Port, Options, Socket) ->
{error,max_sessions}
end.
-
+%%%----------------------------------------------------------------
handle_error(timeout) ->
ok;
@@ -185,10 +180,3 @@ handle_error(Reason) ->
error_logger:error_report(String),
exit({accept_failed, String}).
-
-number_of_connections(SystemSup) ->
- length([X ||
- {R,X,supervisor,[ssh_subsystem_sup]} <- supervisor:which_children(SystemSup),
- is_pid(X),
- is_reference(R)
- ]).
--
cgit v1.2.3
From e20ce5b9174e5ac0e1279a1af5be80f9c1b35caa Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Tue, 21 Mar 2017 15:21:46 +0100
Subject: ssh: handle HostAddr arg and ip-option for daemons
---
lib/ssh/src/ssh.erl | 221 +++++++++++++++++++++++++++++-----------------------
1 file changed, 124 insertions(+), 97 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index c139556791..ff424b738c 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -182,16 +182,86 @@ daemon(Port) ->
daemon(Port, []).
-daemon(Port, UserOptions) when is_integer(Port), Port >= 0 ->
- daemon(any, Port, UserOptions);
-
daemon(Socket, UserOptions) when is_port(Socket) ->
- daemon(socket, Socket, UserOptions).
+ try
+ #{} = Options = ssh_options:handle_options(server, UserOptions),
+ case valid_socket_to_use(Socket, ?GET_OPT(transport,Options)) of
+ ok ->
+ {ok, {IP,Port}} = inet:sockname(Socket),
+ finalize_start(fmt_host(IP), Port, ?GET_OPT(profile, Options),
+ ?PUT_INTERNAL_OPT({connected_socket, Socket}, Options),
+ fun(Opts, DefaultResult) ->
+ try ssh_acceptor:handle_established_connection(
+ ?GET_INTERNAL_OPT(address, Opts),
+ ?GET_INTERNAL_OPT(port, Opts),
+ Opts,
+ Socket)
+ of
+ {error,Error} ->
+ {error,Error};
+ _ ->
+ DefaultResult
+ catch
+ C:R ->
+ {error,{could_not_start_connection,{C,R}}}
+ end
+ end);
+ {error,SockError} ->
+ {error,SockError}
+ end
+ catch
+ throw:bad_fd ->
+ {error,bad_fd};
+ throw:bad_socket ->
+ {error,bad_socket};
+ error:{badmatch,{error,Error}} ->
+ {error,Error};
+ error:Error ->
+ {error,Error};
+ _C:_E ->
+ {error,{cannot_start_daemon,_C,_E}}
+ end;
+
+daemon(Port, UserOptions) when 0 =< Port, Port =< 65535 ->
+ daemon(any, Port, UserOptions).
+
+daemon(Host0, Port0, UserOptions0) when 0 =< Port0, Port0 =< 65535 ->
+ try
+ {Host1, UserOptions} = handle_daemon_args(Host0, UserOptions0),
+ #{} = Options0 = ssh_options:handle_options(server, UserOptions),
+
+ {{Host,Port}, ListenSocket} =
+ open_listen_socket(Host1, Port0, Options0),
+
+ %% Now Host,Port is what to use for the supervisor to register its name,
+ %% and ListenSocket is for listening on connections. But it is still owned
+ %% by self()...
+
+ finalize_start(fmt_host(Host), Port, ?GET_OPT(profile, Options0),
+ ?PUT_INTERNAL_OPT({lsocket,{ListenSocket,self()}}, Options0),
+ fun(Opts, Result) ->
+ {_, Callback, _} = ?GET_OPT(transport, Opts),
+ receive
+ {request_control, ListenSocket, ReqPid} ->
+ ok = Callback:controlling_process(ListenSocket, ReqPid),
+ ReqPid ! {its_yours,ListenSocket},
+ Result
+ end
+ end)
+ catch
+ throw:bad_fd ->
+ {error,bad_fd};
+ throw:bad_socket ->
+ {error,bad_socket};
+ error:{badmatch,{error,Error}} ->
+ {error,Error};
+ error:Error ->
+ {error,Error};
+ _C:_E ->
+ {error,{cannot_start_daemon,_C,_E}}
+ end.
-daemon(Host0, Port, UserOptions0) ->
- {Host, UserOptions} = handle_daemon_args(Host0, UserOptions0),
- start_daemon(Host, Port, ssh_options:handle_options(server, UserOptions)).
%%--------------------------------------------------------------------
-spec daemon_info(daemon_ref()) -> ok_error( [{atom(), term()}] ).
@@ -291,21 +361,49 @@ default_algorithms() ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
-handle_daemon_args(Host, UserOptions0) ->
- case Host of
- socket ->
- {Host, UserOptions0};
- any ->
- {ok, Host0} = inet:gethostname(),
- Inet = proplists:get_value(inet, UserOptions0, inet),
- {Host0, [Inet | UserOptions0]};
- {_,_,_,_} ->
- {Host, [inet, {ip,Host} | UserOptions0]};
- {_,_,_,_,_,_,_,_} ->
- {Host, [inet6, {ip,Host} | UserOptions0]};
- _ ->
- error(badarg)
- end.
+handle_daemon_args(HostAddr, Opts) ->
+ IP = proplists:get_value(ip, Opts),
+ IPh = case inet:parse_strict_address(HostAddr) of
+ {ok, IPtuple} -> IPtuple;
+ {error, einval} when is_tuple(HostAddr),
+ size(HostAddr)==4 ; size(HostAddr)==6 -> HostAddr;
+ _ -> undefined
+ end,
+ handle_daemon_args(HostAddr, IPh, IP, Opts).
+
+
+%% HostAddr is 'any'
+handle_daemon_args(any, undefined, undefined, Opts) -> {any, Opts};
+handle_daemon_args(any, undefined, IP, Opts) -> {IP, Opts};
+
+%% HostAddr is 'loopback' or "localhost"
+handle_daemon_args(loopback, undefined, {127,_,_,_}=IP, Opts) -> {IP, Opts};
+handle_daemon_args(loopback, undefined, {0,0,0,0,0,0,0,1}=IP, Opts) -> {IP, Opts};
+handle_daemon_args(loopback, undefined, undefined, Opts) ->
+ IP = case proplists:get_value(inet,Opts) of
+ true -> {127,0,0,1};
+ inet -> {127,0,0,1};
+ inet6 -> {0,0,0,0,0,0,0,1};
+ _ -> case proplists:get_value(inet6,Opts) of
+ true -> {0,0,0,0,0,0,0,1};
+ _ -> {127,0,0,1} % default if no 'inet' nor 'inet6'
+ end
+ end,
+ {IP, [{ip,IP}|Opts]};
+handle_daemon_args("localhost", IPh, IP, Opts) ->
+ handle_daemon_args(loopback, IPh, IP, Opts);
+
+%% HostAddr is ip and no ip-option
+handle_daemon_args(_, IP, undefined, Opts) when is_tuple(IP) -> {IP, [{ip,IP}|Opts]};
+
+%% HostAddr and ip-option are equal
+handle_daemon_args(_, IP, IP, Opts) when is_tuple(IP) -> {IP, Opts};
+
+%% HostAddr is ip, but ip-option is different!
+handle_daemon_args(_, IPh, IPo, _) when is_tuple(IPh), is_tuple(IPo) -> error({eoption,{ip,IPo}});
+
+%% Something else. Whatever it is, it is wrong.
+handle_daemon_args(_, _, _, _) -> error(badarg).
%%%----------------------------------------------------------------
valid_socket_to_use(Socket, {tcp,_,_}) ->
@@ -332,97 +430,25 @@ is_tcp_socket(Socket) ->
end.
%%%----------------------------------------------------------------
-start_daemon(_, _, {error,Error}) ->
- {error,Error};
-
-start_daemon(socket, Socket, Options) ->
- case valid_socket_to_use(Socket, ?GET_OPT(transport,Options)) of
- ok ->
- start_daemon(inet:sockname(Socket), Socket, Options);
- {error,SockError} ->
- {error,SockError}
- end;
-
-start_daemon(Host, Port, Options) ->
- try
- do_start_daemon(Host, Port, Options)
- catch
- throw:bad_fd ->
- {error,bad_fd};
- throw:bad_socket ->
- {error,bad_socket};
- error:{badmatch,{error,Error}} ->
- {error,Error};
- _C:_E ->
- {error,{cannot_start_daemon,_C,_E}}
- end.
-
-%%%----------------------------------------------------------------
-do_start_daemon({error,Error}, _, _) ->
- {error,Error};
-
-do_start_daemon({ok, {IP,Port}}, Socket, Options0) ->
- finalize_start(fmt_host(IP),
- Port,
- ?PUT_INTERNAL_OPT({connected_socket, Socket}, Options0),
- fun(Opts, DefaultResult) ->
- try ssh_acceptor:handle_established_connection(
- ?GET_INTERNAL_OPT(address, Opts),
- ?GET_INTERNAL_OPT(port, Opts),
- Opts,
- Socket)
- of
- {error,Error} ->
- {error,Error};
- _ ->
- DefaultResult
- catch
- C:R ->
- {error,{could_not_start_connection,{C,R}}}
- end
- end);
-
-do_start_daemon(Host0, Port0, Options0) ->
- {{Host,Port}, ListenSocket} =
- open_listen_socket(Host0, Port0, Options0),
-
- %% Now Host,Port is what to use for the supervisor to register its name,
- %% and ListenSocket is for listening on connections. But it is still owned
- %% by self()...
-
- finalize_start(Host, Port,
- ?PUT_INTERNAL_OPT({lsocket,{ListenSocket,self()}}, Options0),
- fun(Opts, Result) ->
- {_, Callback, _} = ?GET_OPT(transport, Opts),
- receive
- {request_control, ListenSocket, ReqPid} ->
- ok = Callback:controlling_process(ListenSocket, ReqPid),
- ReqPid ! {its_yours,ListenSocket},
- Result
- end
- end).
-
-
open_listen_socket(Host0, Port0, Options0) ->
case ?GET_SOCKET_OPT(fd, Options0) of
undefined ->
{ok,LSock} = ssh_acceptor:listen(Port0, Options0),
{ok,{_,LPort}} = inet:sockname(LSock),
- {{fmt_host(Host0),LPort}, LSock};
+ {{Host0,LPort}, LSock};
Fd when is_integer(Fd) ->
%% Do gen_tcp:listen with the option {fd,Fd}:
{ok,LSock} = ssh_acceptor:listen(0, Options0),
{ok,{LHost,LPort}} = inet:sockname(LSock),
- {{fmt_host(LHost),LPort}, LSock}
+ {{LHost,LPort}, LSock}
end.
%%%----------------------------------------------------------------
-finalize_start(Host, Port, Options0, F) ->
+finalize_start(Host, Port, Profile, Options0, F) ->
Options = ?PUT_INTERNAL_OPT([{address, Host},
{port, Port},
{role, server}], Options0),
- Profile = ?GET_OPT(profile, Options),
case ssh_system_sup:system_supervisor(Host, Port, Profile) of
undefined ->
try sshd_sup:start_child(Options) of
@@ -449,5 +475,6 @@ finalize_start(Host, Port, Options0, F) ->
end.
%%%----------------------------------------------------------------
+fmt_host(any) -> any;
fmt_host(IP) when is_tuple(IP) -> inet:ntoa(IP);
fmt_host(Str) when is_list(Str) -> Str.
--
cgit v1.2.3
From a005cc758490a1fa04119e747534eddbd76c4223 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 6 Mar 2017 16:24:51 +0100
Subject: ssh: killed_acceptor_restarts test case
---
lib/ssh/test/ssh_sup_SUITE.erl | 106 +++++++++++++++++++++++++++++++++++++++--
1 file changed, 103 insertions(+), 3 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_sup_SUITE.erl b/lib/ssh/test/ssh_sup_SUITE.erl
index ff53e1c4c6..3f08ec4b38 100644
--- a/lib/ssh/test/ssh_sup_SUITE.erl
+++ b/lib/ssh/test/ssh_sup_SUITE.erl
@@ -41,7 +41,8 @@ suite() ->
{timetrap,{seconds,100}}].
all() ->
- [default_tree, sshc_subtree, sshd_subtree, sshd_subtree_profile].
+ [default_tree, sshc_subtree, sshd_subtree, sshd_subtree_profile,
+ killed_acceptor_restarts].
groups() ->
[].
@@ -172,7 +173,7 @@ sshd_subtree_profile(Config) when is_list(Config) ->
ct:sleep(?WAIT_FOR_SHUTDOWN),
?wait_match([], supervisor:which_children(sshd_sup)).
-
+%%-------------------------------------------------------------------------
check_sshd_system_tree(Daemon, Config) ->
Host = proplists:get_value(host, Config),
Port = proplists:get_value(port, Config),
@@ -208,4 +209,103 @@ check_sshd_system_tree(Daemon, Config) ->
?wait_match([{_, _,worker,[ssh_channel]}],
supervisor:which_children(ChannelSup)),
ssh:close(Client).
-
+
+%%-------------------------------------------------------------------------
+killed_acceptor_restarts(Config) ->
+ Profile = proplists:get_value(profile, Config),
+ SystemDir = proplists:get_value(data_dir, Config),
+ UserDir = proplists:get_value(userdir, Config),
+ {ok, DaemonPid} = ssh:daemon(0, [{system_dir, SystemDir},
+ {failfun, fun ssh_test_lib:failfun/2},
+ {user_passwords, [{?USER, ?PASSWD}]},
+ {profile, Profile}]),
+
+ {ok, DaemonPid2} = ssh:daemon(0, [{system_dir, SystemDir},
+ {failfun, fun ssh_test_lib:failfun/2},
+ {user_passwords, [{?USER, ?PASSWD}]},
+ {profile, Profile}]),
+
+ {ok,Dinf} = ssh:daemon_info(DaemonPid),
+ Port = proplists:get_value(port, Dinf),
+
+ {ok,Dinf2} = ssh:daemon_info(DaemonPid2),
+ Port2 = proplists:get_value(port, Dinf2),
+
+ true = (Port /= Port2),
+
+ ct:pal("~s",[lists:flatten(ssh_info:string())]),
+
+ {ok,[{AccPid,ListenAddr,Port}]} = acceptor_pid(DaemonPid),
+ {ok,[{AccPid2,ListenAddr,Port2}]} = acceptor_pid(DaemonPid2),
+
+ true = (AccPid /= AccPid2),
+
+ %% Connect first client and check it is alive:
+ {ok,C1} = ssh:connect("localhost", Port, [{silently_accept_hosts, true},
+ {user_interaction, false},
+ {user, ?USER},
+ {password, ?PASSWD},
+ {user_dir, UserDir}]),
+ [{client_version,_}] = ssh:connection_info(C1,[client_version]),
+
+ %% Make acceptor restart:
+ exit(AccPid, kill),
+
+ %% Check it is a new acceptor:
+ {ok,[{AccPid1,ListenAddr,Port}]} = acceptor_pid(DaemonPid),
+ true = (AccPid /= AccPid1),
+ true = (AccPid2 /= AccPid1),
+
+ %% Connect second client and check it is alive:
+ {ok,C2} = ssh:connect("localhost", Port, [{silently_accept_hosts, true},
+ {user_interaction, false},
+ {user, ?USER},
+ {password, ?PASSWD},
+ {user_dir, UserDir}]),
+ [{client_version,_}] = ssh:connection_info(C2,[client_version]),
+
+ ct:pal("~s",[lists:flatten(ssh_info:string())]),
+
+ %% Check first client is still alive:
+ [{client_version,_}] = ssh:connection_info(C1,[client_version]),
+
+ ok = ssh:stop_daemon(DaemonPid2),
+ timer:sleep(15000),
+ [{client_version,_}] = ssh:connection_info(C1,[client_version]),
+ [{client_version,_}] = ssh:connection_info(C2,[client_version]),
+
+ ok = ssh:stop_daemon(DaemonPid),
+ timer:sleep(15000),
+ {error,closed} = ssh:connection_info(C1,[client_version]),
+ {error,closed} = ssh:connection_info(C2,[client_version]).
+
+%%%================================================================
+acceptor_pid(DaemonPid) ->
+ Parent = self(),
+ Pid = spawn(fun() ->
+ Parent ! {self(), supsearch,
+ [{AccPid,ListenAddr,Port}
+
+ || {{server,ssh_system_sup,ListenAddr,Port,NS},
+ DPid,supervisor,
+ [ssh_system_sup]} <- supervisor:which_children(sshd_sup),
+ DPid == DaemonPid,
+
+ {{ssh_acceptor_sup,L1,P1,NS1},
+ AccSupPid,supervisor,
+ [ssh_acceptor_sup]} <- supervisor:which_children(DaemonPid),
+ L1 == ListenAddr,
+ P1 == Port,
+ NS1 == NS1,
+
+ {{ssh_acceptor_sup,L2,P2,NS2},
+ AccPid,worker,
+ [ssh_acceptor]} <- supervisor:which_children(AccSupPid),
+ L2 == ListenAddr,
+ P2 == Port,
+ NS2 == NS]}
+ end),
+ receive {Pid, supsearch, L} -> {ok,L}
+ after 2000 -> timeout
+ end.
+
--
cgit v1.2.3
From 26fffbb94ec15646235f1ba91aa3afcfb9711daa Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 3 Mar 2017 14:17:10 +0100
Subject: ssh: Test-suites beautifications
---
lib/ssh/test/ssh_sftpd_SUITE.erl | 4 +-
lib/ssh/test/ssh_sup_SUITE.erl | 91 ++++++++++++++++++++--------------------
lib/ssh/test/ssh_test_lib.erl | 3 ++
3 files changed, 51 insertions(+), 47 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_sftpd_SUITE.erl b/lib/ssh/test/ssh_sftpd_SUITE.erl
index b167f98ac8..4dd510fc47 100644
--- a/lib/ssh/test/ssh_sftpd_SUITE.erl
+++ b/lib/ssh/test/ssh_sftpd_SUITE.erl
@@ -151,8 +151,8 @@ init_per_testcase(TestCase, Config) ->
SubSystems = [ssh_sftpd:subsystem_spec([])],
ssh:daemon(0, [{subsystems, SubSystems}|Options])
end,
- {ok,Dinf} = ssh:daemon_info(Sftpd),
- Port = proplists:get_value(port, Dinf),
+
+ Port = ssh_test_lib:daemon_port(Sftpd),
Cm = ssh_test_lib:connect(Port,
[{user_dir, ClientUserDir},
diff --git a/lib/ssh/test/ssh_sup_SUITE.erl b/lib/ssh/test/ssh_sup_SUITE.erl
index 3f08ec4b38..fdeb8186a5 100644
--- a/lib/ssh/test/ssh_sup_SUITE.erl
+++ b/lib/ssh/test/ssh_sup_SUITE.erl
@@ -101,6 +101,7 @@ default_tree(Config) when is_list(Config) ->
?wait_match([], supervisor:which_children(sshc_sup)),
?wait_match([], supervisor:which_children(sshd_sup)).
+%%-------------------------------------------------------------------------
sshc_subtree() ->
[{doc, "Make sure the sshc subtree is correct"}].
sshc_subtree(Config) when is_list(Config) ->
@@ -129,6 +130,7 @@ sshc_subtree(Config) when is_list(Config) ->
ssh:close(Pid2),
?wait_match([], supervisor:which_children(sshc_sup)).
+%%-------------------------------------------------------------------------
sshd_subtree() ->
[{doc, "Make sure the sshd subtree is correct"}].
sshd_subtree(Config) when is_list(Config) ->
@@ -150,6 +152,7 @@ sshd_subtree(Config) when is_list(Config) ->
ct:sleep(?WAIT_FOR_SHUTDOWN),
?wait_match([], supervisor:which_children(sshd_sup)).
+%%-------------------------------------------------------------------------
sshd_subtree_profile() ->
[{doc, "Make sure the sshd subtree using profile option is correct"}].
sshd_subtree_profile(Config) when is_list(Config) ->
@@ -173,43 +176,6 @@ sshd_subtree_profile(Config) when is_list(Config) ->
ct:sleep(?WAIT_FOR_SHUTDOWN),
?wait_match([], supervisor:which_children(sshd_sup)).
-%%-------------------------------------------------------------------------
-check_sshd_system_tree(Daemon, Config) ->
- Host = proplists:get_value(host, Config),
- Port = proplists:get_value(port, Config),
- UserDir = proplists:get_value(userdir, Config),
- {ok, Client} = ssh:connect(Host, Port, [{silently_accept_hosts, true},
- {user_interaction, false},
- {user, ?USER}, {password, ?PASSWD},{user_dir, UserDir}]),
-
- ?wait_match([{_,SubSysSup, supervisor,[ssh_subsystem_sup]},
- {{ssh_acceptor_sup,_,_,_}, AccSup, supervisor,[ssh_acceptor_sup]}],
- supervisor:which_children(Daemon),
- [SubSysSup,AccSup]),
-
- ?wait_match([{{server,ssh_connection_sup, _,_},
- ConnectionSup, supervisor,
- [ssh_connection_sup]},
- {{server,ssh_channel_sup,_ ,_},
- ChannelSup,supervisor,
- [ssh_channel_sup]}],
- supervisor:which_children(SubSysSup),
- [ConnectionSup,ChannelSup]),
-
- ?wait_match([{{ssh_acceptor_sup,_,_,_},_,worker,[ssh_acceptor]}],
- supervisor:which_children(AccSup)),
-
- ?wait_match([{_, _, worker,[ssh_connection_handler]}],
- supervisor:which_children(ConnectionSup)),
-
- ?wait_match([], supervisor:which_children(ChannelSup)),
-
- ssh_sftp:start_channel(Client),
-
- ?wait_match([{_, _,worker,[ssh_channel]}],
- supervisor:which_children(ChannelSup)),
- ssh:close(Client).
-
%%-------------------------------------------------------------------------
killed_acceptor_restarts(Config) ->
Profile = proplists:get_value(profile, Config),
@@ -225,12 +191,8 @@ killed_acceptor_restarts(Config) ->
{user_passwords, [{?USER, ?PASSWD}]},
{profile, Profile}]),
- {ok,Dinf} = ssh:daemon_info(DaemonPid),
- Port = proplists:get_value(port, Dinf),
-
- {ok,Dinf2} = ssh:daemon_info(DaemonPid2),
- Port2 = proplists:get_value(port, Dinf2),
-
+ Port = ssh_test_lib:daemon_port(DaemonPid),
+ Port2 = ssh_test_lib:daemon_port(DaemonPid2),
true = (Port /= Port2),
ct:pal("~s",[lists:flatten(ssh_info:string())]),
@@ -279,7 +241,47 @@ killed_acceptor_restarts(Config) ->
{error,closed} = ssh:connection_info(C1,[client_version]),
{error,closed} = ssh:connection_info(C2,[client_version]).
-%%%================================================================
+%%-------------------------------------------------------------------------
+%% Help functions
+%%-------------------------------------------------------------------------
+check_sshd_system_tree(Daemon, Config) ->
+ Host = proplists:get_value(host, Config),
+ Port = proplists:get_value(port, Config),
+ UserDir = proplists:get_value(userdir, Config),
+ {ok, Client} = ssh:connect(Host, Port, [{silently_accept_hosts, true},
+ {user_interaction, false},
+ {user, ?USER},
+ {password, ?PASSWD},
+ {user_dir, UserDir}]),
+
+ ?wait_match([{_,SubSysSup, supervisor,[ssh_subsystem_sup]},
+ {{ssh_acceptor_sup,_,_,_}, AccSup, supervisor,[ssh_acceptor_sup]}],
+ supervisor:which_children(Daemon),
+ [SubSysSup,AccSup]),
+
+ ?wait_match([{{server,ssh_connection_sup, _,_},
+ ConnectionSup, supervisor,
+ [ssh_connection_sup]},
+ {{server,ssh_channel_sup,_ ,_},
+ ChannelSup,supervisor,
+ [ssh_channel_sup]}],
+ supervisor:which_children(SubSysSup),
+ [ConnectionSup,ChannelSup]),
+
+ ?wait_match([{{ssh_acceptor_sup,_,_,_},_,worker,[ssh_acceptor]}],
+ supervisor:which_children(AccSup)),
+
+ ?wait_match([{_, _, worker,[ssh_connection_handler]}],
+ supervisor:which_children(ConnectionSup)),
+
+ ?wait_match([], supervisor:which_children(ChannelSup)),
+
+ ssh_sftp:start_channel(Client),
+
+ ?wait_match([{_, _,worker,[ssh_channel]}],
+ supervisor:which_children(ChannelSup)),
+ ssh:close(Client).
+
acceptor_pid(DaemonPid) ->
Parent = self(),
Pid = spawn(fun() ->
@@ -308,4 +310,3 @@ acceptor_pid(DaemonPid) ->
receive {Pid, supsearch, L} -> {ok,L}
after 2000 -> timeout
end.
-
diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl
index 1673f52821..0ada8233a7 100644
--- a/lib/ssh/test/ssh_test_lib.erl
+++ b/lib/ssh/test/ssh_test_lib.erl
@@ -64,6 +64,9 @@ daemon(Host, Port, Options) ->
Error
end.
+daemon_port(Pid) -> daemon_port(0, Pid).
+
+
daemon_port(0, Pid) -> {ok,Dinf} = ssh:daemon_info(Pid),
proplists:get_value(port, Dinf);
daemon_port(Port, _) -> Port.
--
cgit v1.2.3
From ee8a5fa4da90016d6f17db2aa9f43bd98ca04985 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 13 Mar 2017 14:54:40 +0100
Subject: ssh: Removed outdated comment in ssh_sftpd.erl
---
lib/ssh/src/ssh_sftp.erl | 9 ---------
1 file changed, 9 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_sftp.erl b/lib/ssh/src/ssh_sftp.erl
index 140856c8e3..f1f7b57e8d 100644
--- a/lib/ssh/src/ssh_sftp.erl
+++ b/lib/ssh/src/ssh_sftp.erl
@@ -1063,15 +1063,6 @@ attr_to_info(A) when is_record(A, ssh_xfer_attr) ->
gid = A#ssh_xfer_attr.group}.
-%% Added workaround for sftp timestam problem. (Timestamps should be
-%% in UTC but they where not) . The workaround uses a deprecated
-%% function i calandar. This will work as expected most of the time
-%% but has problems for the same reason as
-%% calendar:local_time_to_universal_time/1. We consider it better that
-%% the timestamps work as expected most of the time instead of none of
-%% the time. Hopfully the file-api will be updated so that we can
-%% solve this problem in a better way in the future.
-
unix_to_datetime(undefined) ->
undefined;
unix_to_datetime(UTCSecs) ->
--
cgit v1.2.3
From f64dc7858c06d3096b47532270d9f6b732aa7ece Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 20 Mar 2017 13:15:34 +0100
Subject: ssh: remove deprecated ssh_sftpd:listen and ssh_sftpd:stop
---
lib/ssh/src/ssh_sftpd.erl | 26 +-------------------------
lib/ssh/test/ssh_sftpd_SUITE.erl | 2 +-
lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl | 2 +-
3 files changed, 3 insertions(+), 27 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_sftpd.erl b/lib/ssh/src/ssh_sftpd.erl
index 9352046795..b879116393 100644
--- a/lib/ssh/src/ssh_sftpd.erl
+++ b/lib/ssh/src/ssh_sftpd.erl
@@ -34,8 +34,7 @@
%%--------------------------------------------------------------------
%% External exports
--export([subsystem_spec/1,
- listen/1, listen/2, listen/3, stop/1]).
+-export([subsystem_spec/1]).
-export([init/1, handle_ssh_msg/2, handle_msg/2, terminate/2]).
@@ -76,29 +75,6 @@
subsystem_spec(Options) ->
{"sftp", {?MODULE, Options}}.
-%%% DEPRECATED START %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%--------------------------------------------------------------------
-%% Function: listen() -> Pid | {error,Error}
-%% Description: Starts the server
-%%--------------------------------------------------------------------
-listen(Port) ->
- listen(any, Port, []).
-listen(Port, Options) ->
- listen(any, Port, Options).
-listen(Addr, Port, Options) ->
- SubSystems = [subsystem_spec(Options)],
- ssh:daemon(Addr, Port, [{subsystems, SubSystems} |Options]).
-
-%%--------------------------------------------------------------------
-%% Function: stop(Pid) -> ok
-%% Description: Stops the listener
-%%--------------------------------------------------------------------
-stop(Pid) ->
- ssh:stop_listener(Pid).
-
-
-%%% DEPRECATED END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%====================================================================
%% subsystem callbacks
diff --git a/lib/ssh/test/ssh_sftpd_SUITE.erl b/lib/ssh/test/ssh_sftpd_SUITE.erl
index 4dd510fc47..673fb54a4f 100644
--- a/lib/ssh/test/ssh_sftpd_SUITE.erl
+++ b/lib/ssh/test/ssh_sftpd_SUITE.erl
@@ -187,7 +187,7 @@ init_per_testcase(TestCase, Config) ->
[{sftp, {Cm, Channel}}, {sftpd, Sftpd }| Config].
end_per_testcase(_TestCase, Config) ->
- ssh_sftpd:stop(proplists:get_value(sftpd, Config)),
+ catch ssh:stop_daemon(proplists:get_value(sftpd, Config)),
{Cm, Channel} = proplists:get_value(sftp, Config),
ssh_connection:close(Cm, Channel),
ssh:close(Cm),
diff --git a/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl b/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl
index b4d7eadfa4..9b5d6b5fae 100644
--- a/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl
+++ b/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl
@@ -138,7 +138,7 @@ init_per_testcase(TestCase, Config) ->
[{port, Port}, {sftp, {ChannelPid, Connection}}, {sftpd, Sftpd} | NewConfig].
end_per_testcase(_TestCase, Config) ->
- catch ssh_sftpd:stop(proplists:get_value(sftpd, Config)),
+ catch ssh:stop_daemon(proplists:get_value(sftpd, Config)),
{Sftp, Connection} = proplists:get_value(sftp, Config),
catch ssh_sftp:stop_channel(Sftp),
catch ssh:close(Connection),
--
cgit v1.2.3
From 3bbb2c9d5f92205f91cc68b9cebe263b84afe3e2 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Tue, 21 Mar 2017 15:20:58 +0100
Subject: ssh: -type and -spec adjustments
---
lib/ssh/src/ssh.hrl | 17 +++++++++++++++--
lib/ssh/src/ssh_options.erl | 12 +-----------
2 files changed, 16 insertions(+), 13 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh.hrl b/lib/ssh/src/ssh.hrl
index 63eeb0bd0a..e03c15454c 100644
--- a/lib/ssh/src/ssh.hrl
+++ b/lib/ssh/src/ssh.hrl
@@ -113,12 +113,25 @@
-type double_algs() :: list( {client2serverlist,simple_algs()} | {server2client,simple_algs()} )
| simple_algs() .
+-type options() :: #{socket_options := socket_options(),
+ internal_options := internal_options(),
+ option_key() => any()
+ }.
+
+-type socket_options() :: proplists:proplist().
+-type internal_options() :: #{option_key() => any()}.
+
+-type option_key() :: atom().
+
+
%% Records
-record(ssh,
{
- role, %% client | server
- peer, %% string version of peer address
+ role :: client | role(),
+ peer :: undefined |
+ {inet:hostname(),
+ {inet:ip_adress(),inet:port_number()}}, %% string version of peer address
c_vsn, %% client version {Major,Minor}
s_vsn, %% server version {Major,Minor}
diff --git a/lib/ssh/src/ssh_options.erl b/lib/ssh/src/ssh_options.erl
index cb3f63103c..febd3f6eef 100644
--- a/lib/ssh/src/ssh_options.erl
+++ b/lib/ssh/src/ssh_options.erl
@@ -38,16 +38,6 @@
%%%================================================================
%%% Types
--type options() :: #{socket_options := socket_options(),
- internal_options := internal_options(),
- option_key() => any()
- }.
-
--type socket_options() :: proplists:proplist().
--type internal_options() :: #{option_key() => any()}.
-
--type option_key() :: atom().
-
-type option_in() :: proplists:property() | proplists:proplist() .
-type option_class() :: internal_options | socket_options | user_options .
@@ -431,7 +421,7 @@ default(client) ->
},
{silently_accept_hosts, def} =>
- #{default => {false,none},
+ #{default => false,
chk => fun check_silently_accept_hosts/1,
class => user_options
},
--
cgit v1.2.3
From 4d6393bc4df58defbc22c5d97e28bbfdd8794fc6 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 6 Apr 2017 19:31:13 +0200
Subject: ssh: Lazy default in get options macro
---
lib/ssh/src/ssh.hrl | 5 ++++-
lib/ssh/src/ssh_connection_handler.erl | 10 ++--------
lib/ssh/src/ssh_options.erl | 15 +++++++++------
3 files changed, 15 insertions(+), 15 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh.hrl b/lib/ssh/src/ssh.hrl
index e03c15454c..315310f700 100644
--- a/lib/ssh/src/ssh.hrl
+++ b/lib/ssh/src/ssh.hrl
@@ -75,9 +75,12 @@
%% Option access macros
-define(do_get_opt(C,K,O), ssh_options:get_value(C,K,O, ?MODULE,?LINE)).
--define(do_get_opt(C,K,O,D), ssh_options:get_value(C,K,O,D,?MODULE,?LINE)).
+-define(do_get_opt(C,K,O,D), ssh_options:get_value(C,K,O,?LAZY(D),?MODULE,?LINE)).
+
+-define(LAZY(D), fun()-> D end).
-define(GET_OPT(Key,Opts), ?do_get_opt(user_options, Key,Opts ) ).
+-define(GET_OPT(Key,Opts,Def), ?do_get_opt(user_options, Key,Opts,Def) ).
-define(GET_INTERNAL_OPT(Key,Opts), ?do_get_opt(internal_options,Key,Opts ) ).
-define(GET_INTERNAL_OPT(Key,Opts,Def), ?do_get_opt(internal_options,Key,Opts,Def) ).
-define(GET_SOCKET_OPT(Key,Opts), ?do_get_opt(socket_options, Key,Opts ) ).
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 5a13209ae3..50a29bbb53 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -413,14 +413,8 @@ init_connection(server, C = #connection{}, Opts) ->
SubSystemSup = proplists:get_value(subsystem_sup, Sups),
ConnectionSup = proplists:get_value(connection_sup, Sups),
- Shell = ?GET_OPT(shell, Opts),
- Exec = ?GET_OPT(exec, Opts),
- CliSpec = case ?GET_OPT(ssh_cli, Opts) of
- undefined -> {ssh_cli, [Shell]};
- Spec -> Spec
- end,
- C#connection{cli_spec = CliSpec,
- exec = Exec,
+ C#connection{cli_spec = ?GET_OPT(ssh_cli, Opts, {ssh_cli,[?GET_OPT(shell, Opts)]}),
+ exec = ?GET_OPT(exec, Opts),
system_supervisor = SystemSup,
sub_system_supervisor = SubSystemSup,
connection_supervisor = ConnectionSup
diff --git a/lib/ssh/src/ssh_options.erl b/lib/ssh/src/ssh_options.erl
index febd3f6eef..ee3cdbb8a0 100644
--- a/lib/ssh/src/ssh_options.erl
+++ b/lib/ssh/src/ssh_options.erl
@@ -69,17 +69,20 @@ get_value(Class, Key, Opts, _CallerMod, _CallerLine) ->
error({bad_options,Class, Key, Opts, _CallerMod, _CallerLine}).
--spec get_value(option_class(), option_key(), options(), any(),
+-spec get_value(option_class(), option_key(), options(), fun(() -> any()),
atom(), non_neg_integer()) -> any() | no_return().
-get_value(socket_options, Key, Opts, Def, _CallerMod, _CallerLine) when is_map(Opts) ->
- proplists:get_value(Key, maps:get(socket_options,Opts), Def);
-get_value(Class, Key, Opts, Def, CallerMod, CallerLine) when is_map(Opts) ->
+get_value(socket_options, Key, Opts, DefFun, _CallerMod, _CallerLine) when is_map(Opts) ->
+ proplists:get_value(Key, maps:get(socket_options,Opts), DefFun);
+get_value(Class, Key, Opts, DefFun, CallerMod, CallerLine) when is_map(Opts) ->
try get_value(Class, Key, Opts, CallerMod, CallerLine)
+ of
+ undefined -> DefFun();
+ Value -> Value
catch
- error:{badkey,Key} -> Def
+ error:{badkey,Key} -> DefFun()
end;
-get_value(Class, Key, Opts, _Def, _CallerMod, _CallerLine) ->
+get_value(Class, Key, Opts, _DefFun, _CallerMod, _CallerLine) ->
error({bad_options,Class, Key, Opts, _CallerMod, _CallerLine}).
--
cgit v1.2.3
From 57d994270d63e7a9ce80eece3c1c3aeca79d3ea4 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Tue, 21 Mar 2017 15:44:44 +0100
Subject: ssh: fix ssh_system_sup naming of Host-Port-Profile
---
lib/ssh/src/ssh.erl | 2 +-
lib/ssh/src/ssh_acceptor_sup.erl | 7 +------
lib/ssh/src/ssh_system_sup.erl | 16 ++--------------
lib/ssh/src/sshd_sup.erl | 7 +------
4 files changed, 5 insertions(+), 27 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index ff424b738c..9047b7e0f0 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -475,6 +475,6 @@ finalize_start(Host, Port, Profile, Options0, F) ->
end.
%%%----------------------------------------------------------------
-fmt_host(any) -> any;
+fmt_host(any) -> "any";
fmt_host(IP) when is_tuple(IP) -> inet:ntoa(IP);
fmt_host(Str) when is_list(Str) -> Str.
diff --git a/lib/ssh/src/ssh_acceptor_sup.erl b/lib/ssh/src/ssh_acceptor_sup.erl
index 77f7826918..613d8fbc75 100644
--- a/lib/ssh/src/ssh_acceptor_sup.erl
+++ b/lib/ssh/src/ssh_acceptor_sup.erl
@@ -93,10 +93,5 @@ child_spec(Options) ->
{Name, StartFunc, Restart, Shutdown, Type, Modules}.
id(Address, Port, Profile) ->
- case is_list(Address) of
- true ->
- {ssh_acceptor_sup, any, Port, Profile};
- false ->
- {ssh_acceptor_sup, Address, Port, Profile}
- end.
+ {ssh_acceptor_sup, Address, Port, Profile}.
diff --git a/lib/ssh/src/ssh_system_sup.erl b/lib/ssh/src/ssh_system_sup.erl
index 5a58ef1c44..4083f666c3 100644
--- a/lib/ssh/src/ssh_system_sup.erl
+++ b/lib/ssh/src/ssh_system_sup.erl
@@ -166,22 +166,10 @@ ssh_subsystem_child_spec(Options) ->
id(Sup, Address, Port, Profile) ->
- case is_list(Address) of
- true ->
- {Sup, any, Port, Profile};
- false ->
- {Sup, Address, Port, Profile}
- end.
+ {Sup, Address, Port, Profile}.
make_name(Address, Port, Profile) ->
- case is_list(Address) of
- true ->
- list_to_atom(lists:flatten(io_lib:format("ssh_system_~p_~p_~p_sup",
- [any, Port, Profile])));
- false ->
- list_to_atom(lists:flatten(io_lib:format("ssh_system_~p_~p_~p_sup",
- [Address, Port, Profile])))
- end.
+ list_to_atom(lists:flatten(io_lib:format("ssh_system_~s_~p_~p_sup", [Address, Port, Profile]))).
ssh_subsystem_sup([{_, Child, _, [ssh_subsystem_sup]} | _]) ->
Child;
diff --git a/lib/ssh/src/sshd_sup.erl b/lib/ssh/src/sshd_sup.erl
index 14f1937abd..791456839d 100644
--- a/lib/ssh/src/sshd_sup.erl
+++ b/lib/ssh/src/sshd_sup.erl
@@ -103,12 +103,7 @@ child_spec(Address, Port, Options) ->
{Name, StartFunc, Restart, Shutdown, Type, Modules}.
id(Address, Port, Profile) ->
- case is_list(Address) of
- true ->
- {server, ssh_system_sup, any, Port, Profile};
- false ->
- {server, ssh_system_sup, Address, Port, Profile}
- end.
+ {server, ssh_system_sup, Address, Port, Profile}.
system_name([], _ ) ->
undefined;
--
cgit v1.2.3
From 6158cb432092c47e178b4dc1177b46cb8c310ab4 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Tue, 21 Mar 2017 19:50:49 +0100
Subject: ssh: Fix supervisors, start daemon and connect code
Remove many internal options and made them as explicit arguments.
---
lib/ssh/src/ssh.erl | 240 +++++++++++++++++++++------------
lib/ssh/src/ssh_acceptor.erl | 3 +-
lib/ssh/src/ssh_acceptor_sup.erl | 22 ++-
lib/ssh/src/ssh_connection_handler.erl | 7 +-
lib/ssh/src/ssh_file.erl | 2 +
lib/ssh/src/ssh_subsystem_sup.erl | 34 ++---
lib/ssh/src/ssh_sup.erl | 53 +-------
lib/ssh/src/ssh_system_sup.erl | 43 +++---
lib/ssh/src/sshc_sup.erl | 14 +-
lib/ssh/src/sshd_sup.erl | 55 +++-----
10 files changed, 237 insertions(+), 236 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 9047b7e0f0..680047dffd 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -108,7 +108,7 @@ connect(Socket, UserOptions, Timeout) when is_port(Socket),
case valid_socket_to_use(Socket, ?GET_OPT(transport,Options)) of
ok ->
{ok, {Host,_Port}} = inet:sockname(Socket),
- Opts = ?PUT_INTERNAL_OPT([{user_pid,self()}, {host,fmt_host(Host)}], Options),
+ Opts = ?PUT_INTERNAL_OPT([{user_pid,self()}, {host,Host}], Options),
ssh_connection_handler:start_connection(client, Socket, Opts, Timeout);
{error,SockError} ->
{error,SockError}
@@ -132,7 +132,7 @@ connect(Host, Port, UserOptions, Timeout) when is_integer(Port),
SocketOpts = [{active,false} | ?GET_OPT(socket_options,Options)],
try Transport:connect(Host, Port, SocketOpts, ConnectionTimeout) of
{ok, Socket} ->
- Opts = ?PUT_INTERNAL_OPT([{user_pid,self()}, {host,fmt_host(Host)}], Options),
+ Opts = ?PUT_INTERNAL_OPT([{user_pid,self()}, {host,Host}], Options),
ssh_connection_handler:start_connection(client, Socket, Opts, Timeout);
{error, Reason} ->
{error, Reason}
@@ -188,14 +188,11 @@ daemon(Socket, UserOptions) when is_port(Socket) ->
case valid_socket_to_use(Socket, ?GET_OPT(transport,Options)) of
ok ->
{ok, {IP,Port}} = inet:sockname(Socket),
- finalize_start(fmt_host(IP), Port, ?GET_OPT(profile, Options),
+ finalize_start(IP, Port, ?GET_OPT(profile, Options),
?PUT_INTERNAL_OPT({connected_socket, Socket}, Options),
fun(Opts, DefaultResult) ->
try ssh_acceptor:handle_established_connection(
- ?GET_INTERNAL_OPT(address, Opts),
- ?GET_INTERNAL_OPT(port, Opts),
- Opts,
- Socket)
+ IP, Port, Opts, Socket)
of
{error,Error} ->
{error,Error};
@@ -238,7 +235,7 @@ daemon(Host0, Port0, UserOptions0) when 0 =< Port0, Port0 =< 65535 ->
%% and ListenSocket is for listening on connections. But it is still owned
%% by self()...
- finalize_start(fmt_host(Host), Port, ?GET_OPT(profile, Options0),
+ finalize_start(Host, Port, ?GET_OPT(profile, Options0),
?PUT_INTERNAL_OPT({lsocket,{ListenSocket,self()}}, Options0),
fun(Opts, Result) ->
{_, Callback, _} = ?GET_OPT(transport, Opts),
@@ -269,17 +266,27 @@ daemon(Host0, Port0, UserOptions0) when 0 =< Port0, Port0 =< 65535 ->
daemon_info(Pid) ->
case catch ssh_system_sup:acceptor_supervisor(Pid) of
AsupPid when is_pid(AsupPid) ->
- [{ListenAddr,Port,Profile}] =
- [{LA,Prt,Prf} || {{ssh_acceptor_sup,LA,Prt,Prf},
- _WorkerPid,worker,[ssh_acceptor]} <- supervisor:which_children(AsupPid)],
+ [{Name,Port,Profile}] =
+ [{Nam,Prt,Prf}
+ || {{ssh_acceptor_sup,Hst,Prt,Prf},_Pid,worker,[ssh_acceptor]}
+ <- supervisor:which_children(AsupPid),
+ Nam <- [case inet:parse_strict_address(Hst) of
+ {ok,IP} -> IP;
+ _ when Hst=="any" -> any;
+ _ when Hst=="loopback" -> loopback;
+ _ -> Hst
+ end]
+ ],
{ok, [{port,Port},
- {listen_address,ListenAddr},
+ {name,Name},
{profile,Profile}
]};
_ ->
{error,bad_daemon_ref}
end.
+
+
%%--------------------------------------------------------------------
-spec stop_listener(daemon_ref()) -> ok.
-spec stop_listener(inet:ip_address(), inet:port_number()) -> ok.
@@ -361,49 +368,128 @@ default_algorithms() ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
-handle_daemon_args(HostAddr, Opts) ->
+
+%% - if Address is 'any' and no ip-option is present, the name is
+%% 'any' and the socket will listen to all addresses
+%%
+%% - if Address is 'any' and an ip-option is present, the name is
+%% set to the value of the ip-option and the socket will listen
+%% to that address
+%%
+%% - if Address is 'loopback' and no ip-option is present, the name
+%% is 'loopback' and an loopback address will be choosen by the
+%% underlying layers
+%%
+%% - if Address is 'loopback' and an ip-option is present, the name
+%% is set to the value of the ip-option kept and the socket will
+%% listen to that address
+%%
+%% - if Address is an ip-address, that ip-address is the name and
+%% the listening address. An ip-option will be discarded.
+%%
+%% - if Address is a HostName, and that resolves to an ip-address,
+%% that ip-address is the name and the listening address. An
+%% ip-option will be discarded.
+%%
+%% - if Address is a string or an atom other than thoose defined
+%% above, that Address will be the name and the listening address
+%% will be choosen by the lower layers taking an ip-option in
+%% consideration
+%%
+
+handle_daemon_args(any, Opts) ->
+ case proplists:get_value(ip, Opts) of
+ undefined -> {any, Opts};
+ IP -> {IP, Opts}
+ end;
+
+handle_daemon_args(loopback, Opts) ->
+ case proplists:get_value(ip, Opts) of
+ undefined -> {loopback, [{ip,loopback}|Opts]};
+ IP -> {IP, Opts}
+ end;
+
+handle_daemon_args(IPaddr, Opts) when is_tuple(IPaddr) ->
+ case proplists:get_value(ip, Opts) of
+ undefined -> {IPaddr, [{ip,IPaddr}|Opts]};
+ IPaddr -> {IPaddr, Opts};
+ IP -> {IPaddr, [{ip,IPaddr}|Opts--[{ip,IP}]]} %% Backward compatibility
+ end;
+
+handle_daemon_args(Address, Opts) when is_list(Address) ; is_atom(Address) ->
IP = proplists:get_value(ip, Opts),
- IPh = case inet:parse_strict_address(HostAddr) of
- {ok, IPtuple} -> IPtuple;
- {error, einval} when is_tuple(HostAddr),
- size(HostAddr)==4 ; size(HostAddr)==6 -> HostAddr;
- _ -> undefined
- end,
- handle_daemon_args(HostAddr, IPh, IP, Opts).
-
-
-%% HostAddr is 'any'
-handle_daemon_args(any, undefined, undefined, Opts) -> {any, Opts};
-handle_daemon_args(any, undefined, IP, Opts) -> {IP, Opts};
-
-%% HostAddr is 'loopback' or "localhost"
-handle_daemon_args(loopback, undefined, {127,_,_,_}=IP, Opts) -> {IP, Opts};
-handle_daemon_args(loopback, undefined, {0,0,0,0,0,0,0,1}=IP, Opts) -> {IP, Opts};
-handle_daemon_args(loopback, undefined, undefined, Opts) ->
- IP = case proplists:get_value(inet,Opts) of
- true -> {127,0,0,1};
- inet -> {127,0,0,1};
- inet6 -> {0,0,0,0,0,0,0,1};
- _ -> case proplists:get_value(inet6,Opts) of
- true -> {0,0,0,0,0,0,0,1};
- _ -> {127,0,0,1} % default if no 'inet' nor 'inet6'
- end
- end,
- {IP, [{ip,IP}|Opts]};
-handle_daemon_args("localhost", IPh, IP, Opts) ->
- handle_daemon_args(loopback, IPh, IP, Opts);
-
-%% HostAddr is ip and no ip-option
-handle_daemon_args(_, IP, undefined, Opts) when is_tuple(IP) -> {IP, [{ip,IP}|Opts]};
-
-%% HostAddr and ip-option are equal
-handle_daemon_args(_, IP, IP, Opts) when is_tuple(IP) -> {IP, Opts};
-
-%% HostAddr is ip, but ip-option is different!
-handle_daemon_args(_, IPh, IPo, _) when is_tuple(IPh), is_tuple(IPo) -> error({eoption,{ip,IPo}});
-
-%% Something else. Whatever it is, it is wrong.
-handle_daemon_args(_, _, _, _) -> error(badarg).
+ case inet:parse_strict_address(Address) of
+ {ok, IP} -> {IP, Opts};
+ {ok, OtherIP} -> {OtherIP, [{ip,OtherIP}|Opts--[{ip,IP}]]};
+ _ ->
+ case inet:getaddr(Address, family(Opts)) of
+ {ok, IP} -> {Address, Opts};
+ {ok, OtherIP} -> {Address, [{ip,OtherIP}|Opts--[{ip,IP}]]};
+ _ -> {Address, Opts}
+ end
+ end.
+
+
+-ifdef(hulahopp).
+%% Check the Address parameter and set an ip-option in some cases. The
+%% Address parameter is left unchanged because ssh:stop_listener and
+%% ssh:stop_daemon needs to find the system supervisor by name
+
+handle_daemon_args(any, Opts) ->
+ %% Listen to 0.0.0.0. The caller may have set an ip-option. Trust
+ %% that one in such a case.
+ {any, Opts};
+
+handle_daemon_args(loopback, Opts) ->
+ %% Listen to a loopback address. Let the underlying layers decide
+ %% in case the caller hasn't set the ip-option.
+ {loopback, ensure_ip_option(loopback,Opts)};
+
+handle_daemon_args(IP, Opts) when is_tuple(IP) ->
+ %% An IP address in Erlang tuple format:
+ {IP, ensure_ip_option(IP,Opts)};
+
+handle_daemon_args(Address, Opts) when is_list(Address) ; is_atom(Address) ->
+ %% This might be a host name, an FQDN, an IP address in string format ("127.1.1.1")
+ %% etc. It might be a string or an atom since inet:hostname() is defined in that way
+ case inet:parse_strict_address(Address) of
+ {ok, IP} ->
+ {Address, ensure_ip_option(IP,Opts)};
+ _ ->
+ %% Try to lookup as a hostname:
+ case inet:getaddr(Address, family(Opts)) of
+ {ok, IP} ->
+ {Address, ensure_ip_option(IP,Opts)};
+ _ ->
+ %% Give up and let the underlying system handle this
+ {Address, Opts}
+ end
+ end.
+
+
+%% Add an ip-option if not already present.
+ensure_ip_option(Address, Opts) ->
+ case proplists:get_value(ip, Opts) of
+ undefined -> [{ip,Address}|Opts];
+ _ -> Opts
+ end.
+-endif.
+
+
+%% Has the caller indicated the address family?
+family(Opts) ->
+ family(Opts, inet).
+
+family(Opts, Default) ->
+ case proplists:get_value(inet,Opts) of
+ true -> inet;
+ inet -> inet;
+ inet6 -> inet6;
+ _ -> case proplists:get_value(inet6,Opts) of
+ true -> inet6;
+ _ -> Default
+ end
+ end.
%%%----------------------------------------------------------------
valid_socket_to_use(Socket, {tcp,_,_}) ->
@@ -434,8 +520,9 @@ open_listen_socket(Host0, Port0, Options0) ->
case ?GET_SOCKET_OPT(fd, Options0) of
undefined ->
{ok,LSock} = ssh_acceptor:listen(Port0, Options0),
- {ok,{_,LPort}} = inet:sockname(LSock),
- {{Host0,LPort}, LSock};
+ {ok,{_LHost,LPort}} = inet:sockname(LSock),
+ {{_LHost,LPort}, LSock};
+%% {{Host0,LPort}, LSock};
Fd when is_integer(Fd) ->
%% Do gen_tcp:listen with the option {fd,Fd}:
@@ -446,35 +533,18 @@ open_listen_socket(Host0, Port0, Options0) ->
%%%----------------------------------------------------------------
finalize_start(Host, Port, Profile, Options0, F) ->
- Options = ?PUT_INTERNAL_OPT([{address, Host},
- {port, Port},
- {role, server}], Options0),
- case ssh_system_sup:system_supervisor(Host, Port, Profile) of
- undefined ->
- try sshd_sup:start_child(Options) of
- {error, {already_started, _}} ->
- {error, eaddrinuse};
- {error, Error} ->
- {error, Error};
- Result = {ok,_} ->
- F(Options, Result)
- catch
- exit:{noproc, _} ->
- {error, ssh_not_started}
- end;
- Sup ->
- AccPid = ssh_system_sup:acceptor_supervisor(Sup),
- case ssh_acceptor_sup:start_child(AccPid, Options) of
- {error, {already_started, _}} ->
- {error, eaddrinuse};
- {error, Error} ->
- {error, Error};
- {ok, _} ->
- F(Options, {ok,Sup})
- end
+ try
+ sshd_sup:start_child(Host, Port, Profile, Options0)
+ of
+ {error, {already_started, _}} ->
+ {error, eaddrinuse};
+ {error, Error} ->
+ {error, Error};
+ Result = {ok,_} ->
+ F(Options0, Result)
+ catch
+ exit:{noproc, _} ->
+ {error, ssh_not_started}
end.
%%%----------------------------------------------------------------
-fmt_host(any) -> "any";
-fmt_host(IP) when is_tuple(IP) -> inet:ntoa(IP);
-fmt_host(Str) when is_list(Str) -> Str.
diff --git a/lib/ssh/src/ssh_acceptor.erl b/lib/ssh/src/ssh_acceptor.erl
index f9e2280212..f7fbd7ccad 100644
--- a/lib/ssh/src/ssh_acceptor.erl
+++ b/lib/ssh/src/ssh_acceptor.erl
@@ -129,7 +129,8 @@ handle_connection(Callback, Address, Port, Options, Socket) ->
MaxSessions = ?GET_OPT(max_sessions, Options),
case number_of_connections(SystemSup) < MaxSessions of
true ->
- {ok, SubSysSup} = ssh_system_sup:start_subsystem(SystemSup, Options),
+ {ok, SubSysSup} =
+ ssh_system_sup:start_subsystem(SystemSup, server, Address, Port, Profile, Options),
ConnectionSup = ssh_subsystem_sup:connection_supervisor(SubSysSup),
NegTimeout = ?GET_OPT(negotiation_timeout, Options),
ssh_connection_handler:start_connection(server, Socket,
diff --git a/lib/ssh/src/ssh_acceptor_sup.erl b/lib/ssh/src/ssh_acceptor_sup.erl
index 613d8fbc75..4606107f56 100644
--- a/lib/ssh/src/ssh_acceptor_sup.erl
+++ b/lib/ssh/src/ssh_acceptor_sup.erl
@@ -29,7 +29,7 @@
-include("ssh.hrl").
--export([start_link/1, start_child/2, stop_child/4]).
+-export([start_link/4, start_child/5, stop_child/4]).
%% Supervisor callback
-export([init/1]).
@@ -41,16 +41,13 @@
%%%=========================================================================
%%% API
%%%=========================================================================
-start_link(Servers) ->
- supervisor:start_link(?MODULE, [Servers]).
+start_link(Address, Port, Profile, Options) ->
+ supervisor:start_link(?MODULE, [Address, Port, Profile, Options]).
-start_child(AccSup, Options) ->
- Spec = child_spec(Options),
+start_child(AccSup, Address, Port, Profile, Options) ->
+ Spec = child_spec(Address, Port, Profile, Options),
case supervisor:start_child(AccSup, Spec) of
{error, already_present} ->
- Address = ?GET_INTERNAL_OPT(address, Options),
- Port = ?GET_INTERNAL_OPT(port, Options),
- Profile = ?GET_OPT(profile, Options),
stop_child(AccSup, Address, Port, Profile),
supervisor:start_child(AccSup, Spec);
Reply ->
@@ -69,21 +66,18 @@ stop_child(AccSup, Address, Port, Profile) ->
%%%=========================================================================
%%% Supervisor callback
%%%=========================================================================
-init([Options]) ->
+init([Address, Port, Profile, Options]) ->
RestartStrategy = one_for_one,
MaxR = 10,
MaxT = 3600,
- Children = [child_spec(Options)],
+ Children = [child_spec(Address, Port, Profile, Options)],
{ok, {{RestartStrategy, MaxR, MaxT}, Children}}.
%%%=========================================================================
%%% Internal functions
%%%=========================================================================
-child_spec(Options) ->
- Address = ?GET_INTERNAL_OPT(address, Options),
- Port = ?GET_INTERNAL_OPT(port, Options),
+child_spec(Address, Port, Profile, Options) ->
Timeout = ?GET_INTERNAL_OPT(timeout, Options, ?DEFAULT_TIMEOUT),
- Profile = ?GET_OPT(profile, Options),
Name = id(Address, Port, Profile),
StartFunc = {ssh_acceptor, start_link, [Port, Address, Options, Timeout]},
Restart = transient,
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 50a29bbb53..ff94e5dfb6 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -440,7 +440,12 @@ init_ssh_record(Role, Socket, Opts) ->
{Vsn, Version} = ssh_transport:versions(Role, Opts),
case Role of
client ->
- PeerName = ?GET_INTERNAL_OPT(host, Opts),
+ PeerName = case ?GET_INTERNAL_OPT(host, Opts) of
+ PeerIP when is_tuple(PeerIP) ->
+ inet_parse:ntoa(PeerIP);
+ PeerName0 ->
+ PeerName0
+ end,
S0#ssh{c_vsn = Vsn,
c_version = Version,
io_cb = case ?GET_OPT(user_interaction, Opts) of
diff --git a/lib/ssh/src/ssh_file.erl b/lib/ssh/src/ssh_file.erl
index 898b4cc5c4..88f4d10792 100644
--- a/lib/ssh/src/ssh_file.erl
+++ b/lib/ssh/src/ssh_file.erl
@@ -221,6 +221,8 @@ file_name(Type, Name, Opts) ->
%% in: "host" out: "host,1.2.3.4.
+add_ip(IP) when is_tuple(IP) ->
+ ssh_connection:encode_ip(IP);
add_ip(Host) ->
case inet:getaddr(Host, inet) of
{ok, Addr} ->
diff --git a/lib/ssh/src/ssh_subsystem_sup.erl b/lib/ssh/src/ssh_subsystem_sup.erl
index cf82db458f..c5ab422265 100644
--- a/lib/ssh/src/ssh_subsystem_sup.erl
+++ b/lib/ssh/src/ssh_subsystem_sup.erl
@@ -28,7 +28,7 @@
-include("ssh.hrl").
--export([start_link/1,
+-export([start_link/5,
connection_supervisor/1,
channel_supervisor/1
]).
@@ -39,8 +39,8 @@
%%%=========================================================================
%%% API
%%%=========================================================================
-start_link(Options) ->
- supervisor:start_link(?MODULE, [Options]).
+start_link(Role, Address, Port, Profile, Options) ->
+ supervisor:start_link(?MODULE, [Role, Address, Port, Profile, Options]).
connection_supervisor(SupPid) ->
Children = supervisor:which_children(SupPid),
@@ -53,30 +53,23 @@ channel_supervisor(SupPid) ->
%%%=========================================================================
%%% Supervisor callback
%%%=========================================================================
--spec init( [term()] ) -> {ok,{supervisor:sup_flags(),[supervisor:child_spec()]}} | ignore .
-
-init([Options]) ->
+init([Role, Address, Port, Profile, Options]) ->
RestartStrategy = one_for_all,
MaxR = 0,
MaxT = 3600,
- Children = child_specs(Options),
+ Children = child_specs(Role, Address, Port, Profile, Options),
{ok, {{RestartStrategy, MaxR, MaxT}, Children}}.
%%%=========================================================================
%%% Internal functions
%%%=========================================================================
-child_specs(Options) ->
- case ?GET_INTERNAL_OPT(role, Options) of
- client ->
- [];
- server ->
- [ssh_channel_child_spec(Options), ssh_connectinon_child_spec(Options)]
- end.
+child_specs(client, _Address, _Port, _Profile, _Options) ->
+ [];
+child_specs(server, Address, Port, Profile, Options) ->
+ [ssh_channel_child_spec(server, Address, Port, Profile, Options),
+ ssh_connection_child_spec(server, Address, Port, Profile, Options)].
-ssh_connectinon_child_spec(Options) ->
- Address = ?GET_INTERNAL_OPT(address, Options),
- Port = ?GET_INTERNAL_OPT(port, Options),
- Role = ?GET_INTERNAL_OPT(role, Options),
+ssh_connection_child_spec(Role, Address, Port, _Profile, Options) ->
Name = id(Role, ssh_connection_sup, Address, Port),
StartFunc = {ssh_connection_sup, start_link, [Options]},
Restart = temporary,
@@ -85,10 +78,7 @@ ssh_connectinon_child_spec(Options) ->
Type = supervisor,
{Name, StartFunc, Restart, Shutdown, Type, Modules}.
-ssh_channel_child_spec(Options) ->
- Address = ?GET_INTERNAL_OPT(address, Options),
- Port = ?GET_INTERNAL_OPT(port, Options),
- Role = ?GET_INTERNAL_OPT(role, Options),
+ssh_channel_child_spec(Role, Address, Port, _Profile, Options) ->
Name = id(Role, ssh_channel_sup, Address, Port),
StartFunc = {ssh_channel_sup, start_link, [Options]},
Restart = temporary,
diff --git a/lib/ssh/src/ssh_sup.erl b/lib/ssh/src/ssh_sup.erl
index 8b57387589..5463401dcd 100644
--- a/lib/ssh/src/ssh_sup.erl
+++ b/lib/ssh/src/ssh_sup.erl
@@ -31,63 +31,20 @@
%%%=========================================================================
%%% Supervisor callback
%%%=========================================================================
--spec init( [term()] ) -> {ok,{supervisor:sup_flags(),[supervisor:child_spec()]}} | ignore .
-
-init([]) ->
+init(_) ->
SupFlags = {one_for_one, 10, 3600},
- Children = children(),
+ Children = [child_spec(sshd_sup), child_spec(sshc_sup)], %%children(),
{ok, {SupFlags, Children}}.
%%%=========================================================================
%%% Internal functions
%%%=========================================================================
-get_services() ->
- case (catch application:get_env(ssh, services)) of
- {ok, Services} ->
- Services;
- _ ->
- []
- end.
-
-children() ->
- Services = get_services(),
- Clients = [Service || Service <- Services, is_client(Service)],
- Servers = [Service || Service <- Services, is_server(Service)],
-
- [server_child_spec(Servers), client_child_spec(Clients)].
-
-server_child_spec(Servers) ->
- Name = sshd_sup,
- StartFunc = {sshd_sup, start_link, [Servers]},
+child_spec(Name) ->
+ StartFunc = {Name, start_link, []},
Restart = permanent,
Shutdown = infinity,
- Modules = [sshd_sup],
+ Modules = [Name],
Type = supervisor,
{Name, StartFunc, Restart, Shutdown, Type, Modules}.
-client_child_spec(Clients) ->
- Name = sshc_sup,
- StartFunc = {sshc_sup, start_link, [Clients]},
- Restart = permanent,
- Shutdown = infinity,
- Modules = [sshc_sup],
- Type = supervisor,
- {Name, StartFunc, Restart, Shutdown, Type, Modules}.
-
-is_server({sftpd, _}) ->
- true;
-is_server({shelld, _}) ->
- true;
-is_server(_) ->
- false.
-
-is_client({sftpc, _}) ->
- true;
-is_client({shellc, _}) ->
- true;
-is_client(_) ->
- false.
-
-
-
diff --git a/lib/ssh/src/ssh_system_sup.erl b/lib/ssh/src/ssh_system_sup.erl
index 4083f666c3..a923b5ef71 100644
--- a/lib/ssh/src/ssh_system_sup.erl
+++ b/lib/ssh/src/ssh_system_sup.erl
@@ -31,12 +31,12 @@
-include("ssh.hrl").
--export([start_link/1, stop_listener/1,
+-export([start_link/4, stop_listener/1,
stop_listener/3, stop_system/1,
stop_system/3, system_supervisor/3,
subsystem_supervisor/1, channel_supervisor/1,
connection_supervisor/1,
- acceptor_supervisor/1, start_subsystem/2, restart_subsystem/3,
+ acceptor_supervisor/1, start_subsystem/6, restart_subsystem/3,
restart_acceptor/3, stop_subsystem/2]).
%% Supervisor callback
@@ -45,12 +45,9 @@
%%%=========================================================================
%%% Internal API
%%%=========================================================================
-start_link(Options) ->
- Address = ?GET_INTERNAL_OPT(address, Options),
- Port = ?GET_INTERNAL_OPT(port, Options),
- Profile = ?GET_OPT(profile, Options),
+start_link(Address, Port, Profile, Options) ->
Name = make_name(Address, Port, Profile),
- supervisor:start_link({local, Name}, ?MODULE, [Options]).
+ supervisor:start_link({local, Name}, ?MODULE, [Address, Port, Profile, Options]).
stop_listener(SysSup) ->
stop_acceptor(SysSup).
@@ -86,8 +83,8 @@ connection_supervisor(SystemSup) ->
acceptor_supervisor(SystemSup) ->
ssh_acceptor_sup(supervisor:which_children(SystemSup)).
-start_subsystem(SystemSup, Options) ->
- Spec = ssh_subsystem_child_spec(Options),
+start_subsystem(SystemSup, Role, Address, Port, Profile, Options) ->
+ Spec = ssh_subsystem_child_spec(Role, Address, Port, Profile, Options),
supervisor:start_child(SystemSup, Spec).
stop_subsystem(SystemSup, SubSys) ->
@@ -125,14 +122,12 @@ restart_acceptor(Address, Port, Profile) ->
%%%=========================================================================
%%% Supervisor callback
%%%=========================================================================
--spec init( [term()] ) -> {ok,{supervisor:sup_flags(),[supervisor:child_spec()]}} | ignore .
-
-init([Options]) ->
+init([Address, Port, Profile, Options]) ->
RestartStrategy = one_for_one,
MaxR = 0,
MaxT = 3600,
Children = case ?GET_INTERNAL_OPT(connected_socket,Options,undefined) of
- undefined -> child_specs(Options);
+ undefined -> child_specs(Address, Port, Profile, Options);
_ -> []
end,
{ok, {{RestartStrategy, MaxR, MaxT}, Children}}.
@@ -140,24 +135,21 @@ init([Options]) ->
%%%=========================================================================
%%% Internal functions
%%%=========================================================================
-child_specs(Options) ->
- [ssh_acceptor_child_spec(Options)].
+child_specs(Address, Port, Profile, Options) ->
+ [ssh_acceptor_child_spec(Address, Port, Profile, Options)].
-ssh_acceptor_child_spec(Options) ->
- Address = ?GET_INTERNAL_OPT(address, Options),
- Port = ?GET_INTERNAL_OPT(port, Options),
- Profile = ?GET_OPT(profile, Options),
+ssh_acceptor_child_spec(Address, Port, Profile, Options) ->
Name = id(ssh_acceptor_sup, Address, Port, Profile),
- StartFunc = {ssh_acceptor_sup, start_link, [Options]},
+ StartFunc = {ssh_acceptor_sup, start_link, [Address, Port, Profile, Options]},
Restart = transient,
Shutdown = infinity,
Modules = [ssh_acceptor_sup],
Type = supervisor,
{Name, StartFunc, Restart, Shutdown, Type, Modules}.
-ssh_subsystem_child_spec(Options) ->
+ssh_subsystem_child_spec(Role, Address, Port, Profile, Options) ->
Name = make_ref(),
- StartFunc = {ssh_subsystem_sup, start_link, [Options]},
+ StartFunc = {ssh_subsystem_sup, start_link, [Role, Address, Port, Profile, Options]},
Restart = temporary,
Shutdown = infinity,
Modules = [ssh_subsystem_sup],
@@ -169,7 +161,12 @@ id(Sup, Address, Port, Profile) ->
{Sup, Address, Port, Profile}.
make_name(Address, Port, Profile) ->
- list_to_atom(lists:flatten(io_lib:format("ssh_system_~s_~p_~p_sup", [Address, Port, Profile]))).
+ list_to_atom(lists:flatten(io_lib:format("ssh_system_~s_~p_~p_sup", [fmt_host(Address), Port, Profile]))).
+
+fmt_host(IP) when is_tuple(IP) -> inet:ntoa(IP);
+fmt_host(A) when is_atom(A) -> A;
+fmt_host(S) when is_list(S) -> S.
+
ssh_subsystem_sup([{_, Child, _, [ssh_subsystem_sup]} | _]) ->
Child;
diff --git a/lib/ssh/src/sshc_sup.erl b/lib/ssh/src/sshc_sup.erl
index 15858f36e1..9aab9d57e9 100644
--- a/lib/ssh/src/sshc_sup.erl
+++ b/lib/ssh/src/sshc_sup.erl
@@ -27,7 +27,7 @@
-behaviour(supervisor).
--export([start_link/1, start_child/1, stop_child/1]).
+-export([start_link/0, start_child/1, stop_child/1]).
%% Supervisor callback
-export([init/1]).
@@ -35,8 +35,8 @@
%%%=========================================================================
%%% API
%%%=========================================================================
-start_link(Args) ->
- supervisor:start_link({local, ?MODULE}, ?MODULE, [Args]).
+start_link() ->
+ supervisor:start_link({local, ?MODULE}, ?MODULE, []).
start_child(Args) ->
supervisor:start_child(?MODULE, Args).
@@ -51,18 +51,16 @@ stop_child(Client) ->
%%%=========================================================================
%%% Supervisor callback
%%%=========================================================================
--spec init( [term()] ) -> {ok,{supervisor:sup_flags(),[supervisor:child_spec()]}} | ignore .
-
-init(Args) ->
+init(_) ->
RestartStrategy = simple_one_for_one,
MaxR = 0,
MaxT = 3600,
- {ok, {{RestartStrategy, MaxR, MaxT}, [child_spec(Args)]}}.
+ {ok, {{RestartStrategy, MaxR, MaxT}, [child_spec()]}}.
%%%=========================================================================
%%% Internal functions
%%%=========================================================================
-child_spec(_) ->
+child_spec() ->
Name = undefined, % As simple_one_for_one is used.
StartFunc = {ssh_connection_handler, start_link, []},
Restart = temporary,
diff --git a/lib/ssh/src/sshd_sup.erl b/lib/ssh/src/sshd_sup.erl
index 791456839d..d4805e9465 100644
--- a/lib/ssh/src/sshd_sup.erl
+++ b/lib/ssh/src/sshd_sup.erl
@@ -29,8 +29,11 @@
-include("ssh.hrl").
--export([start_link/1, start_child/1, stop_child/1,
- stop_child/3, system_name/1]).
+-export([start_link/0,
+ start_child/4,
+ stop_child/1,
+ stop_child/3,
+ system_name/1]).
%% Supervisor callback
-export([init/1]).
@@ -38,27 +41,23 @@
%%%=========================================================================
%%% API
%%%=========================================================================
-start_link(Servers) ->
- supervisor:start_link({local, ?MODULE}, ?MODULE, [Servers]).
+start_link() ->
+ supervisor:start_link({local, ?MODULE}, ?MODULE, []).
-start_child(Options) ->
- Address = ?GET_INTERNAL_OPT(address, Options),
- Port = ?GET_INTERNAL_OPT(port, Options),
- Profile = ?GET_OPT(profile, Options),
+start_child(Address, Port, Profile, Options) ->
+io:format("~p:~p ~p:~p~n",[?MODULE,?LINE,Address, Port]),
case ssh_system_sup:system_supervisor(Address, Port, Profile) of
undefined ->
- Spec = child_spec(Address, Port, Options),
- case supervisor:start_child(?MODULE, Spec) of
- {error, already_present} ->
- Name = id(Address, Port, Profile),
- supervisor:delete_child(?MODULE, Name),
- supervisor:start_child(?MODULE, Spec);
- Reply ->
- Reply
- end;
+io:format("~p:~p undefined~n",[?MODULE,?LINE]),
+ Spec = child_spec(Address, Port, Profile, Options),
+ Reply = supervisor:start_child(?MODULE, Spec),
+io:format("~p:~p Reply=~p~n",[?MODULE,?LINE,Reply]),
+ Reply;
Pid ->
+io:format("~p:~p Pid=~p~n",[?MODULE,?LINE,Pid]),
AccPid = ssh_system_sup:acceptor_supervisor(Pid),
- ssh_acceptor_sup:start_child(AccPid, Options)
+ ssh_acceptor_sup:start_child(AccPid, Address, Port, Profile, Options),
+ {ok,Pid}
end.
stop_child(Name) ->
@@ -75,27 +74,15 @@ system_name(SysSup) ->
%%%=========================================================================
%%% Supervisor callback
%%%=========================================================================
--spec init( [term()] ) -> {ok,{supervisor:sup_flags(),[supervisor:child_spec()]}} | ignore .
-
-init([Servers]) ->
- RestartStrategy = one_for_one,
- MaxR = 10,
- MaxT = 3600,
- Fun = fun(ServerOpts) ->
- Address = ?GET_INTERNAL_OPT(address, ServerOpts),
- Port = ?GET_INTERNAL_OPT(port, ServerOpts),
- child_spec(Address, Port, ServerOpts)
- end,
- Children = lists:map(Fun, Servers),
- {ok, {{RestartStrategy, MaxR, MaxT}, Children}}.
+init(_) ->
+ {ok, {{one_for_one, 10, 3600}, []}}.
%%%=========================================================================
%%% Internal functions
%%%=========================================================================
-child_spec(Address, Port, Options) ->
- Profile = ?GET_OPT(profile, Options),
+child_spec(Address, Port, Profile, Options) ->
Name = id(Address, Port,Profile),
- StartFunc = {ssh_system_sup, start_link, [Options]},
+ StartFunc = {ssh_system_sup, start_link, [Address, Port, Profile, Options]},
Restart = temporary,
Shutdown = infinity,
Modules = [ssh_system_sup],
--
cgit v1.2.3
From 8f4bb9b0bd3aed663521371726ea3ec460e231a0 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 23 Mar 2017 16:53:53 +0100
Subject: ssh: Mappify supervisors
---
lib/ssh/src/ssh_acceptor_sup.erl | 30 ++++---
lib/ssh/src/ssh_connection_sup.erl | 28 +++----
lib/ssh/src/ssh_subsystem_sup.erl | 39 ++++-----
lib/ssh/src/ssh_sup.erl | 30 +++----
lib/ssh/src/ssh_system_sup.erl | 159 ++++++++++++++++---------------------
lib/ssh/src/sshc_sup.erl | 35 ++++----
lib/ssh/src/sshd_sup.erl | 73 +++++++++--------
7 files changed, 190 insertions(+), 204 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_acceptor_sup.erl b/lib/ssh/src/ssh_acceptor_sup.erl
index 4606107f56..3ad842f98c 100644
--- a/lib/ssh/src/ssh_acceptor_sup.erl
+++ b/lib/ssh/src/ssh_acceptor_sup.erl
@@ -48,9 +48,12 @@ start_child(AccSup, Address, Port, Profile, Options) ->
Spec = child_spec(Address, Port, Profile, Options),
case supervisor:start_child(AccSup, Spec) of
{error, already_present} ->
+ %% Is this ever called?
stop_child(AccSup, Address, Port, Profile),
supervisor:start_child(AccSup, Spec);
Reply ->
+ %% Reply = {ok,SystemSupPid} when the user calls ssh:daemon
+ %% after having called ssh:stop_listening
Reply
end.
@@ -67,24 +70,27 @@ stop_child(AccSup, Address, Port, Profile) ->
%%% Supervisor callback
%%%=========================================================================
init([Address, Port, Profile, Options]) ->
- RestartStrategy = one_for_one,
- MaxR = 10,
- MaxT = 3600,
- Children = [child_spec(Address, Port, Profile, Options)],
- {ok, {{RestartStrategy, MaxR, MaxT}, Children}}.
+ %% Initial start of ssh_acceptor_sup for this port or new start after
+ %% ssh:stop_daemon
+ SupFlags = #{strategy => one_for_one,
+ intensity => 10,
+ period => 3600
+ },
+ ChildSpecs = [child_spec(Address, Port, Profile, Options)],
+ {ok, {SupFlags,ChildSpecs}}.
%%%=========================================================================
%%% Internal functions
%%%=========================================================================
child_spec(Address, Port, Profile, Options) ->
Timeout = ?GET_INTERNAL_OPT(timeout, Options, ?DEFAULT_TIMEOUT),
- Name = id(Address, Port, Profile),
- StartFunc = {ssh_acceptor, start_link, [Port, Address, Options, Timeout]},
- Restart = transient,
- Shutdown = brutal_kill,
- Modules = [ssh_acceptor],
- Type = worker,
- {Name, StartFunc, Restart, Shutdown, Type, Modules}.
+ #{id => id(Address, Port, Profile),
+ start => {ssh_acceptor, start_link, [Port, Address, Options, Timeout]},
+ restart => transient,
+ shutdown => brutal_kill,
+ type => worker,
+ modules => [ssh_acceptor]
+ }.
id(Address, Port, Profile) ->
{ssh_acceptor_sup, Address, Port, Profile}.
diff --git a/lib/ssh/src/ssh_connection_sup.erl b/lib/ssh/src/ssh_connection_sup.erl
index 0f54053f52..fad796f196 100644
--- a/lib/ssh/src/ssh_connection_sup.erl
+++ b/lib/ssh/src/ssh_connection_sup.erl
@@ -45,19 +45,17 @@ start_child(Sup, Args) ->
%%%=========================================================================
%%% Supervisor callback
%%%=========================================================================
--spec init( [term()] ) -> {ok,{supervisor:sup_flags(),[supervisor:child_spec()]}} | ignore .
-
init(_) ->
- RestartStrategy = simple_one_for_one,
- MaxR = 0,
- MaxT = 3600,
-
- Name = undefined, % As simple_one_for_one is used.
- StartFunc = {ssh_connection_handler, start_link, []},
- Restart = temporary, % E.g. should not be restarted
- Shutdown = 4000,
- Modules = [ssh_connection_handler],
- Type = worker,
-
- ChildSpec = {Name, StartFunc, Restart, Shutdown, Type, Modules},
- {ok, {{RestartStrategy, MaxR, MaxT}, [ChildSpec]}}.
+ SupFlags = #{strategy => simple_one_for_one,
+ intensity => 0,
+ period => 3600
+ },
+ ChildSpecs = [#{id => undefined, % As simple_one_for_one is used.
+ start => {ssh_connection_handler, start_link, []},
+ restart => temporary,
+ shutdown => 4000,
+ type => worker,
+ modules => [ssh_connection_handler]
+ }
+ ],
+ {ok, {SupFlags,ChildSpecs}}.
diff --git a/lib/ssh/src/ssh_subsystem_sup.erl b/lib/ssh/src/ssh_subsystem_sup.erl
index c5ab422265..cf409ade6b 100644
--- a/lib/ssh/src/ssh_subsystem_sup.erl
+++ b/lib/ssh/src/ssh_subsystem_sup.erl
@@ -54,11 +54,12 @@ channel_supervisor(SupPid) ->
%%% Supervisor callback
%%%=========================================================================
init([Role, Address, Port, Profile, Options]) ->
- RestartStrategy = one_for_all,
- MaxR = 0,
- MaxT = 3600,
- Children = child_specs(Role, Address, Port, Profile, Options),
- {ok, {{RestartStrategy, MaxR, MaxT}, Children}}.
+ SupFlags = #{strategy => one_for_all,
+ intensity => 0,
+ period => 3600
+ },
+ ChildSpecs = child_specs(Role, Address, Port, Profile, Options),
+ {ok, {SupFlags,ChildSpecs}}.
%%%=========================================================================
%%% Internal functions
@@ -70,22 +71,22 @@ child_specs(server, Address, Port, Profile, Options) ->
ssh_connection_child_spec(server, Address, Port, Profile, Options)].
ssh_connection_child_spec(Role, Address, Port, _Profile, Options) ->
- Name = id(Role, ssh_connection_sup, Address, Port),
- StartFunc = {ssh_connection_sup, start_link, [Options]},
- Restart = temporary,
- Shutdown = 5000,
- Modules = [ssh_connection_sup],
- Type = supervisor,
- {Name, StartFunc, Restart, Shutdown, Type, Modules}.
+ #{id => id(Role, ssh_connection_sup, Address, Port),
+ start => {ssh_connection_sup, start_link, [Options]},
+ restart => temporary,
+ shutdown => 5000,
+ type => supervisor,
+ modules => [ssh_connection_sup]
+ }.
ssh_channel_child_spec(Role, Address, Port, _Profile, Options) ->
- Name = id(Role, ssh_channel_sup, Address, Port),
- StartFunc = {ssh_channel_sup, start_link, [Options]},
- Restart = temporary,
- Shutdown = infinity,
- Modules = [ssh_channel_sup],
- Type = supervisor,
- {Name, StartFunc, Restart, Shutdown, Type, Modules}.
+ #{id => id(Role, ssh_channel_sup, Address, Port),
+ start => {ssh_channel_sup, start_link, [Options]},
+ restart => temporary,
+ shutdown => infinity,
+ type => supervisor,
+ modules => [ssh_channel_sup]
+ }.
id(Role, Sup, Address, Port) ->
{Role, Sup, Address, Port}.
diff --git a/lib/ssh/src/ssh_sup.erl b/lib/ssh/src/ssh_sup.erl
index 5463401dcd..6be809b1bd 100644
--- a/lib/ssh/src/ssh_sup.erl
+++ b/lib/ssh/src/ssh_sup.erl
@@ -32,19 +32,19 @@
%%% Supervisor callback
%%%=========================================================================
init(_) ->
- SupFlags = {one_for_one, 10, 3600},
- Children = [child_spec(sshd_sup), child_spec(sshc_sup)], %%children(),
- {ok, {SupFlags, Children}}.
-
-%%%=========================================================================
-%%% Internal functions
-%%%=========================================================================
-child_spec(Name) ->
- StartFunc = {Name, start_link, []},
- Restart = permanent,
- Shutdown = infinity,
- Modules = [Name],
- Type = supervisor,
- {Name, StartFunc, Restart, Shutdown, Type, Modules}.
-
+ SupFlags = #{strategy => one_for_one,
+ intensity => 10,
+ period => 3600
+ },
+ ChildSpecs = [#{id => Module,
+ start => {Module, start_link, []},
+ restart => permanent,
+ shutdown => brutal_kill,
+ type => supervisor,
+ modules => [Module]
+ }
+ || Module <- [sshd_sup,
+ sshc_sup]
+ ],
+ {ok, {SupFlags,ChildSpecs}}.
diff --git a/lib/ssh/src/ssh_system_sup.erl b/lib/ssh/src/ssh_system_sup.erl
index a923b5ef71..84b4cd3241 100644
--- a/lib/ssh/src/ssh_system_sup.erl
+++ b/lib/ssh/src/ssh_system_sup.erl
@@ -21,7 +21,7 @@
%%
%%----------------------------------------------------------------------
%% Purpose: The ssh server instance supervisor, an instans of this supervisor
-%% exists for every ip-address and port combination, hangs under
+%% exists for every ip-address and port combination, hangs under
%% sshd_sup.
%%----------------------------------------------------------------------
@@ -34,58 +34,100 @@
-export([start_link/4, stop_listener/1,
stop_listener/3, stop_system/1,
stop_system/3, system_supervisor/3,
- subsystem_supervisor/1, channel_supervisor/1,
- connection_supervisor/1,
- acceptor_supervisor/1, start_subsystem/6, restart_subsystem/3,
- restart_acceptor/3, stop_subsystem/2]).
+ subsystem_supervisor/1, channel_supervisor/1,
+ connection_supervisor/1,
+ acceptor_supervisor/1, start_subsystem/6,
+ stop_subsystem/2]).
%% Supervisor callback
-export([init/1]).
%%%=========================================================================
-%%% Internal API
+%%% API
%%%=========================================================================
start_link(Address, Port, Profile, Options) ->
Name = make_name(Address, Port, Profile),
supervisor:start_link({local, Name}, ?MODULE, [Address, Port, Profile, Options]).
-stop_listener(SysSup) ->
- stop_acceptor(SysSup).
+%%%=========================================================================
+%%% Supervisor callback
+%%%=========================================================================
+init([Address, Port, Profile, Options]) ->
+ SupFlags = #{strategy => one_for_one,
+ intensity => 0,
+ period => 3600
+ },
+ ChildSpecs =
+ case ?GET_INTERNAL_OPT(connected_socket,Options,undefined) of
+ undefined ->
+ [#{id => id(ssh_acceptor_sup, Address, Port, Profile),
+ start => {ssh_acceptor_sup, start_link, [Address, Port, Profile, Options]},
+ restart => transient,
+ shutdown => infinity,
+ type => supervisor,
+ modules => [ssh_acceptor_sup]
+ }];
+ _ ->
+ []
+ end,
+ {ok, {SupFlags,ChildSpecs}}.
+
+%%%=========================================================================
+%%% Service API
+%%%=========================================================================
+stop_listener(SystemSup) ->
+ {Name, AcceptorSup, _, _} = lookup(ssh_acceptor_sup, SystemSup),
+ case supervisor:terminate_child(AcceptorSup, Name) of
+ ok ->
+ supervisor:delete_child(AcceptorSup, Name);
+ Error ->
+ Error
+ end.
stop_listener(Address, Port, Profile) ->
- Name = make_name(Address, Port, Profile),
- stop_acceptor(whereis(Name)).
-
+ stop_listener(
+ system_supervisor(Address, Port, Profile)).
+
+
stop_system(SysSup) ->
- Name = sshd_sup:system_name(SysSup),
- spawn(fun() -> sshd_sup:stop_child(Name) end),
+ spawn(fun() -> sshd_sup:stop_child(SysSup) end),
ok.
-stop_system(Address, Port, Profile) ->
+stop_system(Address, Port, Profile) ->
spawn(fun() -> sshd_sup:stop_child(Address, Port, Profile) end),
ok.
+
system_supervisor(Address, Port, Profile) ->
Name = make_name(Address, Port, Profile),
whereis(Name).
subsystem_supervisor(SystemSup) ->
- ssh_subsystem_sup(supervisor:which_children(SystemSup)).
+ {_, Child, _, _} = lookup(ssh_subsystem_sup, SystemSup),
+ Child.
channel_supervisor(SystemSup) ->
- SubSysSup = ssh_subsystem_sup(supervisor:which_children(SystemSup)),
- ssh_subsystem_sup:channel_supervisor(SubSysSup).
+ ssh_subsystem_sup:channel_supervisor(
+ subsystem_supervisor(SystemSup)).
connection_supervisor(SystemSup) ->
- SubSysSup = ssh_subsystem_sup(supervisor:which_children(SystemSup)),
- ssh_subsystem_sup:connection_supervisor(SubSysSup).
+ ssh_subsystem_sup:connection_supervisor(
+ subsystem_supervisor(SystemSup)).
acceptor_supervisor(SystemSup) ->
- ssh_acceptor_sup(supervisor:which_children(SystemSup)).
+ {_, Child, _, _} = lookup(ssh_acceptor_sup, SystemSup),
+ Child.
+
start_subsystem(SystemSup, Role, Address, Port, Profile, Options) ->
- Spec = ssh_subsystem_child_spec(Role, Address, Port, Profile, Options),
- supervisor:start_child(SystemSup, Spec).
+ SubsystemSpec =
+ #{id => make_ref(),
+ start => {ssh_subsystem_sup, start_link, [Role, Address, Port, Profile, Options]},
+ restart => temporary,
+ shutdown => infinity,
+ type => supervisor,
+ modules => [ssh_subsystem_sup]},
+ supervisor:start_child(SystemSup, SubsystemSpec).
stop_subsystem(SystemSup, SubSys) ->
case catch lists:keyfind(SubSys, 2, supervisor:which_children(SystemSup)) of
@@ -103,60 +145,9 @@ stop_subsystem(SystemSup, SubSys) ->
ok
end.
-
-restart_subsystem(Address, Port, Profile) ->
- SysSupName = make_name(Address, Port, Profile),
- SubSysName = id(ssh_subsystem_sup, Address, Port, Profile),
- case supervisor:terminate_child(SysSupName, SubSysName) of
- ok ->
- supervisor:restart_child(SysSupName, SubSysName);
- Error ->
- Error
- end.
-
-restart_acceptor(Address, Port, Profile) ->
- SysSupName = make_name(Address, Port, Profile),
- AcceptorName = id(ssh_acceptor_sup, Address, Port, Profile),
- supervisor:restart_child(SysSupName, AcceptorName).
-
-%%%=========================================================================
-%%% Supervisor callback
-%%%=========================================================================
-init([Address, Port, Profile, Options]) ->
- RestartStrategy = one_for_one,
- MaxR = 0,
- MaxT = 3600,
- Children = case ?GET_INTERNAL_OPT(connected_socket,Options,undefined) of
- undefined -> child_specs(Address, Port, Profile, Options);
- _ -> []
- end,
- {ok, {{RestartStrategy, MaxR, MaxT}, Children}}.
-
%%%=========================================================================
%%% Internal functions
%%%=========================================================================
-child_specs(Address, Port, Profile, Options) ->
- [ssh_acceptor_child_spec(Address, Port, Profile, Options)].
-
-ssh_acceptor_child_spec(Address, Port, Profile, Options) ->
- Name = id(ssh_acceptor_sup, Address, Port, Profile),
- StartFunc = {ssh_acceptor_sup, start_link, [Address, Port, Profile, Options]},
- Restart = transient,
- Shutdown = infinity,
- Modules = [ssh_acceptor_sup],
- Type = supervisor,
- {Name, StartFunc, Restart, Shutdown, Type, Modules}.
-
-ssh_subsystem_child_spec(Role, Address, Port, Profile, Options) ->
- Name = make_ref(),
- StartFunc = {ssh_subsystem_sup, start_link, [Role, Address, Port, Profile, Options]},
- Restart = temporary,
- Shutdown = infinity,
- Modules = [ssh_subsystem_sup],
- Type = supervisor,
- {Name, StartFunc, Restart, Shutdown, Type, Modules}.
-
-
id(Sup, Address, Port, Profile) ->
{Sup, Address, Port, Profile}.
@@ -168,23 +159,7 @@ fmt_host(A) when is_atom(A) -> A;
fmt_host(S) when is_list(S) -> S.
-ssh_subsystem_sup([{_, Child, _, [ssh_subsystem_sup]} | _]) ->
- Child;
-ssh_subsystem_sup([_ | Rest]) ->
- ssh_subsystem_sup(Rest).
-
-ssh_acceptor_sup([{_, Child, _, [ssh_acceptor_sup]} | _]) ->
- Child;
-ssh_acceptor_sup([_ | Rest]) ->
- ssh_acceptor_sup(Rest).
+lookup(SupModule, SystemSup) ->
+ lists:keyfind([SupModule], 4,
+ supervisor:which_children(SystemSup)).
-stop_acceptor(Sup) ->
- [{Name, AcceptorSup}] =
- [{SupName, ASup} || {SupName, ASup, _, [ssh_acceptor_sup]} <-
- supervisor:which_children(Sup)],
- case supervisor:terminate_child(AcceptorSup, Name) of
- ok ->
- supervisor:delete_child(AcceptorSup, Name);
- Error ->
- Error
- end.
diff --git a/lib/ssh/src/sshc_sup.erl b/lib/ssh/src/sshc_sup.erl
index 9aab9d57e9..c71b81dc6d 100644
--- a/lib/ssh/src/sshc_sup.erl
+++ b/lib/ssh/src/sshc_sup.erl
@@ -32,18 +32,20 @@
%% Supervisor callback
-export([init/1]).
+-define(SSHC_SUP, ?MODULE).
+
%%%=========================================================================
%%% API
%%%=========================================================================
start_link() ->
- supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+ supervisor:start_link({local,?SSHC_SUP}, ?MODULE, []).
start_child(Args) ->
supervisor:start_child(?MODULE, Args).
stop_child(Client) ->
spawn(fun() ->
- ClientSup = whereis(?MODULE),
+ ClientSup = whereis(?SSHC_SUP),
supervisor:terminate_child(ClientSup, Client)
end),
ok.
@@ -52,19 +54,16 @@ stop_child(Client) ->
%%% Supervisor callback
%%%=========================================================================
init(_) ->
- RestartStrategy = simple_one_for_one,
- MaxR = 0,
- MaxT = 3600,
- {ok, {{RestartStrategy, MaxR, MaxT}, [child_spec()]}}.
-
-%%%=========================================================================
-%%% Internal functions
-%%%=========================================================================
-child_spec() ->
- Name = undefined, % As simple_one_for_one is used.
- StartFunc = {ssh_connection_handler, start_link, []},
- Restart = temporary,
- Shutdown = 4000,
- Modules = [ssh_connection_handler],
- Type = worker,
- {Name, StartFunc, Restart, Shutdown, Type, Modules}.
+ SupFlags = #{strategy => simple_one_for_one,
+ intensity => 0,
+ period => 3600
+ },
+ ChildSpecs = [#{id => undefined, % As simple_one_for_one is used.
+ start => {ssh_connection_handler, start_link, []},
+ restart => temporary,
+ shutdown => 4000,
+ type => worker,
+ modules => [ssh_connection_handler]
+ }
+ ],
+ {ok, {SupFlags,ChildSpecs}}.
diff --git a/lib/ssh/src/sshd_sup.erl b/lib/ssh/src/sshd_sup.erl
index d4805e9465..449ba20d02 100644
--- a/lib/ssh/src/sshd_sup.erl
+++ b/lib/ssh/src/sshd_sup.erl
@@ -19,7 +19,7 @@
%%
%%
%%----------------------------------------------------------------------
-%% Purpose: The top supervisor for ssh servers hangs under
+%% Purpose: The top supervisor for ssh servers hangs under
%% ssh_sup.
%%----------------------------------------------------------------------
@@ -29,72 +29,79 @@
-include("ssh.hrl").
--export([start_link/0,
+-export([start_link/0,
start_child/4,
stop_child/1,
- stop_child/3,
- system_name/1]).
+ stop_child/3
+]).
%% Supervisor callback
-export([init/1]).
+-define(SSHD_SUP, ?MODULE).
+
%%%=========================================================================
%%% API
%%%=========================================================================
start_link() ->
- supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+ %% No children are start now. We wait until the user calls ssh:daemon
+ %% and uses start_child/4 to create the children
+ supervisor:start_link({local,?SSHD_SUP}, ?MODULE, []).
start_child(Address, Port, Profile, Options) ->
-io:format("~p:~p ~p:~p~n",[?MODULE,?LINE,Address, Port]),
case ssh_system_sup:system_supervisor(Address, Port, Profile) of
undefined ->
-io:format("~p:~p undefined~n",[?MODULE,?LINE]),
+ %% Here we start listening on a new Host/Port/Profile
Spec = child_spec(Address, Port, Profile, Options),
- Reply = supervisor:start_child(?MODULE, Spec),
-io:format("~p:~p Reply=~p~n",[?MODULE,?LINE,Reply]),
- Reply;
+ supervisor:start_child(?SSHD_SUP, Spec);
Pid ->
-io:format("~p:~p Pid=~p~n",[?MODULE,?LINE,Pid]),
+ %% Here we resume listening on a new Host/Port/Profile after
+ %% haveing stopped listening to he same with ssh:stop_listen(Pid)
AccPid = ssh_system_sup:acceptor_supervisor(Pid),
ssh_acceptor_sup:start_child(AccPid, Address, Port, Profile, Options),
{ok,Pid}
end.
-stop_child(Name) ->
- supervisor:terminate_child(?MODULE, Name).
+stop_child(ChildId) when is_tuple(ChildId) ->
+ supervisor:terminate_child(?SSHD_SUP, ChildId);
+stop_child(ChildPid) when is_pid(ChildPid)->
+ stop_child(system_name(ChildPid)).
-stop_child(Address, Port, Profile) ->
- Name = id(Address, Port, Profile),
- stop_child(Name).
-system_name(SysSup) ->
- Children = supervisor:which_children(sshd_sup),
- system_name(SysSup, Children).
+stop_child(Address, Port, Profile) ->
+ Id = id(Address, Port, Profile),
+ stop_child(Id).
%%%=========================================================================
%%% Supervisor callback
%%%=========================================================================
init(_) ->
- {ok, {{one_for_one, 10, 3600}, []}}.
+ SupFlags = #{strategy => one_for_one,
+ intensity => 10,
+ period => 3600
+ },
+ ChildSpecs = [
+ ],
+ {ok, {SupFlags,ChildSpecs}}.
%%%=========================================================================
%%% Internal functions
%%%=========================================================================
child_spec(Address, Port, Profile, Options) ->
- Name = id(Address, Port,Profile),
- StartFunc = {ssh_system_sup, start_link, [Address, Port, Profile, Options]},
- Restart = temporary,
- Shutdown = infinity,
- Modules = [ssh_system_sup],
- Type = supervisor,
- {Name, StartFunc, Restart, Shutdown, Type, Modules}.
+ #{id => id(Address, Port, Profile),
+ start => {ssh_system_sup, start_link, [Address, Port, Profile, Options]},
+ restart => temporary,
+ shutdown => infinity,
+ type => supervisor,
+ modules => [ssh_system_sup]
+ }.
id(Address, Port, Profile) ->
{server, ssh_system_sup, Address, Port, Profile}.
-system_name([], _ ) ->
- undefined;
-system_name(SysSup, [{Name, SysSup, _, _} | _]) ->
- Name;
-system_name(SysSup, [_ | Rest]) ->
- system_name(SysSup, Rest).
+system_name(SysSup) ->
+ case lists:keyfind(SysSup, 2, supervisor:which_children(?SSHD_SUP)) of
+ {Name, SysSup, _, _} -> Name;
+ false -> undefind
+ end.
+
--
cgit v1.2.3
From 92bdf870ec6509eb958535780b8655206478f7db Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Tue, 28 Mar 2017 17:20:46 +0200
Subject: ssh: change 'brutal_kill' to timeout'
---
lib/ssh/src/ssh_acceptor_sup.erl | 2 +-
lib/ssh/src/ssh_sup.erl | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_acceptor_sup.erl b/lib/ssh/src/ssh_acceptor_sup.erl
index 3ad842f98c..26defcfdbd 100644
--- a/lib/ssh/src/ssh_acceptor_sup.erl
+++ b/lib/ssh/src/ssh_acceptor_sup.erl
@@ -87,7 +87,7 @@ child_spec(Address, Port, Profile, Options) ->
#{id => id(Address, Port, Profile),
start => {ssh_acceptor, start_link, [Port, Address, Options, Timeout]},
restart => transient,
- shutdown => brutal_kill,
+ shutdown => 5500, %brutal_kill,
type => worker,
modules => [ssh_acceptor]
}.
diff --git a/lib/ssh/src/ssh_sup.erl b/lib/ssh/src/ssh_sup.erl
index 6be809b1bd..26574763e4 100644
--- a/lib/ssh/src/ssh_sup.erl
+++ b/lib/ssh/src/ssh_sup.erl
@@ -39,7 +39,7 @@ init(_) ->
ChildSpecs = [#{id => Module,
start => {Module, start_link, []},
restart => permanent,
- shutdown => brutal_kill,
+ shutdown => 4000, %brutal_kill,
type => supervisor,
modules => [Module]
}
--
cgit v1.2.3
From 3bed79615b9702f8335dbe75295c6610b097175e Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 29 Mar 2017 13:13:43 +0200
Subject: ssh: remove dead code and add comments
---
lib/ssh/src/ssh.erl | 55 ++++++++---------------------------------------------
1 file changed, 8 insertions(+), 47 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 680047dffd..aff143dc26 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -416,66 +416,27 @@ handle_daemon_args(IPaddr, Opts) when is_tuple(IPaddr) ->
IP -> {IPaddr, [{ip,IPaddr}|Opts--[{ip,IP}]]} %% Backward compatibility
end;
-handle_daemon_args(Address, Opts) when is_list(Address) ; is_atom(Address) ->
+handle_daemon_args(Address, Opts) when is_list(Address) ; % IP address in string or a domain
+ is_atom(Address) % domains could be atoms in inet
+ ->
IP = proplists:get_value(ip, Opts),
case inet:parse_strict_address(Address) of
+ %% check if Address is an IP-address
{ok, IP} -> {IP, Opts};
{ok, OtherIP} -> {OtherIP, [{ip,OtherIP}|Opts--[{ip,IP}]]};
_ ->
+ %% Not an IP-address. Check if it is a host name:
case inet:getaddr(Address, family(Opts)) of
{ok, IP} -> {Address, Opts};
{ok, OtherIP} -> {Address, [{ip,OtherIP}|Opts--[{ip,IP}]]};
- _ -> {Address, Opts}
- end
- end.
-
-
--ifdef(hulahopp).
-%% Check the Address parameter and set an ip-option in some cases. The
-%% Address parameter is left unchanged because ssh:stop_listener and
-%% ssh:stop_daemon needs to find the system supervisor by name
-
-handle_daemon_args(any, Opts) ->
- %% Listen to 0.0.0.0. The caller may have set an ip-option. Trust
- %% that one in such a case.
- {any, Opts};
-
-handle_daemon_args(loopback, Opts) ->
- %% Listen to a loopback address. Let the underlying layers decide
- %% in case the caller hasn't set the ip-option.
- {loopback, ensure_ip_option(loopback,Opts)};
-
-handle_daemon_args(IP, Opts) when is_tuple(IP) ->
- %% An IP address in Erlang tuple format:
- {IP, ensure_ip_option(IP,Opts)};
-
-handle_daemon_args(Address, Opts) when is_list(Address) ; is_atom(Address) ->
- %% This might be a host name, an FQDN, an IP address in string format ("127.1.1.1")
- %% etc. It might be a string or an atom since inet:hostname() is defined in that way
- case inet:parse_strict_address(Address) of
- {ok, IP} ->
- {Address, ensure_ip_option(IP,Opts)};
- _ ->
- %% Try to lookup as a hostname:
- case inet:getaddr(Address, family(Opts)) of
- {ok, IP} ->
- {Address, ensure_ip_option(IP,Opts)};
_ ->
- %% Give up and let the underlying system handle this
+ %% Not a Host name and not an IP address, let
+ %% inet and the OS later figure out what it
+ %% could be
{Address, Opts}
end
end.
-
-%% Add an ip-option if not already present.
-ensure_ip_option(Address, Opts) ->
- case proplists:get_value(ip, Opts) of
- undefined -> [{ip,Address}|Opts];
- _ -> Opts
- end.
--endif.
-
-
%% Has the caller indicated the address family?
family(Opts) ->
family(Opts, inet).
--
cgit v1.2.3
From a9fc169d5d0ca63a3062800429e3a16169901ab3 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 29 Mar 2017 15:08:48 +0200
Subject: ssh: Change handling of IP addresses, 'any' and names in sup
structure
---
lib/ssh/src/ssh.erl | 100 ++++++++++++++++++++++++++++++++++++----------------
1 file changed, 70 insertions(+), 30 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index aff143dc26..8c802d46eb 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -26,6 +26,7 @@
-include("ssh_connect.hrl").
-include_lib("public_key/include/public_key.hrl").
-include_lib("kernel/include/file.hrl").
+-include_lib("kernel/include/inet.hrl").
-export([start/0, start/1, stop/0,
connect/2, connect/3, connect/4,
@@ -120,7 +121,7 @@ connect(Host, Port, UserOptions) when is_integer(Port),
is_list(UserOptions) ->
connect(Host, Port, UserOptions, infinity).
-connect(Host, Port, UserOptions, Timeout) when is_integer(Port),
+connect(Host0, Port, UserOptions, Timeout) when is_integer(Port),
Port>0,
is_list(UserOptions) ->
case ssh_options:handle_options(client, UserOptions) of
@@ -130,6 +131,7 @@ connect(Host, Port, UserOptions, Timeout) when is_integer(Port),
{_, Transport, _} = TransportOpts = ?GET_OPT(transport, Options),
ConnectionTimeout = ?GET_OPT(connect_timeout, Options),
SocketOpts = [{active,false} | ?GET_OPT(socket_options,Options)],
+ Host = mangle_connect_address(Host0, SocketOpts),
try Transport:connect(Host, Port, SocketOpts, ConnectionTimeout) of
{ok, Socket} ->
Opts = ?PUT_INTERNAL_OPT([{user_pid,self()}, {host,Host}], Options),
@@ -227,7 +229,7 @@ daemon(Host0, Port0, UserOptions0) when 0 =< Port0, Port0 =< 65535 ->
try
{Host1, UserOptions} = handle_daemon_args(Host0, UserOptions0),
#{} = Options0 = ssh_options:handle_options(server, UserOptions),
-
+
{{Host,Port}, ListenSocket} =
open_listen_socket(Host1, Port0, Options0),
@@ -266,27 +268,23 @@ daemon(Host0, Port0, UserOptions0) when 0 =< Port0, Port0 =< 65535 ->
daemon_info(Pid) ->
case catch ssh_system_sup:acceptor_supervisor(Pid) of
AsupPid when is_pid(AsupPid) ->
- [{Name,Port,Profile}] =
- [{Nam,Prt,Prf}
+ [{IP,Port,Profile}] =
+ [{IP,Prt,Prf}
|| {{ssh_acceptor_sup,Hst,Prt,Prf},_Pid,worker,[ssh_acceptor]}
<- supervisor:which_children(AsupPid),
- Nam <- [case inet:parse_strict_address(Hst) of
- {ok,IP} -> IP;
- _ when Hst=="any" -> any;
- _ when Hst=="loopback" -> loopback;
- _ -> Hst
- end]
+ IP <- [case inet:parse_strict_address(Hst) of
+ {ok,IP} -> IP;
+ _ -> Hst
+ end]
],
{ok, [{port,Port},
- {name,Name},
+ {ip,IP},
{profile,Profile}
]};
_ ->
{error,bad_daemon_ref}
end.
-
-
%%--------------------------------------------------------------------
-spec stop_listener(daemon_ref()) -> ok.
-spec stop_listener(inet:ip_address(), inet:port_number()) -> ok.
@@ -298,8 +296,14 @@ stop_listener(SysSup) ->
ssh_system_sup:stop_listener(SysSup).
stop_listener(Address, Port) ->
stop_listener(Address, Port, ?DEFAULT_PROFILE).
+stop_listener(any, Port, Profile) ->
+ map_ip(fun(IP) ->
+ ssh_system_sup:stop_listener(IP, Port, Profile)
+ end, [{0,0,0,0},{0,0,0,0,0,0,0,0}]);
stop_listener(Address, Port, Profile) ->
- ssh_system_sup:stop_listener(Address, Port, Profile).
+ map_ip(fun(IP) ->
+ ssh_system_sup:stop_listener(IP, Port, Profile)
+ end, {address,Address}).
%%--------------------------------------------------------------------
-spec stop_daemon(daemon_ref()) -> ok.
@@ -312,9 +316,15 @@ stop_listener(Address, Port, Profile) ->
stop_daemon(SysSup) ->
ssh_system_sup:stop_system(SysSup).
stop_daemon(Address, Port) ->
- ssh_system_sup:stop_system(Address, Port, ?DEFAULT_PROFILE).
+ stop_daemon(Address, Port, ?DEFAULT_PROFILE).
+stop_daemon(any, Port, Profile) ->
+ map_ip(fun(IP) ->
+ ssh_system_sup:stop_system(IP, Port, Profile)
+ end, [{0,0,0,0},{0,0,0,0,0,0,0,0}]);
stop_daemon(Address, Port, Profile) ->
- ssh_system_sup:stop_system(Address, Port, Profile).
+ map_ip(fun(IP) ->
+ ssh_system_sup:stop_system(IP, Port, Profile)
+ end, {address,Address}).
%%--------------------------------------------------------------------
-spec shell(inet:socket() | string()) -> _.
@@ -397,6 +407,9 @@ default_algorithms() ->
%% consideration
%%
+%% The handle_daemon_args/2 function basically only sets the ip-option in Opts
+%% so that it is correctly set when opening the listening socket.
+
handle_daemon_args(any, Opts) ->
case proplists:get_value(ip, Opts) of
undefined -> {any, Opts};
@@ -477,20 +490,17 @@ is_tcp_socket(Socket) ->
end.
%%%----------------------------------------------------------------
-open_listen_socket(Host0, Port0, Options0) ->
- case ?GET_SOCKET_OPT(fd, Options0) of
- undefined ->
- {ok,LSock} = ssh_acceptor:listen(Port0, Options0),
- {ok,{_LHost,LPort}} = inet:sockname(LSock),
- {{_LHost,LPort}, LSock};
-%% {{Host0,LPort}, LSock};
-
- Fd when is_integer(Fd) ->
- %% Do gen_tcp:listen with the option {fd,Fd}:
- {ok,LSock} = ssh_acceptor:listen(0, Options0),
- {ok,{LHost,LPort}} = inet:sockname(LSock),
- {{LHost,LPort}, LSock}
- end.
+open_listen_socket(_Host0, Port0, Options0) ->
+ {ok,LSock} =
+ case ?GET_SOCKET_OPT(fd, Options0) of
+ undefined ->
+ ssh_acceptor:listen(Port0, Options0);
+ Fd when is_integer(Fd) ->
+ %% Do gen_tcp:listen with the option {fd,Fd}:
+ ssh_acceptor:listen(0, Options0)
+ end,
+ {ok,{LHost,LPort}} = inet:sockname(LSock),
+ {{LHost,LPort}, LSock}.
%%%----------------------------------------------------------------
finalize_start(Host, Port, Profile, Options0, F) ->
@@ -509,3 +519,33 @@ finalize_start(Host, Port, Profile, Options0, F) ->
end.
%%%----------------------------------------------------------------
+map_ip(Fun, {address,IP}) when is_tuple(IP) ->
+ Fun(IP);
+map_ip(Fun, {address,Address}) ->
+ IPs = try {ok,#hostent{h_addr_list=IP0s}} = inet:gethostbyname(Address),
+ IP0s
+ catch
+ _:_ -> []
+ end,
+ map_ip(Fun, IPs);
+map_ip(Fun, IPs) ->
+ lists:map(Fun, IPs).
+
+%%%----------------------------------------------------------------
+mangle_connect_address(A, SockOpts) ->
+ mangle_connect_address1(A, proplists:get_value(inet6,SockOpts,false)).
+
+loopback(true) -> {0,0,0,0,0,0,0,1};
+loopback(false) -> {127,0,0,1}.
+
+mangle_connect_address1( loopback, V6flg) -> loopback(V6flg);
+mangle_connect_address1( any, V6flg) -> loopback(V6flg);
+mangle_connect_address1({0,0,0,0}, _) -> loopback(false);
+mangle_connect_address1({0,0,0,0,0,0,0,0}, _) -> loopback(true);
+mangle_connect_address1( IP, _) when is_tuple(IP) -> IP;
+mangle_connect_address1(A, _) ->
+ case catch inet:parse_address(A) of
+ {ok, {0,0,0,0}} -> loopback(false);
+ {ok, {0,0,0,0,0,0,0,0}} -> loopback(true);
+ _ -> A
+ end.
--
cgit v1.2.3
From 2f91341ae855b28c82024caa87c7541e94f68a18 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 29 Mar 2017 12:57:23 +0200
Subject: ssh: Make test suites pass
---
lib/ssh/test/ssh_algorithms_SUITE.erl | 13 ++--
lib/ssh/test/ssh_basic_SUITE.erl | 3 +-
lib/ssh/test/ssh_bench_SUITE.erl | 6 +-
lib/ssh/test/ssh_connection_SUITE.erl | 64 +++++++++---------
lib/ssh/test/ssh_options_SUITE.erl | 24 +++----
lib/ssh/test/ssh_relay.erl | 3 +-
lib/ssh/test/ssh_sftp_SUITE.erl | 2 +-
lib/ssh/test/ssh_sftpd_SUITE.erl | 4 +-
lib/ssh/test/ssh_sup_SUITE.erl | 31 +++++----
lib/ssh/test/ssh_test_lib.erl | 124 +++++++++++++++++++++++++++++++---
lib/ssh/test/ssh_to_openssh_SUITE.erl | 28 ++++----
lib/ssh/test/ssh_trpt_test_lib.erl | 3 +-
12 files changed, 210 insertions(+), 95 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_algorithms_SUITE.erl b/lib/ssh/test/ssh_algorithms_SUITE.erl
index 6f75d83c4a..2990d1e02a 100644
--- a/lib/ssh/test/ssh_algorithms_SUITE.erl
+++ b/lib/ssh/test/ssh_algorithms_SUITE.erl
@@ -235,13 +235,12 @@ sshc_simple_exec_os_cmd(Config) ->
Parent = self(),
Client = spawn(
fun() ->
- Cmd = lists:concat(["ssh -p ",Port,
- " -C"
- " -o UserKnownHostsFile=",KnownHosts,
- " -o StrictHostKeyChecking=no"
- " ",Host," 1+1."]),
- Result = os:cmd(Cmd),
- ct:log("~p~n = ~p",[Cmd, Result]),
+ Result = ssh_test_lib:open_sshc(Host, Port,
+ [" -C"
+ " -o UserKnownHostsFile=",KnownHosts,
+ " -o StrictHostKeyChecking=no"
+ ],
+ " 1+1."),
Parent ! {result, self(), Result, "2"}
end),
receive
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index a9b6be222e..089d191fea 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -742,7 +742,8 @@ known_hosts(Config) when is_list(Config) ->
Lines = string:tokens(binary_to_list(Binary), "\n"),
[Line] = Lines,
[HostAndIp, Alg, _KeyData] = string:tokens(Line, " "),
- [Host, _Ip] = string:tokens(HostAndIp, ","),
+ [StoredHost, _Ip] = string:tokens(HostAndIp, ","),
+ true = ssh_test_lib:match_ip(StoredHost, Host),
"ssh-" ++ _ = Alg,
ssh:stop_daemon(Pid).
%%--------------------------------------------------------------------
diff --git a/lib/ssh/test/ssh_bench_SUITE.erl b/lib/ssh/test/ssh_bench_SUITE.erl
index ac52bb7e28..317e50ed1d 100644
--- a/lib/ssh/test/ssh_bench_SUITE.erl
+++ b/lib/ssh/test/ssh_bench_SUITE.erl
@@ -98,7 +98,7 @@ end_per_testcase(_Func, _Conf) ->
connect(Config) ->
KexAlgs = proplists:get_value(kex, ssh:default_algorithms()),
- ct:pal("KexAlgs = ~p",[KexAlgs]),
+ ct:log("KexAlgs = ~p",[KexAlgs]),
lists:foreach(
fun(KexAlg) ->
PrefAlgs = preferred_algorithms(KexAlg),
@@ -242,11 +242,11 @@ median(Data) when is_list(Data) ->
1 ->
lists:nth(N div 2 + 1, SortedData)
end,
- ct:pal("median(~p) = ~p",[SortedData,Median]),
+ ct:log("median(~p) = ~p",[SortedData,Median]),
Median.
report(Data) ->
- ct:pal("EventData = ~p",[Data]),
+ ct:log("EventData = ~p",[Data]),
ct_event:notify(#event{name = benchmark_data,
data = Data}).
diff --git a/lib/ssh/test/ssh_connection_SUITE.erl b/lib/ssh/test/ssh_connection_SUITE.erl
index 2819a4dbd9..b911cf0e9e 100644
--- a/lib/ssh/test/ssh_connection_SUITE.erl
+++ b/lib/ssh/test/ssh_connection_SUITE.erl
@@ -89,7 +89,7 @@ end_per_suite(Config) ->
%%--------------------------------------------------------------------
init_per_group(openssh, Config) ->
- case gen_tcp:connect("localhost", 22, []) of
+ case ssh_test_lib:gen_tcp_connect("localhost", 22, []) of
{error,econnrefused} ->
{skip,"No openssh deamon"};
{ok, Socket} ->
@@ -126,7 +126,7 @@ simple_exec(Config) when is_list(Config) ->
simple_exec_sock(_Config) ->
- {ok, Sock} = gen_tcp:connect("localhost", ?SSH_DEFAULT_PORT, [{active,false}]),
+ {ok, Sock} = ssh_test_lib:gen_tcp_connect("localhost", ?SSH_DEFAULT_PORT, [{active,false}]),
{ok, ConnectionRef} = ssh:connect(Sock, [{silently_accept_hosts, true},
{user_interaction, false}]),
do_simple_exec(ConnectionRef).
@@ -179,13 +179,13 @@ daemon_sock_not_tcp(_Config) ->
%%--------------------------------------------------------------------
connect_sock_not_passive(_Config) ->
- {ok,Sock} = gen_tcp:connect("localhost", ?SSH_DEFAULT_PORT, []),
+ {ok,Sock} = ssh_test_lib:gen_tcp_connect("localhost", ?SSH_DEFAULT_PORT, []),
{error, not_passive_mode} = ssh:connect(Sock, []),
gen_tcp:close(Sock).
%%--------------------------------------------------------------------
daemon_sock_not_passive(_Config) ->
- {ok,Sock} = gen_tcp:connect("localhost", ?SSH_DEFAULT_PORT, []),
+ {ok,Sock} = ssh_test_lib:gen_tcp_connect("localhost", ?SSH_DEFAULT_PORT, []),
{error, not_passive_mode} = ssh:daemon(Sock),
gen_tcp:close(Sock).
@@ -585,12 +585,13 @@ start_shell_sock_exec_fun(Config) when is_list(Config) ->
UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth
file:make_dir(UserDir),
SysDir = proplists:get_value(data_dir, Config),
- {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir},
- {user_dir, UserDir},
- {password, "morot"},
- {exec, fun ssh_exec/1}]),
+ {Pid, HostD, Port} = ssh_test_lib:daemon([{system_dir, SysDir},
+ {user_dir, UserDir},
+ {password, "morot"},
+ {exec, fun ssh_exec/1}]),
+ Host = ssh_test_lib:ntoa(ssh_test_lib:mangle_connect_address(HostD)),
- {ok, Sock} = gen_tcp:connect(Host, Port, [{active,false}]),
+ {ok, Sock} = ssh_test_lib:gen_tcp_connect(Host, Port, [{active,false}]),
{ok,ConnectionRef} = ssh:connect(Sock, [{silently_accept_hosts, true},
{user, "foo"},
{password, "morot"},
@@ -623,7 +624,7 @@ start_shell_sock_daemon_exec(Config) ->
{ok,{_IP,Port}} = inet:sockname(Sl), % _IP is likely to be {0,0,0,0}. Win don't like...
spawn_link(fun() ->
- {ok,Ss} = gen_tcp:connect("localhost", Port, [{active,false}]),
+ {ok,Ss} = ssh_test_lib:gen_tcp_connect("localhost", Port, [{active,false}]),
{ok, _Pid} = ssh:daemon(Ss, [{system_dir, SysDir},
{user_dir, UserDir},
{password, "morot"},
@@ -658,10 +659,10 @@ gracefull_invalid_version(Config) when is_list(Config) ->
SysDir = proplists:get_value(data_dir, Config),
{_Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir},
- {user_dir, UserDir},
- {password, "morot"}]),
+ {user_dir, UserDir},
+ {password, "morot"}]),
- {ok, S} = gen_tcp:connect(Host, Port, []),
+ {ok, S} = ssh_test_lib:gen_tcp_connect(Host, Port, []),
ok = gen_tcp:send(S, ["SSH-8.-1","\r\n"]),
receive
Verstring ->
@@ -680,10 +681,10 @@ gracefull_invalid_start(Config) when is_list(Config) ->
file:make_dir(UserDir),
SysDir = proplists:get_value(data_dir, Config),
{_Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir},
- {user_dir, UserDir},
- {password, "morot"}]),
+ {user_dir, UserDir},
+ {password, "morot"}]),
- {ok, S} = gen_tcp:connect(Host, Port, []),
+ {ok, S} = ssh_test_lib:gen_tcp_connect(Host, Port, []),
ok = gen_tcp:send(S, ["foobar","\r\n"]),
receive
Verstring ->
@@ -702,10 +703,10 @@ gracefull_invalid_long_start(Config) when is_list(Config) ->
file:make_dir(UserDir),
SysDir = proplists:get_value(data_dir, Config),
{_Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir},
- {user_dir, UserDir},
- {password, "morot"}]),
+ {user_dir, UserDir},
+ {password, "morot"}]),
- {ok, S} = gen_tcp:connect(Host, Port, []),
+ {ok, S} = ssh_test_lib:gen_tcp_connect(Host, Port, []),
ok = gen_tcp:send(S, [lists:duplicate(257, $a), "\r\n"]),
receive
Verstring ->
@@ -725,10 +726,10 @@ gracefull_invalid_long_start_no_nl(Config) when is_list(Config) ->
file:make_dir(UserDir),
SysDir = proplists:get_value(data_dir, Config),
{_Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir},
- {user_dir, UserDir},
- {password, "morot"}]),
+ {user_dir, UserDir},
+ {password, "morot"}]),
- {ok, S} = gen_tcp:connect(Host, Port, []),
+ {ok, S} = ssh_test_lib:gen_tcp_connect(Host, Port, []),
ok = gen_tcp:send(S, [lists:duplicate(257, $a), "\r\n"]),
receive
Verstring ->
@@ -779,22 +780,21 @@ stop_listener(Config) when is_list(Config) ->
ct:fail("Exec Timeout")
end,
- {ok, HostAddr} = inet:getaddr(Host, inet),
- case ssh_test_lib:daemon(HostAddr, Port, [{system_dir, SysDir},
- {user_dir, UserDir},
- {password, "potatis"},
- {exec, fun ssh_exec/1}]) of
- {Pid1, HostAddr, Port} ->
+ case ssh_test_lib:daemon(Port, [{system_dir, SysDir},
+ {user_dir, UserDir},
+ {password, "potatis"},
+ {exec, fun ssh_exec/1}]) of
+ {Pid1, Host, Port} ->
ConnectionRef1 = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
{user, "foo"},
{password, "potatis"},
{user_interaction, true},
{user_dir, UserDir}]),
{error, _} = ssh:connect(Host, Port, [{silently_accept_hosts, true},
- {user, "foo"},
- {password, "morot"},
- {user_interaction, true},
- {user_dir, UserDir}]),
+ {user, "foo"},
+ {password, "morot"},
+ {user_interaction, true},
+ {user_dir, UserDir}]),
ssh:close(ConnectionRef0),
ssh:close(ConnectionRef1),
ssh:stop_daemon(Pid0),
diff --git a/lib/ssh/test/ssh_options_SUITE.erl b/lib/ssh/test/ssh_options_SUITE.erl
index 758c20e2b8..344a042d79 100644
--- a/lib/ssh/test/ssh_options_SUITE.erl
+++ b/lib/ssh/test/ssh_options_SUITE.erl
@@ -868,13 +868,13 @@ really_do_hostkey_fingerprint_check(Config, HashAlg) ->
ct:log("Fingerprints(~p) = ~p",[HashAlg,FPs]),
%% Start daemon with the public keys that we got fingerprints from
- {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir},
+ {Pid, Host0, Port} = ssh_test_lib:daemon([{system_dir, SysDir},
{user_dir, UserDirServer},
{password, "morot"}]),
-
+ Host = ssh_test_lib:ntoa(Host0),
FP_check_fun = fun(PeerName, FP) ->
- ct:pal("PeerName = ~p, FP = ~p",[PeerName,FP]),
- HostCheck = (Host == PeerName),
+ ct:log("PeerName = ~p, FP = ~p",[PeerName,FP]),
+ HostCheck = ssh_test_lib:match_ip(Host, PeerName),
FPCheck =
if is_atom(HashAlg) -> lists:member(FP, FPs);
is_list(HashAlg) -> lists:all(fun(FP1) -> lists:member(FP1,FPs) end,
@@ -1052,20 +1052,20 @@ id_string_random_client(Config) ->
%%--------------------------------------------------------------------
id_string_no_opt_server(Config) ->
{_Server, Host, Port} = ssh_test_lib:std_daemon(Config, []),
- {ok,S1}=gen_tcp:connect(Host,Port,[{active,false},{packet,line}]),
+ {ok,S1}=ssh_test_lib:gen_tcp_connect(Host,Port,[{active,false},{packet,line}]),
{ok,"SSH-2.0-Erlang/"++Vsn} = gen_tcp:recv(S1, 0, 2000),
true = expected_ssh_vsn(Vsn).
%%--------------------------------------------------------------------
id_string_own_string_server(Config) ->
{_Server, Host, Port} = ssh_test_lib:std_daemon(Config, [{id_string,"Olle"}]),
- {ok,S1}=gen_tcp:connect(Host,Port,[{active,false},{packet,line}]),
+ {ok,S1}=ssh_test_lib:gen_tcp_connect(Host,Port,[{active,false},{packet,line}]),
{ok,"SSH-2.0-Olle\r\n"} = gen_tcp:recv(S1, 0, 2000).
%%--------------------------------------------------------------------
id_string_random_server(Config) ->
{_Server, Host, Port} = ssh_test_lib:std_daemon(Config, [{id_string,random}]),
- {ok,S1}=gen_tcp:connect(Host,Port,[{active,false},{packet,line}]),
+ {ok,S1}=ssh_test_lib:gen_tcp_connect(Host,Port,[{active,false},{packet,line}]),
{ok,"SSH-2.0-"++Rnd} = gen_tcp:recv(S1, 0, 2000),
case Rnd of
"Erlang"++_ -> ct:log("Id=~p",[Rnd]),
@@ -1086,11 +1086,11 @@ ssh_connect_negtimeout(Config, Parallel) ->
ct:log("Parallel: ~p",[Parallel]),
{_Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},{user_dir, UserDir},
- {parallel_login, Parallel},
- {negotiation_timeout, NegTimeOut},
- {failfun, fun ssh_test_lib:failfun/2}]),
-
- {ok,Socket} = gen_tcp:connect(Host, Port, []),
+ {parallel_login, Parallel},
+ {negotiation_timeout, NegTimeOut},
+ {failfun, fun ssh_test_lib:failfun/2}]),
+
+ {ok,Socket} = ssh_test_lib:gen_tcp_connect(Host, Port, []),
Factor = 2,
ct:log("And now sleeping ~p*NegTimeOut (~p ms)...", [Factor, round(Factor * NegTimeOut)]),
diff --git a/lib/ssh/test/ssh_relay.erl b/lib/ssh/test/ssh_relay.erl
index 28000fbb97..1e3810e9d4 100644
--- a/lib/ssh/test/ssh_relay.erl
+++ b/lib/ssh/test/ssh_relay.erl
@@ -131,7 +131,8 @@ init([ListenAddr, ListenPort, PeerAddr, PeerPort | _Options]) ->
S = #state{local_addr = ListenAddr,
local_port = ListenPort,
lpid = LPid,
- peer_addr = PeerAddr,
+ peer_addr = ssh_test_lib:ntoa(
+ ssh_test_lib:mangle_connect_address(PeerAddr)),
peer_port = PeerPort
},
{ok, S};
diff --git a/lib/ssh/test/ssh_sftp_SUITE.erl b/lib/ssh/test/ssh_sftp_SUITE.erl
index acf76157a2..7efeb3a0ad 100644
--- a/lib/ssh/test/ssh_sftp_SUITE.erl
+++ b/lib/ssh/test/ssh_sftp_SUITE.erl
@@ -660,7 +660,7 @@ start_channel_sock(Config) ->
{Host,Port} = proplists:get_value(peer, Config),
%% Get a tcp socket
- {ok, Sock} = gen_tcp:connect(Host, Port, [{active,false}]),
+ {ok, Sock} = ssh_test_lib:gen_tcp_connect(Host, Port, [{active,false}]),
%% and open one channel on one new Connection
{ok, ChPid1, Conn} = ssh_sftp:start_channel(Sock, Opts),
diff --git a/lib/ssh/test/ssh_sftpd_SUITE.erl b/lib/ssh/test/ssh_sftpd_SUITE.erl
index 673fb54a4f..379c0bcb0a 100644
--- a/lib/ssh/test/ssh_sftpd_SUITE.erl
+++ b/lib/ssh/test/ssh_sftpd_SUITE.erl
@@ -705,10 +705,10 @@ try_access(Path, Cm, Channel, ReqId) ->
{ok, <>, <<>>} ->
case Code of
?SSH_FX_FILE_IS_A_DIRECTORY ->
- ct:pal("Got the expected SSH_FX_FILE_IS_A_DIRECTORY status",[]),
+ ct:log("Got the expected SSH_FX_FILE_IS_A_DIRECTORY status",[]),
ok;
?SSH_FX_FAILURE ->
- ct:pal("Got the expected SSH_FX_FAILURE status",[]),
+ ct:log("Got the expected SSH_FX_FAILURE status",[]),
ok;
_ ->
case Rest of
diff --git a/lib/ssh/test/ssh_sup_SUITE.erl b/lib/ssh/test/ssh_sup_SUITE.erl
index fdeb8186a5..dd7c4b1473 100644
--- a/lib/ssh/test/ssh_sup_SUITE.erl
+++ b/lib/ssh/test/ssh_sup_SUITE.erl
@@ -137,16 +137,18 @@ sshd_subtree(Config) when is_list(Config) ->
HostIP = proplists:get_value(host_ip, Config),
Port = proplists:get_value(port, Config),
SystemDir = proplists:get_value(data_dir, Config),
- ssh:daemon(HostIP, Port, [{system_dir, SystemDir},
- {failfun, fun ssh_test_lib:failfun/2},
- {user_passwords,
- [{?USER, ?PASSWD}]}]),
+ {ok,Daemon} = ssh:daemon(HostIP, Port, [{system_dir, SystemDir},
+ {failfun, fun ssh_test_lib:failfun/2},
+ {user_passwords,
+ [{?USER, ?PASSWD}]}]),
- ?wait_match([{{server,ssh_system_sup, HostIP, Port, ?DEFAULT_PROFILE},
+ ct:log("Expect HostIP=~p, Port=~p, Daemon=~p",[HostIP,Port,Daemon]),
+ ?wait_match([{{server,ssh_system_sup, ListenIP, Port, ?DEFAULT_PROFILE},
Daemon, supervisor,
[ssh_system_sup]}],
supervisor:which_children(sshd_sup),
- Daemon),
+ [ListenIP,Daemon]),
+ true = ssh_test_lib:match_ip(HostIP, ListenIP),
check_sshd_system_tree(Daemon, Config),
ssh:stop_daemon(HostIP, Port),
ct:sleep(?WAIT_FOR_SHUTDOWN),
@@ -161,16 +163,18 @@ sshd_subtree_profile(Config) when is_list(Config) ->
Profile = proplists:get_value(profile, Config),
SystemDir = proplists:get_value(data_dir, Config),
- {ok, _} = ssh:daemon(HostIP, Port, [{system_dir, SystemDir},
- {failfun, fun ssh_test_lib:failfun/2},
- {user_passwords,
- [{?USER, ?PASSWD}]},
- {profile, Profile}]),
- ?wait_match([{{server,ssh_system_sup, HostIP,Port,Profile},
+ {ok, Daemon} = ssh:daemon(HostIP, Port, [{system_dir, SystemDir},
+ {failfun, fun ssh_test_lib:failfun/2},
+ {user_passwords,
+ [{?USER, ?PASSWD}]},
+ {profile, Profile}]),
+ ct:log("Expect HostIP=~p, Port=~p, Profile=~p, Daemon=~p",[HostIP,Port,Profile,Daemon]),
+ ?wait_match([{{server,ssh_system_sup, ListenIP,Port,Profile},
Daemon, supervisor,
[ssh_system_sup]}],
supervisor:which_children(sshd_sup),
- Daemon),
+ [ListenIP,Daemon]),
+ true = ssh_test_lib:match_ip(HostIP, ListenIP),
check_sshd_system_tree(Daemon, Config),
ssh:stop_daemon(HostIP, Port, Profile),
ct:sleep(?WAIT_FOR_SHUTDOWN),
@@ -310,3 +314,4 @@ acceptor_pid(DaemonPid) ->
receive {Pid, supsearch, L} -> {ok,L}
after 2000 -> timeout
end.
+
diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl
index 0ada8233a7..6186d44890 100644
--- a/lib/ssh/test/ssh_test_lib.erl
+++ b/lib/ssh/test/ssh_test_lib.erl
@@ -32,15 +32,18 @@
-define(TIMEOUT, 50000).
+%%%----------------------------------------------------------------
connect(Port, Options) when is_integer(Port) ->
connect(hostname(), Port, Options).
connect(any, Port, Options) ->
connect(hostname(), Port, Options);
connect(Host, Port, Options) ->
+ ct:log("~p:~p Calling ssh:connect(~p, ~p, ~p)",[?MODULE,?LINE,Host, Port, Options]),
{ok, ConnectionRef} = ssh:connect(Host, Port, Options),
ConnectionRef.
+%%%----------------------------------------------------------------
daemon(Options) ->
daemon(any, 0, Options).
@@ -53,26 +56,57 @@ daemon(Host, Options) ->
daemon(Host, Port, Options) ->
ct:log("~p:~p Calling ssh:daemon(~p, ~p, ~p)",[?MODULE,?LINE,Host,Port,Options]),
case ssh:daemon(Host, Port, Options) of
- {ok, Pid} when Host == any ->
- ct:log("ssh:daemon ok (1)",[]),
- {Pid, hostname(), daemon_port(Port,Pid)};
{ok, Pid} ->
- ct:log("ssh:daemon ok (2)",[]),
- {Pid, Host, daemon_port(Port,Pid)};
+ {ok,L} = ssh:daemon_info(Pid),
+ ListenPort = proplists:get_value(port, L),
+ ListenIP = proplists:get_value(ip, L),
+ {Pid, ListenIP, ListenPort};
Error ->
ct:log("ssh:daemon error ~p",[Error]),
Error
end.
+%%%----------------------------------------------------------------
daemon_port(Pid) -> daemon_port(0, Pid).
daemon_port(0, Pid) -> {ok,Dinf} = ssh:daemon_info(Pid),
proplists:get_value(port, Dinf);
daemon_port(Port, _) -> Port.
-
+%%%----------------------------------------------------------------
+gen_tcp_connect(Host0, Port, Options) ->
+ Host = ssh_test_lib:ntoa(ssh_test_lib:mangle_connect_address(Host0)),
+ ct:log("~p:~p gen_tcp:connect(~p, ~p, ~p)~nHost0 = ~p",
+ [?MODULE,?LINE, Host, Port, Options, Host0]),
+ Result = gen_tcp:connect(Host, Port, Options),
+ ct:log("~p:~p Result = ~p", [?MODULE,?LINE, Result]),
+ Result.
+
+%%%----------------------------------------------------------------
+open_sshc(Host0, Port, OptStr) ->
+ open_sshc(Host0, Port, OptStr, "").
+
+open_sshc(Host0, Port, OptStr, ExecStr) ->
+ Cmd = open_sshc_cmd(Host0, Port, OptStr, ExecStr),
+ Result = os:cmd(Cmd),
+ ct:log("~p:~p Result = ~p", [?MODULE,?LINE, Result]),
+ Result.
+
+open_sshc_cmd(Host, Port, OptStr) ->
+ open_sshc_cmd(Host, Port, OptStr, "").
+
+open_sshc_cmd(Host0, Port, OptStr, ExecStr) ->
+ Host = ssh_test_lib:ntoa(ssh_test_lib:mangle_connect_address(Host0)),
+ Cmd = lists:flatten(["ssh -p ", integer_to_list(Port),
+ " ", OptStr,
+ " ", Host,
+ " ", ExecStr]),
+ ct:log("~p:~p OpenSSH Cmd = ~p", [?MODULE,?LINE, Cmd]),
+ Cmd.
+
+%%%----------------------------------------------------------------
std_daemon(Config, ExtraOpts) ->
PrivDir = proplists:get_value(priv_dir, Config),
UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth
@@ -88,6 +122,7 @@ std_daemon1(Config, ExtraOpts) ->
{failfun, fun ssh_test_lib:failfun/2}
| ExtraOpts]).
+%%%----------------------------------------------------------------
std_connect(Config, Host, Port, ExtraOpts) ->
UserDir = proplists:get_value(priv_dir, Config),
_ConnectionRef =
@@ -98,6 +133,7 @@ std_connect(Config, Host, Port, ExtraOpts) ->
{user_interaction, false}
| ExtraOpts]).
+%%%----------------------------------------------------------------
std_simple_sftp(Host, Port, Config) ->
std_simple_sftp(Host, Port, Config, []).
@@ -112,6 +148,7 @@ std_simple_sftp(Host, Port, Config, Opts) ->
ok = ssh:close(ConnectionRef),
Data == ReadData.
+%%%----------------------------------------------------------------
std_simple_exec(Host, Port, Config) ->
std_simple_exec(Host, Port, Config, []).
@@ -138,6 +175,7 @@ std_simple_exec(Host, Port, Config, Opts) ->
ct:fail(ExecResult)
end.
+%%%----------------------------------------------------------------
start_shell(Port, IOServer) ->
start_shell(Port, IOServer, []).
@@ -152,6 +190,7 @@ start_shell(Port, IOServer, ExtraOptions) ->
end).
+%%%----------------------------------------------------------------
start_io_server() ->
spawn_link(?MODULE, init_io_server, [self()]).
@@ -210,8 +249,7 @@ reply(TestCase, Result) ->
%%ct:log("reply ~p sending ~p ! ~p",[self(), TestCase, Result]),
TestCase ! Result.
-
-
+%%%----------------------------------------------------------------
rcv_expected(Expect, SshPort, Timeout) ->
receive
{SshPort, Recvd} when is_function(Expect) ->
@@ -865,3 +903,73 @@ create_random_dir(Config) ->
%% The likelyhood of always generating an existing file name is low
create_random_dir(Config)
end.
+
+%%%----------------------------------------------------------------
+match_ip(A, B) ->
+ R = match_ip0(A,B) orelse match_ip0(B,A),
+ ct:log("match_ip(~p, ~p) -> ~p",[A, B, R]),
+ R.
+
+match_ip0(A, A) ->
+ true;
+match_ip0(any, _) ->
+ true;
+match_ip0(A, B) ->
+ case match_ip1(A, B) of
+ true ->
+ true;
+ false when is_list(A) ->
+ case inet:parse_address(A) of
+ {ok,IPa} -> match_ip0(IPa, B);
+ _ -> false
+ end;
+ false when is_list(B) ->
+ case inet:parse_address(B) of
+ {ok,IPb} -> match_ip0(A, IPb);
+ _ -> false
+ end;
+ false ->
+ false
+ end.
+
+match_ip1(any, _) -> true;
+match_ip1(loopback, {127,_,_,_}) -> true;
+match_ip1({0,0,0,0}, {127,_,_,_}) -> true;
+match_ip1(loopback, {0,0,0,0,0,0,0,1}) -> true;
+match_ip1({0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,1}) -> true;
+match_ip1(_, _) -> false.
+
+%%%----------------------------------------------------------------
+mangle_connect_address(A) ->
+ mangle_connect_address(A, []).
+
+mangle_connect_address(A, SockOpts) ->
+ mangle_connect_address1(A, proplists:get_value(inet6,SockOpts,false)).
+
+loopback(true) -> {0,0,0,0,0,0,0,1};
+loopback(false) -> {127,0,0,1}.
+
+mangle_connect_address1( loopback, V6flg) -> loopback(V6flg);
+mangle_connect_address1( any, V6flg) -> loopback(V6flg);
+mangle_connect_address1({0,0,0,0}, _) -> loopback(false);
+mangle_connect_address1({0,0,0,0,0,0,0,0}, _) -> loopback(true);
+mangle_connect_address1( IP, _) when is_tuple(IP) -> IP;
+mangle_connect_address1(A, _) ->
+ case catch inet:parse_address(A) of
+ {ok, {0,0,0,0}} -> loopback(false);
+ {ok, {0,0,0,0,0,0,0,0}} -> loopback(true);
+ _ -> A
+ end.
+
+%%%----------------------------------------------------------------
+ntoa(A) ->
+ try inet:ntoa(A)
+ of
+ {error,_} when is_atom(A) -> atom_to_list(A);
+ {error,_} when is_list(A) -> A;
+ S when is_list(S) -> S
+ catch
+ _:_ when is_atom(A) -> atom_to_list(A);
+ _:_ when is_list(A) -> A
+ end.
+
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl
index 7eda009552..35e3ee3edf 100644
--- a/lib/ssh/test/ssh_to_openssh_SUITE.erl
+++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl
@@ -376,18 +376,18 @@ erlang_server_openssh_client_public_key_rsa(Config) when is_list(Config) ->
erlang_server_openssh_client_public_key_X(Config, ssh_rsa).
-erlang_server_openssh_client_public_key_X(Config, PubKeyAlg) ->
+erlang_server_openssh_client_public_key_X(Config, _PubKeyAlg) ->
SystemDir = proplists:get_value(data_dir, Config),
PrivDir = proplists:get_value(priv_dir, Config),
KnownHosts = filename:join(PrivDir, "known_hosts"),
{Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
{failfun, fun ssh_test_lib:failfun/2}]),
-
ct:sleep(500),
- Cmd = "ssh -p " ++ integer_to_list(Port) ++
- " -o UserKnownHostsFile=" ++ KnownHosts ++
- " " ++ Host ++ " 1+1.",
+ Cmd = ssh_test_lib:open_sshc_cmd(Host, Port,
+ [" -o UserKnownHostsFile=", KnownHosts,
+ " -o StrictHostKeyChecking=no"],
+ "1+1."),
OpenSsh = ssh_test_lib:open_port({spawn, Cmd}),
ssh_test_lib:rcv_expected({data,<<"2\n">>}, OpenSsh, ?TIMEOUT),
ssh:stop_daemon(Pid).
@@ -395,13 +395,13 @@ erlang_server_openssh_client_public_key_X(Config, PubKeyAlg) ->
%%--------------------------------------------------------------------
%% Test that the Erlang/OTP server can renegotiate with openSSH
erlang_server_openssh_client_renegotiate(Config) ->
- PubKeyAlg = ssh_rsa,
+ _PubKeyAlg = ssh_rsa,
SystemDir = proplists:get_value(data_dir, Config),
PrivDir = proplists:get_value(priv_dir, Config),
KnownHosts = filename:join(PrivDir, "known_hosts"),
{Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
- {failfun, fun ssh_test_lib:failfun/2}]),
+ {failfun, fun ssh_test_lib:failfun/2}]),
ct:sleep(500),
RenegLimitK = 3,
@@ -409,11 +409,13 @@ erlang_server_openssh_client_renegotiate(Config) ->
Data = lists:duplicate(trunc(1.1*RenegLimitK*1024), $a),
ok = file:write_file(DataFile, Data),
- Cmd = "ssh -p " ++ integer_to_list(Port) ++
- " -o UserKnownHostsFile=" ++ KnownHosts ++
- " -o RekeyLimit=" ++ integer_to_list(RenegLimitK) ++"K" ++
- " " ++ Host ++ " < " ++ DataFile,
- OpenSsh = ssh_test_lib:open_port({spawn, Cmd}),
+ Cmd = ssh_test_lib:open_sshc_cmd(Host, Port,
+ [" -o UserKnownHostsFile=", KnownHosts,
+ " -o StrictHostKeyChecking=no",
+ " -o RekeyLimit=",integer_to_list(RenegLimitK),"K"]),
+
+
+ OpenSsh = ssh_test_lib:open_port({spawn, Cmd++" < "++DataFile}),
Expect = fun({data,R}) ->
try
@@ -462,7 +464,7 @@ erlang_client_openssh_server_renegotiate(_Config) ->
{silently_accept_hosts,true}],
group_leader(IO, self()),
{ok, ConnRef} = ssh:connect(Host, ?SSH_DEFAULT_PORT, Options),
- ct:pal("Parent = ~p, IO = ~p, Shell = ~p, ConnRef = ~p~n",[Parent, IO, self(), ConnRef]),
+ ct:log("Parent = ~p, IO = ~p, Shell = ~p, ConnRef = ~p~n",[Parent, IO, self(), ConnRef]),
case ssh_connection:session_channel(ConnRef, infinity) of
{ok,ChannelId} ->
success = ssh_connection:ptty_alloc(ConnRef, ChannelId, []),
diff --git a/lib/ssh/test/ssh_trpt_test_lib.erl b/lib/ssh/test/ssh_trpt_test_lib.erl
index 261239c152..e1f4c65300 100644
--- a/lib/ssh/test/ssh_trpt_test_lib.erl
+++ b/lib/ssh/test/ssh_trpt_test_lib.erl
@@ -314,8 +314,7 @@ mangle_opts(Options) ->
lists:keydelete(K,1,Opts)
end, Options, SysOpts).
-host({0,0,0,0}) -> "localhost";
-host(H) -> H.
+host(H) -> ssh_test_lib:ntoa(ssh_test_lib:mangle_connect_address(H)).
%%%----------------------------------------------------------------
send(S=#s{ssh=C}, hello) ->
--
cgit v1.2.3
From 7ad21ca66f5a46be231fffe884ac2c3b5d97c7ae Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Tue, 4 Apr 2017 19:53:05 +0200
Subject: ssh: document what happens when ssh:daemon sets both HostAddr and ip
option
The idea is that the HostAddress argument takes precedence over an
ip-option. However, an ip-option overrides the 'any' HostAddr.
This fixes the case of dameon(Port, [{ip,IP}..] in a non-surprising
way.
---
lib/ssh/doc/src/ssh.xml | 22 ++++++++++++-
lib/ssh/src/ssh.erl | 82 +++++--------------------------------------------
2 files changed, 29 insertions(+), 75 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index 88d402cf38..48c9aa18e9 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -379,7 +379,7 @@
on the given port.
Port = integer()
- HostAddress = ip_address() | any
+ HostAddress = ip_address() | any | loopback
Options = [{Option, Value}]
Option = atom()
Value = term()
@@ -390,6 +390,26 @@
Starts a server listening for SSH connections on the given
port. If the Port is 0, a random free port is selected. See
daemon_info/1 about how to find the selected port number.
+
+ Please note that by historical reasons both the HostAddress argument and the inet socket option
+ ip set the listening address. This is a source of possible inconsistent settings.
+
+ The rules for handling the two address passing options are:
+
+ - if HostAddress is an ip-address, that ip-address is the listening address.
+ An ip-option will be discarded if present.
+
+ - if HostAddress is loopback, the listening address
+ is loopback and an loopback address will be choosen by the underlying layers.
+ An ip-option will be discarded if present.
+
+ - if HostAddress is any and no ip-option is present, the listening address is
+ any and the socket will listen to all addresses
+
+ - if HostAddress is any and an ip-option is present, the listening address is
+ set to the value of the ip-option
+
+
Options:
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 8c802d46eb..3e80a04b70 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -225,7 +225,8 @@ daemon(Port, UserOptions) when 0 =< Port, Port =< 65535 ->
daemon(any, Port, UserOptions).
-daemon(Host0, Port0, UserOptions0) when 0 =< Port0, Port0 =< 65535 ->
+daemon(Host0, Port0, UserOptions0) when 0 =< Port0, Port0 =< 65535,
+ Host0 == any ; Host0 == loopback ; is_tuple(Host0) ->
try
{Host1, UserOptions} = handle_daemon_args(Host0, UserOptions0),
#{} = Options0 = ssh_options:handle_options(server, UserOptions),
@@ -259,7 +260,11 @@ daemon(Host0, Port0, UserOptions0) when 0 =< Port0, Port0 =< 65535 ->
{error,Error};
_C:_E ->
{error,{cannot_start_daemon,_C,_E}}
- end.
+ end;
+
+daemon(_, _, _) ->
+ {error, badarg}.
+
%%--------------------------------------------------------------------
@@ -378,35 +383,6 @@ default_algorithms() ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
-
-%% - if Address is 'any' and no ip-option is present, the name is
-%% 'any' and the socket will listen to all addresses
-%%
-%% - if Address is 'any' and an ip-option is present, the name is
-%% set to the value of the ip-option and the socket will listen
-%% to that address
-%%
-%% - if Address is 'loopback' and no ip-option is present, the name
-%% is 'loopback' and an loopback address will be choosen by the
-%% underlying layers
-%%
-%% - if Address is 'loopback' and an ip-option is present, the name
-%% is set to the value of the ip-option kept and the socket will
-%% listen to that address
-%%
-%% - if Address is an ip-address, that ip-address is the name and
-%% the listening address. An ip-option will be discarded.
-%%
-%% - if Address is a HostName, and that resolves to an ip-address,
-%% that ip-address is the name and the listening address. An
-%% ip-option will be discarded.
-%%
-%% - if Address is a string or an atom other than thoose defined
-%% above, that Address will be the name and the listening address
-%% will be choosen by the lower layers taking an ip-option in
-%% consideration
-%%
-
%% The handle_daemon_args/2 function basically only sets the ip-option in Opts
%% so that it is correctly set when opening the listening socket.
@@ -416,53 +392,11 @@ handle_daemon_args(any, Opts) ->
IP -> {IP, Opts}
end;
-handle_daemon_args(loopback, Opts) ->
- case proplists:get_value(ip, Opts) of
- undefined -> {loopback, [{ip,loopback}|Opts]};
- IP -> {IP, Opts}
- end;
-
-handle_daemon_args(IPaddr, Opts) when is_tuple(IPaddr) ->
+handle_daemon_args(IPaddr, Opts) when is_tuple(IPaddr) ; IPaddr == loopback ->
case proplists:get_value(ip, Opts) of
undefined -> {IPaddr, [{ip,IPaddr}|Opts]};
IPaddr -> {IPaddr, Opts};
IP -> {IPaddr, [{ip,IPaddr}|Opts--[{ip,IP}]]} %% Backward compatibility
- end;
-
-handle_daemon_args(Address, Opts) when is_list(Address) ; % IP address in string or a domain
- is_atom(Address) % domains could be atoms in inet
- ->
- IP = proplists:get_value(ip, Opts),
- case inet:parse_strict_address(Address) of
- %% check if Address is an IP-address
- {ok, IP} -> {IP, Opts};
- {ok, OtherIP} -> {OtherIP, [{ip,OtherIP}|Opts--[{ip,IP}]]};
- _ ->
- %% Not an IP-address. Check if it is a host name:
- case inet:getaddr(Address, family(Opts)) of
- {ok, IP} -> {Address, Opts};
- {ok, OtherIP} -> {Address, [{ip,OtherIP}|Opts--[{ip,IP}]]};
- _ ->
- %% Not a Host name and not an IP address, let
- %% inet and the OS later figure out what it
- %% could be
- {Address, Opts}
- end
- end.
-
-%% Has the caller indicated the address family?
-family(Opts) ->
- family(Opts, inet).
-
-family(Opts, Default) ->
- case proplists:get_value(inet,Opts) of
- true -> inet;
- inet -> inet;
- inet6 -> inet6;
- _ -> case proplists:get_value(inet6,Opts) of
- true -> inet6;
- _ -> Default
- end
end.
%%%----------------------------------------------------------------
--
cgit v1.2.3
From b89f06569ee24011a8535c57d6a82e336afeb5bf Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 5 Apr 2017 15:45:18 +0200
Subject: ssh: Doc-changes to make clearer IP-address and 'ip'-option
---
lib/ssh/doc/src/ssh.xml | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index 48c9aa18e9..368261968d 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -396,18 +396,18 @@
The rules for handling the two address passing options are:
- - if HostAddress is an ip-address, that ip-address is the listening address.
- An ip-option will be discarded if present.
+ - if HostAddress is an IP-address, that IP-address is the listening address.
+ An 'ip'-option will be discarded if present.
- if HostAddress is loopback, the listening address
is loopback and an loopback address will be choosen by the underlying layers.
- An ip-option will be discarded if present.
+ An 'ip'-option will be discarded if present.
- - if HostAddress is any and no ip-option is present, the listening address is
+
- if HostAddress is any and no 'ip'-option is present, the listening address is
any and the socket will listen to all addresses
- - if HostAddress is any and an ip-option is present, the listening address is
- set to the value of the ip-option
+ - if HostAddress is any and an 'ip'-option is present, the listening address is
+ set to the value of the 'ip'-option
Options:
--
cgit v1.2.3
From 43dfbf7533ff9d176051231e52d308613a8d4bd1 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Tue, 31 Jan 2017 13:59:19 +0100
Subject: ssh: added message_queue_data,off_heap to spawn
Seems to solve some test case problems when heavily loaded
---
lib/ssh/src/ssh_connection_handler.erl | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index ff94e5dfb6..84adf952e6 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -80,7 +80,11 @@
) -> {ok, pid()}.
%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
start_link(Role, Socket, Options) ->
- {ok, proc_lib:spawn_link(?MODULE, init_connection_handler, [Role, Socket, Options])}.
+ {ok, proc_lib:spawn_opt(?MODULE,
+ init_connection_handler,
+ [Role, Socket, Options],
+ [link, {message_queue_data,off_heap}]
+ )}.
%%--------------------------------------------------------------------
--
cgit v1.2.3
From a0ab002c9f23865b96595a4a95750d85801f93d1 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 12 Apr 2017 19:07:27 +0200
Subject: ssh: change next_event to postpone
---
lib/ssh/src/ssh_connection_handler.erl | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 84adf952e6..ca9790ba0d 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -813,7 +813,7 @@ handle_event(_, #ssh_msg_userauth_info_request{} = Msg, {userauth_keyboard_inter
send_bytes(Reply, D),
{next_state, {userauth_keyboard_interactive_info_response,client}, D#data{ssh_params = Ssh}};
not_ok ->
- {next_state, {userauth,client}, D, [{next_event, internal, Msg}]}
+ {next_state, {userauth,client}, D, [postpone]}
end;
handle_event(_, #ssh_msg_userauth_info_response{} = Msg, {userauth_keyboard_interactive, server}, D) ->
@@ -842,14 +842,14 @@ handle_event(_, #ssh_msg_userauth_info_response{} = Msg, {userauth_keyboard_inte
{next_state, {connected,server}, D#data{auth_user = User,
ssh_params = Ssh#ssh{authenticated = true}}};
-handle_event(_, Msg = #ssh_msg_userauth_failure{}, {userauth_keyboard_interactive, client},
+handle_event(_, #ssh_msg_userauth_failure{}, {userauth_keyboard_interactive, client},
#data{ssh_params = Ssh0} = D0) ->
Prefs = [{Method,M,F,A} || {Method,M,F,A} <- Ssh0#ssh.userauth_preference,
Method =/= "keyboard-interactive"],
D = D0#data{ssh_params = Ssh0#ssh{userauth_preference=Prefs}},
- {next_state, {userauth,client}, D, [{next_event, internal, Msg}]};
+ {next_state, {userauth,client}, D, [postpone]};
-handle_event(_, Msg=#ssh_msg_userauth_failure{}, {userauth_keyboard_interactive_info_response, client},
+handle_event(_, #ssh_msg_userauth_failure{}, {userauth_keyboard_interactive_info_response, client},
#data{ssh_params = Ssh0} = D0) ->
Opts = Ssh0#ssh.opts,
D = case ?GET_OPT(password, Opts) of
@@ -859,23 +859,23 @@ handle_event(_, Msg=#ssh_msg_userauth_failure{}, {userauth_keyboard_interactive_
D0#data{ssh_params =
Ssh0#ssh{opts = ?PUT_OPT({password,not_ok}, Opts)}} % FIXME:intermodule dependency
end,
- {next_state, {userauth,client}, D, [{next_event, internal, Msg}]};
+ {next_state, {userauth,client}, D, [postpone]};
-handle_event(_, Msg=#ssh_msg_userauth_success{}, {userauth_keyboard_interactive_info_response, client}, D) ->
- {next_state, {userauth,client}, D, [{next_event, internal, Msg}]};
+handle_event(_, #ssh_msg_userauth_success{}, {userauth_keyboard_interactive_info_response, client}, D) ->
+ {next_state, {userauth,client}, D, [postpone]};
-handle_event(_, Msg=#ssh_msg_userauth_info_request{}, {userauth_keyboard_interactive_info_response, client}, D) ->
- {next_state, {userauth_keyboard_interactive,client}, D, [{next_event, internal, Msg}]};
+handle_event(_, #ssh_msg_userauth_info_request{}, {userauth_keyboard_interactive_info_response, client}, D) ->
+ {next_state, {userauth_keyboard_interactive,client}, D, [postpone]};
%%% ######## {connected, client|server} ####
-handle_event(_, {#ssh_msg_kexinit{},_} = Event, {connected,Role}, D0) ->
+handle_event(_, {#ssh_msg_kexinit{},_}, {connected,Role}, D0) ->
{KeyInitMsg, SshPacket, Ssh} = ssh_transport:key_exchange_init_msg(D0#data.ssh_params),
D = D0#data{ssh_params = Ssh,
key_exchange_init_msg = KeyInitMsg},
send_bytes(SshPacket, D),
- {next_state, {kexinit,Role,renegotiate}, D, [{next_event, internal, Event}]};
+ {next_state, {kexinit,Role,renegotiate}, D, [postpone]};
handle_event(_, #ssh_msg_disconnect{description=Desc} = Msg, StateName, D0) ->
{disconnect, _, {{replies,Replies}, _}} =
--
cgit v1.2.3
From 24cce98e38f1c8d36abb67bc7aca0668cf64c1ad Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 12 Apr 2017 19:56:12 +0200
Subject: ssh: replace deprecated crypto:rand_uniform
---
lib/ssh/src/ssh_transport.erl | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 54ea80c727..6b47868d5c 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -181,7 +181,7 @@ ssh_vsn() ->
end.
random_id(Nlo, Nup) ->
- [crypto:rand_uniform($a,$z+1) || _<- lists:duplicate(crypto:rand_uniform(Nlo,Nup+1),x) ].
+ [$a + rand:uniform($z-$a+1) - 1 || _<- lists:duplicate(Nlo + rand:uniform(Nup-Nlo+1) - 1, x)].
hello_version_msg(Data) ->
[Data,"\r\n"].
@@ -1041,7 +1041,7 @@ padding_length(Size, #ssh{encrypt_block_size = BlockSize,
end,
PadBlockSize = max(BlockSize,4),
MaxExtraBlocks = (max(RandomLengthPadding,MinPaddingLen) - MinPaddingLen) div PadBlockSize,
- ExtraPaddingLen = try crypto:rand_uniform(0,MaxExtraBlocks)*PadBlockSize
+ ExtraPaddingLen = try (rand:uniform(MaxExtraBlocks+1) - 1) * PadBlockSize
catch _:_ -> 0
end,
MinPaddingLen + ExtraPaddingLen.
--
cgit v1.2.3
From 5e2f2fb80636e858877fa4d4ff2d9834bc1cd616 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 13 Apr 2017 14:38:50 +0200
Subject: ssh: re-write to use callback init/1
---
lib/ssh/src/ssh_connection_handler.erl | 144 +++++++++++++++------------------
1 file changed, 67 insertions(+), 77 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 84adf952e6..11d182849c 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -60,7 +60,7 @@
]).
%%% Behaviour callbacks
--export([callback_mode/0, handle_event/4, terminate/3,
+-export([init/1, callback_mode/0, handle_event/4, terminate/3,
format_status/2, code_change/4]).
%%% Exports not intended to be used :). They are used for spawning and tests
@@ -362,71 +362,79 @@ renegotiate_data(ConnectionHandler) ->
) -> no_return().
%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
init_connection_handler(Role, Socket, Opts) ->
- process_flag(trap_exit, true),
- S0 = init_process_state(Role, Socket, Opts),
- try
- {Protocol, Callback, CloseTag} = ?GET_OPT(transport, Opts),
- S0#data{ssh_params = init_ssh_record(Role, Socket, Opts),
- transport_protocol = Protocol,
- transport_cb = Callback,
- transport_close_tag = CloseTag
- }
- of
- S ->
- gen_statem:enter_loop(?MODULE,
- [], %%[{debug,[trace,log,statistics,debug]} || Role==server],
- {hello,Role},
- S)
- catch
- _:Error ->
- gen_statem:enter_loop(?MODULE,
- [],
- {init_error,Error},
- S0)
- end.
-
-
-init_process_state(Role, Socket, Opts) ->
- D = #data{connection_state =
- C = #connection{channel_cache = ssh_channel:cache_create(),
- channel_id_seed = 0,
- port_bindings = [],
- requests = [],
- options = Opts},
- starter = ?GET_INTERNAL_OPT(user_pid, Opts),
- socket = Socket,
- opts = Opts
- },
- case Role of
- client ->
- %% Start the renegotiation timers
- timer:apply_after(?REKEY_TIMOUT, gen_statem, cast, [self(), renegotiate]),
- timer:apply_after(?REKEY_DATA_TIMOUT, gen_statem, cast, [self(), data_size]),
- cache_init_idle_timer(D);
- server ->
- cache_init_idle_timer(
- D#data{connection_state = init_connection(Role, C, Opts)}
- )
+ case init([Role, Socket, Opts]) of
+ {ok, StartState, D} ->
+ process_flag(trap_exit, true),
+ gen_statem:enter_loop(?MODULE,
+ [], %%[{debug,[trace,log,statistics,debug]} || Role==server],
+ StartState,
+ D);
+
+ {stop, {error,enotconn}} ->
+ %% Handles the abnormal sequence:
+ %% SYN->
+ %% <-SYNACK
+ %% ACK->
+ %% RST->
+ exit({shutdown, "TCP connection to server was prematurely closed by the client"});
+
+ {stop, OtherError} ->
+ exit({shutdown, {init,OtherError}})
end.
-init_connection(server, C = #connection{}, Opts) ->
- Sups = ?GET_INTERNAL_OPT(supervisors, Opts),
- SystemSup = proplists:get_value(system_sup, Sups),
- SubSystemSup = proplists:get_value(subsystem_sup, Sups),
- ConnectionSup = proplists:get_value(connection_sup, Sups),
+init([Role,Socket,Opts]) ->
+ case inet:peername(Socket) of
+ {ok, PeerAddr} ->
+ {Protocol, Callback, CloseTag} = ?GET_OPT(transport, Opts),
+ C = #connection{channel_cache = ssh_channel:cache_create(),
+ channel_id_seed = 0,
+ port_bindings = [],
+ requests = [],
+ options = Opts},
+ D0 = #data{starter = ?GET_INTERNAL_OPT(user_pid, Opts),
+ socket = Socket,
+ transport_protocol = Protocol,
+ transport_cb = Callback,
+ transport_close_tag = CloseTag,
+ ssh_params = init_ssh_record(Role, Socket, PeerAddr, Opts),
+ opts = Opts
+ },
+ D = case Role of
+ client ->
+ %% Start the renegotiation timers
+ timer:apply_after(?REKEY_TIMOUT, gen_statem, cast, [self(), renegotiate]),
+ timer:apply_after(?REKEY_DATA_TIMOUT, gen_statem, cast, [self(), data_size]),
+ cache_init_idle_timer(
+ D0#data{connection_state = C}
+ );
+ server ->
+ Sups = ?GET_INTERNAL_OPT(supervisors, Opts),
+ cache_init_idle_timer(
+ D0#data{connection_state =
+ C#connection{cli_spec = ?GET_OPT(ssh_cli, Opts, {ssh_cli,[?GET_OPT(shell, Opts)]}),
+ exec = ?GET_OPT(exec, Opts),
+ system_supervisor = proplists:get_value(system_sup, Sups),
+ sub_system_supervisor = proplists:get_value(subsystem_sup, Sups),
+ connection_supervisor = proplists:get_value(connection_sup, Sups)
+ }})
+ end,
+ {ok, {hello,Role}, D};
+
+ {error,Error} ->
+ {stop, Error}
+ end.
- C#connection{cli_spec = ?GET_OPT(ssh_cli, Opts, {ssh_cli,[?GET_OPT(shell, Opts)]}),
- exec = ?GET_OPT(exec, Opts),
- system_supervisor = SystemSup,
- sub_system_supervisor = SubSystemSup,
- connection_supervisor = ConnectionSup
- }.
init_ssh_record(Role, Socket, Opts) ->
- {ok, PeerAddr} = inet:peername(Socket),
+ %% Export of this internal function is
+ %% intended for low-level protocol test suites
+ {ok,PeerAddr} = inet:peername(Socket),
+ init_ssh_record(Role, Socket, PeerAddr, Opts).
+
+init_ssh_record(Role, _Socket, PeerAddr, Opts) ->
KeyCb = ?GET_OPT(key_cb, Opts),
AuthMethods =
case Role of
@@ -481,8 +489,7 @@ init_ssh_record(Role, Socket, Opts) ->
-type renegotiate_flag() :: init | renegotiate.
-type state_name() ::
- {init_error,any()}
- | {hello, role()}
+ {hello, role()}
| {kexinit, role(), renegotiate_flag()}
| {key_exchange, role(), renegotiate_flag()}
| {key_exchange_dh_gex_init, server, renegotiate_flag()}
@@ -504,26 +511,9 @@ init_ssh_record(Role, Socket, Opts) ->
%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-%%% ######## Error in the initialisation ####
-
callback_mode() ->
handle_event_function.
-handle_event(_, _Event, {init_error,Error}, _) ->
- case Error of
- {badmatch,{error,enotconn}} ->
- %% Handles the abnormal sequence:
- %% SYN->
- %% <-SYNACK
- %% ACK->
- %% RST->
- {stop, {shutdown,"TCP connenction to server was prematurely closed by the client"}};
-
- OtherError ->
- {stop, {shutdown,{init,OtherError}}}
- end;
-
-
%%% ######## {hello, client|server} ####
%% The very first event that is sent when the we are set as controlling process of Socket
handle_event(_, socket_control, {hello,_}, D) ->
--
cgit v1.2.3
From 0d91185b9093de3a254f0a869e7dadfcfa79295d Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Tue, 18 Apr 2017 12:15:58 +0200
Subject: ssh: fix dialyzer errors
---
lib/ssh/src/ssh_connection_handler.erl | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 1a8e022da8..84bb7dc23f 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -337,8 +337,7 @@ renegotiate_data(ConnectionHandler) ->
transport_protocol :: atom(), % ex: tcp
transport_cb :: atom(), % ex: gen_tcp
transport_close_tag :: atom(), % ex: tcp_closed
- ssh_params :: #ssh{}
- | undefined,
+ ssh_params :: #ssh{},
socket :: inet:socket(),
decrypted_data_buffer = <<>> :: binary(),
encrypted_data_buffer = <<>> :: binary(),
@@ -370,7 +369,7 @@ init_connection_handler(Role, Socket, Opts) ->
StartState,
D);
- {stop, {error,enotconn}} ->
+ {stop, enotconn} ->
%% Handles the abnormal sequence:
%% SYN->
%% <-SYNACK
@@ -394,21 +393,20 @@ init([Role,Socket,Opts]) ->
requests = [],
options = Opts},
D0 = #data{starter = ?GET_INTERNAL_OPT(user_pid, Opts),
+ connection_state = C,
socket = Socket,
transport_protocol = Protocol,
transport_cb = Callback,
transport_close_tag = CloseTag,
ssh_params = init_ssh_record(Role, Socket, PeerAddr, Opts),
- opts = Opts
+ opts = Opts
},
D = case Role of
client ->
%% Start the renegotiation timers
timer:apply_after(?REKEY_TIMOUT, gen_statem, cast, [self(), renegotiate]),
timer:apply_after(?REKEY_DATA_TIMOUT, gen_statem, cast, [self(), data_size]),
- cache_init_idle_timer(
- D0#data{connection_state = C}
- );
+ cache_init_idle_timer(D0);
server ->
Sups = ?GET_INTERNAL_OPT(supervisors, Opts),
cache_init_idle_timer(
--
cgit v1.2.3
From 192379acc9e112f393ad18e20f4951d1e318a7a0 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 26 Apr 2017 11:49:43 +0200
Subject: ssh: Correction of misspelled type
---
lib/ssh/src/ssh.hrl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh.hrl b/lib/ssh/src/ssh.hrl
index 315310f700..c7ed11895c 100644
--- a/lib/ssh/src/ssh.hrl
+++ b/lib/ssh/src/ssh.hrl
@@ -134,7 +134,7 @@
role :: client | role(),
peer :: undefined |
{inet:hostname(),
- {inet:ip_adress(),inet:port_number()}}, %% string version of peer address
+ {inet:ip_address(),inet:port_number()}}, %% string version of peer address
c_vsn, %% client version {Major,Minor}
s_vsn, %% server version {Major,Minor}
--
cgit v1.2.3
From c0d2e134f90ddd3fd2f5b0f9a94a5b0d55c93416 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 10 Apr 2017 13:19:37 +0200
Subject: ssh: clearify public key option handling
Change the handling of option pref_public_key_algs so that the same
checks are not performed twice.
---
lib/ssh/src/ssh_auth.erl | 47 ++++++++++++++++++++---------------------------
1 file changed, 20 insertions(+), 27 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl
index 88c8144063..51df54341f 100644
--- a/lib/ssh/src/ssh_auth.erl
+++ b/lib/ssh/src/ssh_auth.erl
@@ -175,6 +175,7 @@ service_request_msg(Ssh) ->
%%%----------------------------------------------------------------
init_userauth_request_msg(#ssh{opts = Opts} = Ssh) ->
+ %% Client side
case ?GET_OPT(user, Opts) of
undefined ->
ErrStr = "Could not determine the users name",
@@ -183,25 +184,17 @@ init_userauth_request_msg(#ssh{opts = Opts} = Ssh) ->
description = ErrStr});
User ->
- Msg = #ssh_msg_userauth_request{user = User,
- service = "ssh-connection",
- method = "none",
- data = <<>>},
- Algs0 = ?GET_OPT(pref_public_key_algs, Opts),
- %% The following line is not strictly correct. The call returns the
- %% supported HOST key types while we are interested in USER keys. However,
- %% they "happens" to be the same (for now). This could change....
- %% There is no danger as long as the set of user keys is a subset of the set
- %% of host keys.
- CryptoSupported = ssh_transport:supported_algorithms(public_key),
- Algs = [A || A <- Algs0,
- lists:member(A, CryptoSupported)],
-
- Prefs = method_preference(Algs),
- ssh_transport:ssh_packet(Msg, Ssh#ssh{user = User,
- userauth_preference = Prefs,
- userauth_methods = none,
- service = "ssh-connection"})
+ ssh_transport:ssh_packet(
+ #ssh_msg_userauth_request{user = User,
+ service = "ssh-connection",
+ method = "none",
+ data = <<>>},
+ Ssh#ssh{user = User,
+ userauth_preference =
+ method_preference(?GET_OPT(pref_public_key_algs, Opts)),
+ userauth_methods = none,
+ service = "ssh-connection"}
+ )
end.
%%%----------------------------------------------------------------
@@ -453,14 +446,14 @@ handle_userauth_info_response(#ssh_msg_userauth_info_response{},
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
-method_preference(Algs) ->
- lists:foldr(fun(A, Acc) ->
- [{"publickey", ?MODULE, publickey_msg, [A]} | Acc]
- end,
- [{"password", ?MODULE, password_msg, []},
- {"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []}
- ],
- Algs).
+method_preference(PubKeyAlgs) ->
+ %% PubKeyAlgs: List of user (client) public key algorithms to try to use.
+ %% All of the acceptable algorithms is the default values.
+ PubKeyDefs = [{"publickey", ?MODULE, publickey_msg, [A]} || A <- PubKeyAlgs],
+ NonPKmethods = [{"password", ?MODULE, password_msg, []},
+ {"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []}
+ ],
+ PubKeyDefs ++ NonPKmethods.
check_password(User, Password, Opts, Ssh) ->
case ?GET_OPT(pwdfun, Opts) of
--
cgit v1.2.3
From 29d7533c715f972ee996382c2c45cc0c055e10d2 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 10 Apr 2017 16:25:06 +0200
Subject: ssh: Implement ext-info extension. draft-ietf-curdle-ssh-ext-info
This is only a draft extension, but it is quite stable and already supported
by some implementations. OpenSSH has had it for some year now.
---
lib/ssh/src/ssh.hrl | 7 +-
lib/ssh/src/ssh_connection_handler.erl | 142 ++++++++++++++++-----
lib/ssh/src/ssh_dbg.erl | 5 +-
lib/ssh/src/ssh_message.erl | 33 +++++
lib/ssh/src/ssh_options.erl | 22 +++-
lib/ssh/src/ssh_transport.erl | 221 ++++++++++++++++++++++-----------
lib/ssh/src/ssh_transport.hrl | 15 +++
lib/ssh/test/ssh_trpt_test_lib.erl | 11 +-
8 files changed, 344 insertions(+), 112 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh.hrl b/lib/ssh/src/ssh.hrl
index c7ed11895c..1a95bb27e7 100644
--- a/lib/ssh/src/ssh.hrl
+++ b/lib/ssh/src/ssh.hrl
@@ -145,6 +145,9 @@
c_keyinit, %% binary payload of kexinit packet
s_keyinit, %% binary payload of kexinit packet
+ send_ext_info, %% May send ext-info to peer
+ recv_ext_info, %% Expect ext-info from peer
+
algorithms, %% #alg{}
kex, %% key exchange algorithm
@@ -216,7 +219,9 @@
compress,
decompress,
c_lng,
- s_lng
+ s_lng,
+ send_ext_info,
+ recv_ext_info
}).
-record(ssh_key,
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 84bb7dc23f..0ff7c9b3a1 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -453,7 +453,9 @@ init_ssh_record(Role, _Socket, PeerAddr, Opts) ->
PeerName = case ?GET_INTERNAL_OPT(host, Opts) of
PeerIP when is_tuple(PeerIP) ->
inet_parse:ntoa(PeerIP);
- PeerName0 ->
+ PeerName0 when is_atom(PeerName0) ->
+ atom_to_list(PeerName0);
+ PeerName0 when is_list(PeerName0) ->
PeerName0
end,
S0#ssh{c_vsn = Vsn,
@@ -493,6 +495,7 @@ init_ssh_record(Role, _Socket, PeerAddr, Opts) ->
| {key_exchange_dh_gex_init, server, renegotiate_flag()}
| {key_exchange_dh_gex_reply, client, renegotiate_flag()}
| {new_keys, role()}
+ | {ext_info, role(), renegotiate_flag()}
| {service_request, role()}
| {userauth, role()}
| {userauth_keyboard_interactive, role()}
@@ -589,13 +592,17 @@ handle_event(_, {#ssh_msg_kexinit{}=Kex, Payload}, {kexinit,Role,ReNeg},
handle_event(_, #ssh_msg_kexdh_init{} = Msg, {key_exchange,server,ReNeg}, D) ->
{ok, KexdhReply, Ssh1} = ssh_transport:handle_kexdh_init(Msg, D#data.ssh_params),
send_bytes(KexdhReply, D),
- {ok, NewKeys, Ssh} = ssh_transport:new_keys_message(Ssh1),
+ {ok, NewKeys, Ssh2} = ssh_transport:new_keys_message(Ssh1),
send_bytes(NewKeys, D),
+ {ok, ExtInfo, Ssh} = ssh_transport:ext_info_message(Ssh2),
+ send_bytes(ExtInfo, D),
{next_state, {new_keys,server,ReNeg}, D#data{ssh_params=Ssh}};
handle_event(_, #ssh_msg_kexdh_reply{} = Msg, {key_exchange,client,ReNeg}, D) ->
- {ok, NewKeys, Ssh} = ssh_transport:handle_kexdh_reply(Msg, D#data.ssh_params),
+ {ok, NewKeys, Ssh1} = ssh_transport:handle_kexdh_reply(Msg, D#data.ssh_params),
send_bytes(NewKeys, D),
+ {ok, ExtInfo, Ssh} = ssh_transport:ext_info_message(Ssh1),
+ send_bytes(ExtInfo, D),
{next_state, {new_keys,client,ReNeg}, D#data{ssh_params=Ssh}};
%%%---- diffie-hellman group exchange
@@ -620,13 +627,17 @@ handle_event(_, #ssh_msg_kex_dh_gex_group{} = Msg, {key_exchange,client,ReNeg},
handle_event(_, #ssh_msg_kex_ecdh_init{} = Msg, {key_exchange,server,ReNeg}, D) ->
{ok, KexEcdhReply, Ssh1} = ssh_transport:handle_kex_ecdh_init(Msg, D#data.ssh_params),
send_bytes(KexEcdhReply, D),
- {ok, NewKeys, Ssh} = ssh_transport:new_keys_message(Ssh1),
+ {ok, NewKeys, Ssh2} = ssh_transport:new_keys_message(Ssh1),
send_bytes(NewKeys, D),
+ {ok, ExtInfo, Ssh} = ssh_transport:ext_info_message(Ssh2),
+ send_bytes(ExtInfo, D),
{next_state, {new_keys,server,ReNeg}, D#data{ssh_params=Ssh}};
handle_event(_, #ssh_msg_kex_ecdh_reply{} = Msg, {key_exchange,client,ReNeg}, D) ->
- {ok, NewKeys, Ssh} = ssh_transport:handle_kex_ecdh_reply(Msg, D#data.ssh_params),
+ {ok, NewKeys, Ssh1} = ssh_transport:handle_kex_ecdh_reply(Msg, D#data.ssh_params),
send_bytes(NewKeys, D),
+ {ok, ExtInfo, Ssh} = ssh_transport:ext_info_message(Ssh1),
+ send_bytes(ExtInfo, D),
{next_state, {new_keys,client,ReNeg}, D#data{ssh_params=Ssh}};
@@ -635,8 +646,10 @@ handle_event(_, #ssh_msg_kex_ecdh_reply{} = Msg, {key_exchange,client,ReNeg}, D)
handle_event(_, #ssh_msg_kex_dh_gex_init{} = Msg, {key_exchange_dh_gex_init,server,ReNeg}, D) ->
{ok, KexGexReply, Ssh1} = ssh_transport:handle_kex_dh_gex_init(Msg, D#data.ssh_params),
send_bytes(KexGexReply, D),
- {ok, NewKeys, Ssh} = ssh_transport:new_keys_message(Ssh1),
+ {ok, NewKeys, Ssh2} = ssh_transport:new_keys_message(Ssh1),
send_bytes(NewKeys, D),
+ {ok, ExtInfo, Ssh} = ssh_transport:ext_info_message(Ssh2),
+ send_bytes(ExtInfo, D),
{next_state, {new_keys,server,ReNeg}, D#data{ssh_params=Ssh}};
@@ -645,30 +658,60 @@ handle_event(_, #ssh_msg_kex_dh_gex_init{} = Msg, {key_exchange_dh_gex_init,serv
handle_event(_, #ssh_msg_kex_dh_gex_reply{} = Msg, {key_exchange_dh_gex_reply,client,ReNeg}, D) ->
{ok, NewKeys, Ssh1} = ssh_transport:handle_kex_dh_gex_reply(Msg, D#data.ssh_params),
send_bytes(NewKeys, D),
- {next_state, {new_keys,client,ReNeg}, D#data{ssh_params=Ssh1}};
+ {ok, ExtInfo, Ssh} = ssh_transport:ext_info_message(Ssh1),
+ send_bytes(ExtInfo, D),
+ {next_state, {new_keys,client,ReNeg}, D#data{ssh_params=Ssh}};
%%% ######## {new_keys, client|server} ####
%% First key exchange round:
-handle_event(_, #ssh_msg_newkeys{} = Msg, {new_keys,Role,init}, D) ->
+handle_event(_, #ssh_msg_newkeys{} = Msg, {new_keys,client,init}, D) ->
{ok, Ssh1} = ssh_transport:handle_new_keys(Msg, D#data.ssh_params),
- Ssh = case Role of
- client ->
- {MsgReq, Ssh2} = ssh_auth:service_request_msg(Ssh1),
- send_bytes(MsgReq, D),
- Ssh2;
- server ->
- Ssh1
- end,
- {next_state, {service_request,Role}, D#data{ssh_params=Ssh}};
+ %% {ok, ExtInfo, Ssh2} = ssh_transport:ext_info_message(Ssh1),
+ %% send_bytes(ExtInfo, D),
+ {MsgReq, Ssh} = ssh_auth:service_request_msg(Ssh1),
+ send_bytes(MsgReq, D),
+ {next_state, {ext_info,client,init}, D#data{ssh_params=Ssh}};
+
+handle_event(_, #ssh_msg_newkeys{} = Msg, {new_keys,server,init}, D) ->
+ {ok, Ssh} = ssh_transport:handle_new_keys(Msg, D#data.ssh_params),
+ %% {ok, ExtInfo, Ssh} = ssh_transport:ext_info_message(Ssh1),
+ %% send_bytes(ExtInfo, D),
+ {next_state, {ext_info,server,init}, D#data{ssh_params=Ssh}};
%% Subsequent key exchange rounds (renegotiation):
handle_event(_, #ssh_msg_newkeys{} = Msg, {new_keys,Role,renegotiate}, D) ->
{ok, Ssh} = ssh_transport:handle_new_keys(Msg, D#data.ssh_params),
- {next_state, {connected,Role}, D#data{ssh_params=Ssh}};
+ %% {ok, ExtInfo, Ssh} = ssh_transport:ext_info_message(Ssh1),
+ %% send_bytes(ExtInfo, D),
+ {next_state, {ext_info,Role,renegotiate}, D#data{ssh_params=Ssh}};
+
+
+%%% ######## {ext_info, client|server, init|renegotiate} ####
+
+handle_event(_, #ssh_msg_ext_info{}=Msg, {ext_info,Role,init}, D0) ->
+ D = handle_ssh_msg_ext_info(Msg, D0),
+ {next_state, {service_request,Role}, D};
+
+handle_event(_, #ssh_msg_ext_info{}=Msg, {ext_info,Role,renegotiate}, D0) ->
+ D = handle_ssh_msg_ext_info(Msg, D0),
+ {next_state, {connected,Role}, D};
+
+handle_event(_, #ssh_msg_newkeys{}=Msg, {ext_info,_Role,renegotiate}, D) ->
+ {ok, Ssh} = ssh_transport:handle_new_keys(Msg, D#data.ssh_params),
+ {keep_state, D#data{ssh_params = Ssh}};
+
+
+handle_event(internal, Msg, {ext_info,Role,init}, D) when is_tuple(Msg) ->
+ %% If something else arrives, goto next state and handle the event in that one
+ {next_state, {service_request,Role}, D, [postpone]};
-%%% ######## {service_request, client|server}
+handle_event(internal, Msg, {ext_info,Role,renegotiate}, D) when is_tuple(Msg) ->
+ %% If something else arrives, goto next state and handle the event in that one
+ {next_state, {connected,Role}, D, [postpone]};
+
+%%% ######## {service_request, client|server} ####
handle_event(_, Msg = #ssh_msg_service_request{name=ServiceName}, StateName = {service_request,server}, D) ->
case ServiceName of
@@ -747,6 +790,11 @@ handle_event(_,
end;
%%---- userauth success to client
+handle_event(_, #ssh_msg_ext_info{}=Msg, {userauth,client}, D0) ->
+ %% FIXME: need new state to receive this msg!
+ D = handle_ssh_msg_ext_info(Msg, D0),
+ {keep_state, D};
+
handle_event(_, #ssh_msg_userauth_success{}, {userauth,client}, D=#data{ssh_params = Ssh}) ->
D#data.starter ! ssh_connected,
{next_state, {connected,client}, D#data{ssh_params=Ssh#ssh{authenticated = true}}};
@@ -849,6 +897,11 @@ handle_event(_, #ssh_msg_userauth_failure{}, {userauth_keyboard_interactive_info
end,
{next_state, {userauth,client}, D, [postpone]};
+handle_event(_, #ssh_msg_ext_info{}=Msg, {userauth_keyboard_interactive_info_response, client}, D0) ->
+ %% FIXME: need new state to receive this msg!
+ D = handle_ssh_msg_ext_info(Msg, D0),
+ {keep_state, D};
+
handle_event(_, #ssh_msg_userauth_success{}, {userauth_keyboard_interactive_info_response, client}, D) ->
{next_state, {userauth,client}, D, [postpone]};
@@ -1080,26 +1133,34 @@ handle_event({call,_}, _, StateName, _) when StateName /= {connected,server},
StateName /= {connected,client} ->
{keep_state_and_data, [postpone]};
-handle_event({call,From}, {request, ChannelPid, ChannelId, Type, Data, Timeout}, {connected,_}, D0) ->
+handle_event({call,From}, {request, ChannelPid, ChannelId, Type, Data, Timeout}, StateName, D0)
+ when element(1,StateName) == connected ;
+ element(1,StateName) == ext_info ->
D = handle_request(ChannelPid, ChannelId, Type, Data, true, From, D0),
%% Note reply to channel will happen later when reply is recived from peer on the socket
start_channel_request_timer(ChannelId, From, Timeout),
{keep_state, cache_request_idle_timer_check(D)};
-handle_event({call,From}, {request, ChannelId, Type, Data, Timeout}, {connected,_}, D0) ->
+handle_event({call,From}, {request, ChannelId, Type, Data, Timeout}, StateName, D0)
+ when element(1,StateName) == connected ;
+ element(1,StateName) == ext_info ->
D = handle_request(ChannelId, Type, Data, true, From, D0),
%% Note reply to channel will happen later when reply is recived from peer on the socket
start_channel_request_timer(ChannelId, From, Timeout),
{keep_state, cache_request_idle_timer_check(D)};
-handle_event({call,From}, {data, ChannelId, Type, Data, Timeout}, {connected,_}, D0) ->
+handle_event({call,From}, {data, ChannelId, Type, Data, Timeout}, StateName, D0)
+ when element(1,StateName) == connected ;
+ element(1,StateName) == ext_info ->
{{replies, Replies}, Connection} =
ssh_connection:channel_data(ChannelId, Type, Data, D0#data.connection_state, From),
{Repls,D} = send_replies(Replies, D0#data{connection_state = Connection}),
start_channel_request_timer(ChannelId, From, Timeout), % FIXME: No message exchange so why?
{keep_state, D, Repls};
-handle_event({call,From}, {eof, ChannelId}, {connected,_}, D0) ->
+handle_event({call,From}, {eof, ChannelId}, StateName, D0)
+ when element(1,StateName) == connected ;
+ element(1,StateName) == ext_info ->
case ssh_channel:cache_lookup(cache(D0), ChannelId) of
#channel{remote_id = Id, sent_close = false} ->
D = send_msg(ssh_connection:channel_eof_msg(Id), D0),
@@ -1110,8 +1171,9 @@ handle_event({call,From}, {eof, ChannelId}, {connected,_}, D0) ->
handle_event({call,From},
{open, ChannelPid, Type, InitialWindowSize, MaxPacketSize, Data, Timeout},
- {connected,_},
- D0) ->
+ StateName,
+ D0) when element(1,StateName) == connected ;
+ element(1,StateName) == ext_info ->
erlang:monitor(process, ChannelPid),
{ChannelId, D1} = new_channel_id(D0),
D2 = send_msg(ssh_connection:channel_open_msg(Type, ChannelId,
@@ -1131,7 +1193,9 @@ handle_event({call,From},
start_channel_request_timer(ChannelId, From, Timeout),
{keep_state, cache_cancel_idle_timer(D)};
-handle_event({call,From}, {send_window, ChannelId}, {connected,_}, D) ->
+handle_event({call,From}, {send_window, ChannelId}, StateName, D)
+ when element(1,StateName) == connected ;
+ element(1,StateName) == ext_info ->
Reply = case ssh_channel:cache_lookup(cache(D), ChannelId) of
#channel{send_window_size = WinSize,
send_packet_size = Packsize} ->
@@ -1141,7 +1205,9 @@ handle_event({call,From}, {send_window, ChannelId}, {connected,_}, D) ->
end,
{keep_state_and_data, [{reply,From,Reply}]};
-handle_event({call,From}, {recv_window, ChannelId}, {connected,_}, D) ->
+handle_event({call,From}, {recv_window, ChannelId}, StateName, D)
+ when element(1,StateName) == connected ;
+ element(1,StateName) == ext_info ->
Reply = case ssh_channel:cache_lookup(cache(D), ChannelId) of
#channel{recv_window_size = WinSize,
recv_packet_size = Packsize} ->
@@ -1151,7 +1217,9 @@ handle_event({call,From}, {recv_window, ChannelId}, {connected,_}, D) ->
end,
{keep_state_and_data, [{reply,From,Reply}]};
-handle_event({call,From}, {close, ChannelId}, {connected,_}, D0) ->
+handle_event({call,From}, {close, ChannelId}, StateName, D0)
+ when element(1,StateName) == connected ;
+ element(1,StateName) == ext_info ->
case ssh_channel:cache_lookup(cache(D0), ChannelId) of
#channel{remote_id = Id} = Channel ->
D1 = send_msg(ssh_connection:channel_close_msg(Id), D0),
@@ -1323,7 +1391,8 @@ handle_event(Type, Ev, StateName, D) ->
Descr =
case catch atom_to_list(element(1,Ev)) of
"ssh_msg_" ++_ when Type==internal ->
- "Message in wrong state";
+%% "Message in wrong state";
+lists:flatten(io_lib:format("Message ~p in wrong state (~p)", [element(1,Ev), StateName]));
_ ->
"Internal error"
end,
@@ -1516,6 +1585,8 @@ send_msg(Msg, State=#data{ssh_params=Ssh0}) when is_tuple(Msg) ->
send_bytes(Bytes, State),
State#data{ssh_params=Ssh}.
+send_bytes("", _D) ->
+ ok;
send_bytes(Bytes, #data{socket = Socket, transport_cb = Transport}) ->
_ = Transport:send(Socket, Bytes),
ok.
@@ -1621,6 +1692,19 @@ kex(_) -> undefined.
cache(#data{connection_state=C}) -> C#connection.channel_cache.
+%%%----------------------------------------------------------------
+handle_ssh_msg_ext_info(#ssh_msg_ext_info{}, D=#data{ssh_params = #ssh{recv_ext_info=false}} ) ->
+ % The peer sent this although we didn't allow it!
+ D;
+handle_ssh_msg_ext_info(#ssh_msg_ext_info{data=Data}, D0) ->
+ lists:foldl(fun ext_info/2, D0, Data).
+
+%% ext_info({ExtName,ExtValue}, D0) ->
+%% D0;
+ext_info(_, D0) ->
+ %% Not implemented
+ D0.
+
%%%----------------------------------------------------------------
handle_request(ChannelPid, ChannelId, Type, Data, WantReply, From, D) ->
case ssh_channel:cache_lookup(cache(D), ChannelId) of
diff --git a/lib/ssh/src/ssh_dbg.erl b/lib/ssh/src/ssh_dbg.erl
index 0345bbdea7..9431bf1817 100644
--- a/lib/ssh/src/ssh_dbg.erl
+++ b/lib/ssh/src/ssh_dbg.erl
@@ -56,7 +56,7 @@ messages(Write, MangleArg) when is_function(Write,2),
dbg_ssh_messages() ->
dbg:tp(ssh_message,encode,1, x),
dbg:tp(ssh_message,decode,1, x),
- dbg:tpl(ssh_transport,select_algorithm,3, x),
+ dbg:tpl(ssh_transport,select_algorithm,4, x),
dbg:tp(ssh_transport,hello_version_msg,1, x),
dbg:tp(ssh_transport,handle_hello_version,1, x).
@@ -77,7 +77,7 @@ msg_formater({trace_ts,Pid,return_from,{ssh_message,decode,1},Msg,TS}, D) ->
msg_formater({trace_ts,_Pid,call,{ssh_transport,select_algorithm,_},_TS}, D) ->
D;
-msg_formater({trace_ts,Pid,return_from,{ssh_transport,select_algorithm,3},{ok,Alg},TS}, D) ->
+msg_formater({trace_ts,Pid,return_from,{ssh_transport,select_algorithm,_},{ok,Alg},TS}, D) ->
fmt("~n~s ~p ALGORITHMS~n~s~n", [ts(TS),Pid, wr_record(Alg)], D);
msg_formater({trace_ts,_Pid,call,{ssh_transport,hello_version_msg,_},_TS}, D) ->
@@ -160,6 +160,7 @@ shrink_bin(X) -> X.
?wr_record(ssh_msg_kexdh_init);
?wr_record(ssh_msg_kexdh_reply);
?wr_record(ssh_msg_newkeys);
+?wr_record(ssh_msg_ext_info);
?wr_record(ssh_msg_kex_dh_gex_request);
?wr_record(ssh_msg_kex_dh_gex_request_old);
?wr_record(ssh_msg_kex_dh_gex_group);
diff --git a/lib/ssh/src/ssh_message.erl b/lib/ssh/src/ssh_message.erl
index 562f040477..56f678876c 100644
--- a/lib/ssh/src/ssh_message.erl
+++ b/lib/ssh/src/ssh_message.erl
@@ -215,6 +215,16 @@ encode(#ssh_msg_service_accept{
}) ->
<>;
+encode(#ssh_msg_ext_info{
+ nr_extensions = N,
+ data = Data
+ }) ->
+ lists:foldl(fun({ExtName,ExtVal}, Acc) ->
+ <>
+ end,
+ <>,
+ Data);
+
encode(#ssh_msg_newkeys{}) ->
<>;
@@ -435,6 +445,18 @@ decode(<>) ->
num_responses = Num,
data = Data};
+decode(<>) ->
+ Data = bin_foldr(
+ fun(Bin,Acc) when length(Acc) == N ->
+ {Bin,Acc};
+ (<>, Acc) ->
+ {Rest,[{binary_to_list(V0),binary_to_list(V1)}|Acc]}
+ end, [], BinData),
+ #ssh_msg_ext_info{
+ nr_extensions = N,
+ data = Data
+ };
+
%%% Keyexchange messages
decode(<>) ->
decode_kex_init(Data, [Cookie, ssh_msg_kexinit], 10);
@@ -537,17 +559,28 @@ decode(<
+ lists:reverse(bin_foldl(Fun, Acc, Bin)).
+
+bin_foldl(_, Acc, <<>>) -> Acc;
+bin_foldl(Fun, Acc0, Bin0) ->
+ {Bin,Acc} = Fun(Bin0,Acc0),
+ bin_foldl(Fun, Acc, Bin).
+
+%%%----------------------------------------------------------------
decode_keyboard_interactive_prompts(<<>>, Acc) ->
lists:reverse(Acc);
decode_keyboard_interactive_prompts(<>,
Acc) ->
decode_keyboard_interactive_prompts(Bin, [{Prompt, erl_boolean(Bool)} | Acc]).
+%%%----------------------------------------------------------------
erl_boolean(0) ->
false;
erl_boolean(1) ->
true.
+%%%----------------------------------------------------------------
decode_kex_init(<>, Acc, 0) ->
list_to_tuple(lists:reverse([X, erl_boolean(Bool) | Acc]));
decode_kex_init(<>, Acc, 0) ->
diff --git a/lib/ssh/src/ssh_options.erl b/lib/ssh/src/ssh_options.erl
index ee3cdbb8a0..6e898b4fde 100644
--- a/lib/ssh/src/ssh_options.erl
+++ b/lib/ssh/src/ssh_options.erl
@@ -614,11 +614,23 @@ default(common) ->
},
{max_random_length_padding, def} =>
- #{default => ?MAX_RND_PADDING_LEN,
- chk => fun check_non_neg_integer/1,
- class => user_options
- }
- }.
+ #{default => ?MAX_RND_PADDING_LEN,
+ chk => fun check_non_neg_integer/1,
+ class => user_options
+ },
+
+ {send_ext_info, def} =>
+ #{default => true,
+ chk => fun erlang:is_boolean/1,
+ class => user_options
+ },
+
+ {recv_ext_info, def} =>
+ #{default => true,
+ chk => fun erlang:is_boolean/1,
+ class => user_options
+ }
+ }.
%%%================================================================
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 6b47868d5c..d623d24529 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -38,6 +38,7 @@
handle_hello_version/1,
key_exchange_init_msg/1,
key_init/3, new_keys_message/1,
+ ext_info_message/1,
handle_kexinit_msg/3, handle_kexdh_init/2,
handle_kex_dh_gex_group/2, handle_kex_dh_gex_init/2, handle_kex_dh_gex_reply/2,
handle_new_keys/2, handle_kex_dh_gex_request/2,
@@ -230,7 +231,7 @@ key_exchange_init_msg(Ssh0) ->
kex_init(#ssh{role = Role, opts = Opts, available_host_keys = HostKeyAlgs}) ->
Random = ssh_bits:random(16),
PrefAlgs = ?GET_OPT(preferred_algorithms, Opts),
- kexinit_message(Role, Random, PrefAlgs, HostKeyAlgs).
+ kexinit_message(Role, Random, PrefAlgs, HostKeyAlgs, Opts).
key_init(client, Ssh, Value) ->
Ssh#ssh{c_keyinit = Value};
@@ -238,10 +239,11 @@ key_init(server, Ssh, Value) ->
Ssh#ssh{s_keyinit = Value}.
-kexinit_message(_Role, Random, Algs, HostKeyAlgs) ->
+kexinit_message(Role, Random, Algs, HostKeyAlgs, Opts) ->
#ssh_msg_kexinit{
cookie = Random,
- kex_algorithms = to_strings( get_algs(kex,Algs) ),
+ kex_algorithms = to_strings( get_algs(kex,Algs) )
+ ++ kex_ext_info(Role,Opts),
server_host_key_algorithms = HostKeyAlgs,
encryption_algorithms_client_to_server = c2s(cipher,Algs),
encryption_algorithms_server_to_client = s2c(cipher,Algs),
@@ -263,39 +265,42 @@ get_algs(Key, Algs) -> proplists:get_value(Key, Algs, default_algorithms(Key)).
to_strings(L) -> lists:map(fun erlang:atom_to_list/1, L).
new_keys_message(Ssh0) ->
- {SshPacket, Ssh} =
- ssh_packet(#ssh_msg_newkeys{}, Ssh0),
+ {SshPacket, Ssh1} = ssh_packet(#ssh_msg_newkeys{}, Ssh0),
+ Ssh = install_alg(snd, Ssh1),
{ok, SshPacket, Ssh}.
handle_kexinit_msg(#ssh_msg_kexinit{} = CounterPart, #ssh_msg_kexinit{} = Own,
- #ssh{role = client} = Ssh0) ->
- {ok, Algoritms} = select_algorithm(client, Own, CounterPart),
- case verify_algorithm(Algoritms) of
- true ->
- key_exchange_first_msg(Algoritms#alg.kex,
- Ssh0#ssh{algorithms = Algoritms});
- {false,Alg} ->
- %% TODO: Correct code?
- ssh_connection_handler:disconnect(
- #ssh_msg_disconnect{code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
- description = "Selection of key exchange algorithm failed: "
- ++ Alg
- })
+ #ssh{role = client} = Ssh) ->
+ try
+ {ok, Algorithms} = select_algorithm(client, Own, CounterPart, Ssh#ssh.opts),
+ true = verify_algorithm(Algorithms),
+ Algorithms
+ of
+ Algos ->
+ key_exchange_first_msg(Algos#alg.kex,
+ Ssh#ssh{algorithms = Algos})
+ catch
+ _:_ ->
+ ssh_connection_handler:disconnect(
+ #ssh_msg_disconnect{code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
+ description = "Selection of key exchange algorithm failed"})
end;
handle_kexinit_msg(#ssh_msg_kexinit{} = CounterPart, #ssh_msg_kexinit{} = Own,
- #ssh{role = server} = Ssh) ->
- {ok, Algoritms} = select_algorithm(server, CounterPart, Own),
- case verify_algorithm(Algoritms) of
- true ->
- {ok, Ssh#ssh{algorithms = Algoritms}};
- {false,Alg} ->
- ssh_connection_handler:disconnect(
- #ssh_msg_disconnect{code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
- description = "Selection of key exchange algorithm failed: "
- ++ Alg
- })
+ #ssh{role = server} = Ssh) ->
+ try
+ {ok, Algorithms} = select_algorithm(server, CounterPart, Own, Ssh#ssh.opts),
+ true = verify_algorithm(Algorithms),
+ Algorithms
+ of
+ Algos ->
+ {ok, Ssh#ssh{algorithms = Algos}}
+ catch
+ _:_ ->
+ ssh_connection_handler:disconnect(
+ #ssh_msg_disconnect{code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
+ description = "Selection of key exchange algorithm failed"})
end.
@@ -308,6 +313,8 @@ verify_algorithm(#alg{decrypt = undefined}) -> {false, "decrypt"};
verify_algorithm(#alg{compress = undefined}) -> {false, "compress"};
verify_algorithm(#alg{decompress = undefined}) -> {false, "decompress"};
verify_algorithm(#alg{kex = Kex}) ->
+ %% This also catches the error if 'ext-info-s' or 'ext-info-c' is selected.
+ %% (draft-ietf-curdle-ssh-ext-info-04 2.2)
case lists:member(Kex, supported_algorithms(kex)) of
true -> true;
false -> {false, "kex"}
@@ -414,9 +421,9 @@ handle_kexdh_reply(#ssh_msg_kexdh_reply{public_host_key = PeerPubHostKey,
case verify_host_key(Ssh0, PeerPubHostKey, H, H_SIG) of
ok ->
{SshPacket, Ssh} = ssh_packet(#ssh_msg_newkeys{}, Ssh0),
- {ok, SshPacket, Ssh#ssh{shared_secret = ssh_bits:mpint(K),
- exchanged_hash = H,
- session_id = sid(Ssh, H)}};
+ {ok, SshPacket, install_alg(snd, Ssh#ssh{shared_secret = ssh_bits:mpint(K),
+ exchanged_hash = H,
+ session_id = sid(Ssh, H)})};
Error ->
ssh_connection_handler:disconnect(
#ssh_msg_disconnect{
@@ -584,9 +591,9 @@ handle_kex_dh_gex_reply(#ssh_msg_kex_dh_gex_reply{public_host_key = PeerPubHostK
case verify_host_key(Ssh0, PeerPubHostKey, H, H_SIG) of
ok ->
{SshPacket, Ssh} = ssh_packet(#ssh_msg_newkeys{}, Ssh0),
- {ok, SshPacket, Ssh#ssh{shared_secret = ssh_bits:mpint(K),
- exchanged_hash = H,
- session_id = sid(Ssh, H)}};
+ {ok, SshPacket, install_alg(snd, Ssh#ssh{shared_secret = ssh_bits:mpint(K),
+ exchanged_hash = H,
+ session_id = sid(Ssh, H)})};
_Error ->
ssh_connection_handler:disconnect(
#ssh_msg_disconnect{
@@ -660,9 +667,9 @@ handle_kex_ecdh_reply(#ssh_msg_kex_ecdh_reply{public_host_key = PeerPubHostKey,
case verify_host_key(Ssh0, PeerPubHostKey, H, H_SIG) of
ok ->
{SshPacket, Ssh} = ssh_packet(#ssh_msg_newkeys{}, Ssh0),
- {ok, SshPacket, Ssh#ssh{shared_secret = ssh_bits:mpint(K),
- exchanged_hash = H,
- session_id = sid(Ssh, H)}};
+ {ok, SshPacket, install_alg(snd, Ssh#ssh{shared_secret = ssh_bits:mpint(K),
+ exchanged_hash = H,
+ session_id = sid(Ssh, H)})};
Error ->
ssh_connection_handler:disconnect(
#ssh_msg_disconnect{
@@ -682,7 +689,7 @@ handle_kex_ecdh_reply(#ssh_msg_kex_ecdh_reply{public_host_key = PeerPubHostKey,
%%%----------------------------------------------------------------
handle_new_keys(#ssh_msg_newkeys{}, Ssh0) ->
- try install_alg(Ssh0) of
+ try install_alg(rcv, Ssh0) of
#ssh{} = Ssh ->
{ok, Ssh}
catch
@@ -693,6 +700,34 @@ handle_new_keys(#ssh_msg_newkeys{}, Ssh0) ->
})
end.
+
+%%%----------------------------------------------------------------
+kex_ext_info(Role, Opts) ->
+ case ?GET_OPT(recv_ext_info,Opts) of
+ true when Role==client -> ["ext-info-c"];
+ true when Role==server -> ["ext-info-s"];
+ false -> []
+ end.
+
+ext_info_message(#ssh{role=client,
+ algorithms=#alg{send_ext_info=true}} = Ssh0) ->
+ %% FIXME: no extensions implemented for clients
+ {ok, "", Ssh0};
+
+ext_info_message(#ssh{role=server,
+ algorithms=#alg{send_ext_info=true}} = Ssh0) ->
+ AlgsList = lists:map(fun erlang:atom_to_list/1,
+ ssh_transport:default_algorithms(public_key)),
+ Msg = #ssh_msg_ext_info{nr_extensions = 1,
+ data = [{"server-sig-algs", string:join(AlgsList,",")}]
+ },
+ {SshPacket, Ssh} = ssh_packet(Msg, Ssh0),
+ {ok, SshPacket, Ssh};
+
+ext_info_message(Ssh0) ->
+ {ok, "", Ssh0}. % "" means: 'do not send'
+
+%%%----------------------------------------------------------------
%% select session id
sid(#ssh{session_id = undefined}, H) ->
H;
@@ -812,7 +847,7 @@ known_host_key(#ssh{opts = Opts, key_cb = {KeyCb,KeyCbOpts}, peer = {PeerName,_}
%%
%% The first algorithm in each list MUST be the preferred (guessed)
%% algorithm. Each string MUST contain at least one algorithm name.
-select_algorithm(Role, Client, Server) ->
+select_algorithm(Role, Client, Server, Opts) ->
{Encrypt0, Decrypt0} = select_encrypt_decrypt(Role, Client, Server),
{SendMac0, RecvMac0} = select_send_recv_mac(Role, Client, Server),
@@ -837,17 +872,34 @@ select_algorithm(Role, Client, Server) ->
Kex = select(Client#ssh_msg_kexinit.kex_algorithms,
Server#ssh_msg_kexinit.kex_algorithms),
- Alg = #alg{kex = Kex,
- hkey = HK,
- encrypt = Encrypt,
- decrypt = Decrypt,
- send_mac = SendMac,
- recv_mac = RecvMac,
- compress = Compression,
- decompress = Decompression,
- c_lng = C_Lng,
- s_lng = S_Lng},
- {ok, Alg}.
+ SendExtInfo =
+ %% To send we must have that option enabled and ...
+ ?GET_OPT(send_ext_info,Opts) andalso
+ %% ... the peer must have told us to send:
+ case Role of
+ server -> lists:member("ext-info-c", Client#ssh_msg_kexinit.kex_algorithms);
+ client -> lists:member("ext-info-s", Server#ssh_msg_kexinit.kex_algorithms)
+ end,
+
+ RecvExtInfo =
+ %% The peer should not send unless told so by us (which is
+ %% guided by an option).
+ %% (However a malicious peer could send anyway, so we must be prepared)
+ ?GET_OPT(recv_ext_info,Opts),
+
+ {ok, #alg{kex = Kex,
+ hkey = HK,
+ encrypt = Encrypt,
+ decrypt = Decrypt,
+ send_mac = SendMac,
+ recv_mac = RecvMac,
+ compress = Compression,
+ decompress = Decompression,
+ c_lng = C_Lng,
+ s_lng = S_Lng,
+ send_ext_info = SendExtInfo,
+ recv_ext_info = RecvExtInfo
+ }}.
%%% It is an agreed problem with RFC 5674 that if the selection is
@@ -928,45 +980,66 @@ select_compression_decompression(server, Client, Server) ->
Server#ssh_msg_kexinit.compression_algorithms_server_to_client),
{Compression, Decompression}.
-install_alg(SSH) ->
- SSH1 = alg_final(SSH),
- SSH2 = alg_setup(SSH1),
- alg_init(SSH2).
+%% DIr = rcv | snd
+install_alg(Dir, SSH) ->
+ SSH1 = alg_final(Dir, SSH),
+ SSH2 = alg_setup(Dir, SSH1),
+ alg_init(Dir, SSH2).
-alg_setup(SSH) ->
+alg_setup(snd, SSH) ->
ALG = SSH#ssh.algorithms,
SSH#ssh{kex = ALG#alg.kex,
hkey = ALG#alg.hkey,
encrypt = ALG#alg.encrypt,
- decrypt = ALG#alg.decrypt,
send_mac = ALG#alg.send_mac,
send_mac_size = mac_digest_size(ALG#alg.send_mac),
+ compress = ALG#alg.compress,
+ c_lng = ALG#alg.c_lng,
+ s_lng = ALG#alg.s_lng,
+ send_ext_info = ALG#alg.send_ext_info,
+ recv_ext_info = ALG#alg.recv_ext_info
+ };
+
+alg_setup(rcv, SSH) ->
+ ALG = SSH#ssh.algorithms,
+ SSH#ssh{kex = ALG#alg.kex,
+ hkey = ALG#alg.hkey,
+ decrypt = ALG#alg.decrypt,
recv_mac = ALG#alg.recv_mac,
recv_mac_size = mac_digest_size(ALG#alg.recv_mac),
- compress = ALG#alg.compress,
decompress = ALG#alg.decompress,
c_lng = ALG#alg.c_lng,
s_lng = ALG#alg.s_lng,
- algorithms = undefined
+ send_ext_info = ALG#alg.send_ext_info,
+ recv_ext_info = ALG#alg.recv_ext_info
}.
-alg_init(SSH0) ->
+
+alg_init(snd, SSH0) ->
{ok,SSH1} = send_mac_init(SSH0),
- {ok,SSH2} = recv_mac_init(SSH1),
- {ok,SSH3} = encrypt_init(SSH2),
- {ok,SSH4} = decrypt_init(SSH3),
- {ok,SSH5} = compress_init(SSH4),
- {ok,SSH6} = decompress_init(SSH5),
- SSH6.
-
-alg_final(SSH0) ->
+ {ok,SSH2} = encrypt_init(SSH1),
+ {ok,SSH3} = compress_init(SSH2),
+ SSH3;
+
+alg_init(rcv, SSH0) ->
+ {ok,SSH1} = recv_mac_init(SSH0),
+ {ok,SSH2} = decrypt_init(SSH1),
+ {ok,SSH3} = decompress_init(SSH2),
+ SSH3.
+
+
+alg_final(snd, SSH0) ->
{ok,SSH1} = send_mac_final(SSH0),
- {ok,SSH2} = recv_mac_final(SSH1),
- {ok,SSH3} = encrypt_final(SSH2),
- {ok,SSH4} = decrypt_final(SSH3),
- {ok,SSH5} = compress_final(SSH4),
- {ok,SSH6} = decompress_final(SSH5),
- SSH6.
+ {ok,SSH2} = encrypt_final(SSH1),
+ {ok,SSH3} = compress_final(SSH2),
+ SSH3;
+
+alg_final(rcv, SSH0) ->
+ {ok,SSH1} = recv_mac_final(SSH0),
+ {ok,SSH2} = decrypt_final(SSH1),
+ {ok,SSH3} = decompress_final(SSH2),
+ SSH3.
+
select_all(CL, SL) when length(CL) + length(SL) < ?MAX_NUM_ALGORITHMS ->
A = CL -- SL, %% algortihms only used by client
diff --git a/lib/ssh/src/ssh_transport.hrl b/lib/ssh/src/ssh_transport.hrl
index 19b3f5c437..faae6008f2 100644
--- a/lib/ssh/src/ssh_transport.hrl
+++ b/lib/ssh/src/ssh_transport.hrl
@@ -48,6 +48,7 @@
-define(SSH_MSG_DEBUG, 4).
-define(SSH_MSG_SERVICE_REQUEST, 5).
-define(SSH_MSG_SERVICE_ACCEPT, 6).
+-define(SSH_MSG_EXT_INFO, 7).
-define(SSH_MSG_KEXINIT, 20).
-define(SSH_MSG_NEWKEYS, 21).
@@ -88,6 +89,20 @@
name %% string
}).
+-record(ssh_msg_ext_info,
+ {
+ nr_extensions, %% uint32
+
+ %% repeat the following 2 fields "nr-extensions" times:
+ %% string extension-name
+ %% string extension-value
+
+ data %% [{extension-name, %% string
+ %% extension-value}, %% string
+ %% ...
+ %% ]
+ }).
+
-record(ssh_msg_kexinit,
{
cookie, %% random(16)
diff --git a/lib/ssh/test/ssh_trpt_test_lib.erl b/lib/ssh/test/ssh_trpt_test_lib.erl
index e1f4c65300..781889ddd1 100644
--- a/lib/ssh/test/ssh_trpt_test_lib.erl
+++ b/lib/ssh/test/ssh_trpt_test_lib.erl
@@ -397,6 +397,12 @@ send(S0, {special,Msg,PacketFun}) when is_tuple(Msg),
send_bytes(Packet, S#s{ssh = C, %%inc_send_seq_num(C),
return_value = Msg});
+send(S0, #ssh_msg_newkeys{} = Msg) ->
+ S = opt(print_messages, S0,
+ fun(X) when X==true;X==detail -> {"Send~n~s~n",[format_msg(Msg)]} end),
+ {ok, Packet, C} = ssh_transport:new_keys_message(S#s.ssh),
+ send_bytes(Packet, S#s{ssh = C});
+
send(S0, Msg) when is_tuple(Msg) ->
S = opt(print_messages, S0,
fun(X) when X==true;X==detail -> {"Send~n~s~n",[format_msg(Msg)]} end),
@@ -455,7 +461,10 @@ recv(S0 = #s{}) ->
};
#ssh_msg_kexdh_reply{} ->
{ok, _NewKeys, C} = ssh_transport:handle_kexdh_reply(PeerMsg, S#s.ssh),
- S#s{ssh=C#ssh{send_sequence=S#s.ssh#ssh.send_sequence}}; % Back the number
+ S#s{ssh = (S#s.ssh)#ssh{shared_secret = C#ssh.shared_secret,
+ exchanged_hash = C#ssh.exchanged_hash,
+ session_id = C#ssh.session_id}};
+ %%%S#s{ssh=C#ssh{send_sequence=S#s.ssh#ssh.send_sequence}}; % Back the number
#ssh_msg_newkeys{} ->
{ok, C} = ssh_transport:handle_new_keys(PeerMsg, S#s.ssh),
S#s{ssh=C};
--
cgit v1.2.3
From b7cba805e37e591d8fa7d7df06f9563a9f926e23 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 26 Apr 2017 12:08:01 +0200
Subject: ssh: state machine fixes for calls during re-negotiation
---
lib/ssh/src/ssh_connection_handler.erl | 47 +++++++++++++++-------------------
1 file changed, 20 insertions(+), 27 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 0ff7c9b3a1..128a9175f5 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -365,7 +365,7 @@ init_connection_handler(Role, Socket, Opts) ->
{ok, StartState, D} ->
process_flag(trap_exit, true),
gen_statem:enter_loop(?MODULE,
- [], %%[{debug,[trace,log,statistics,debug]} || Role==server],
+ [], %%[{debug,[trace,log,statistics,debug]} ], %% []
StartState,
D);
@@ -504,6 +504,10 @@ init_ssh_record(Role, _Socket, PeerAddr, Opts) ->
-type handle_event_result() :: gen_statem:handle_event_result().
+-define(CONNECTED(StateName),
+ (element(1,StateName) == connected orelse
+ element(1,StateName) == ext_info ) ).
+
-spec handle_event(gen_statem:event_type(),
event_content(),
state_name(),
@@ -1020,12 +1024,10 @@ handle_event(cast, data_size, _, _) ->
-handle_event(cast, _, StateName, _) when StateName /= {connected,server},
- StateName /= {connected,client} ->
+handle_event(cast, _, StateName, _) when not ?CONNECTED(StateName) ->
{keep_state_and_data, [postpone]};
-
-handle_event(cast, {adjust_window,ChannelId,Bytes}, {connected,_}, D) ->
+handle_event(cast, {adjust_window,ChannelId,Bytes}, StateName, D) when ?CONNECTED(StateName) ->
case ssh_channel:cache_lookup(cache(D), ChannelId) of
#channel{recv_window_size = WinSize,
recv_window_pending = Pending,
@@ -1051,7 +1053,7 @@ handle_event(cast, {adjust_window,ChannelId,Bytes}, {connected,_}, D) ->
keep_state_and_data
end;
-handle_event(cast, {reply_request,success,ChannelId}, {connected,_}, D) ->
+handle_event(cast, {reply_request,success,ChannelId}, StateName, D) when ?CONNECTED(StateName) ->
case ssh_channel:cache_lookup(cache(D), ChannelId) of
#channel{remote_id = RemoteId} ->
Msg = ssh_connection:channel_success_msg(RemoteId),
@@ -1062,13 +1064,13 @@ handle_event(cast, {reply_request,success,ChannelId}, {connected,_}, D) ->
keep_state_and_data
end;
-handle_event(cast, {request,ChannelPid, ChannelId, Type, Data}, {connected,_}, D) ->
+handle_event(cast, {request,ChannelPid, ChannelId, Type, Data}, StateName, D) when ?CONNECTED(StateName) ->
{keep_state, handle_request(ChannelPid, ChannelId, Type, Data, false, none, D)};
-handle_event(cast, {request,ChannelId,Type,Data}, {connected,_}, D) ->
+handle_event(cast, {request,ChannelId,Type,Data}, StateName, D) when ?CONNECTED(StateName) ->
{keep_state, handle_request(ChannelId, Type, Data, false, none, D)};
-handle_event(cast, {unknown,Data}, {connected,_}, D) ->
+handle_event(cast, {unknown,Data}, StateName, D) when ?CONNECTED(StateName) ->
Msg = #ssh_msg_unimplemented{sequence = Data},
{keep_state, send_msg(Msg,D)};
@@ -1129,29 +1131,25 @@ handle_event({call,From}, stop, StateName, D0) ->
{Repls,D} = send_replies(Replies, D0),
{stop_and_reply, normal, [{reply,From,ok}|Repls], D#data{connection_state=Connection}};
-handle_event({call,_}, _, StateName, _) when StateName /= {connected,server},
- StateName /= {connected,client} ->
+handle_event({call,_}, _, StateName, _) when not ?CONNECTED(StateName) ->
{keep_state_and_data, [postpone]};
handle_event({call,From}, {request, ChannelPid, ChannelId, Type, Data, Timeout}, StateName, D0)
- when element(1,StateName) == connected ;
- element(1,StateName) == ext_info ->
+ when ?CONNECTED(StateName) ->
D = handle_request(ChannelPid, ChannelId, Type, Data, true, From, D0),
%% Note reply to channel will happen later when reply is recived from peer on the socket
start_channel_request_timer(ChannelId, From, Timeout),
{keep_state, cache_request_idle_timer_check(D)};
handle_event({call,From}, {request, ChannelId, Type, Data, Timeout}, StateName, D0)
- when element(1,StateName) == connected ;
- element(1,StateName) == ext_info ->
+ when ?CONNECTED(StateName) ->
D = handle_request(ChannelId, Type, Data, true, From, D0),
%% Note reply to channel will happen later when reply is recived from peer on the socket
start_channel_request_timer(ChannelId, From, Timeout),
{keep_state, cache_request_idle_timer_check(D)};
handle_event({call,From}, {data, ChannelId, Type, Data, Timeout}, StateName, D0)
- when element(1,StateName) == connected ;
- element(1,StateName) == ext_info ->
+ when ?CONNECTED(StateName) ->
{{replies, Replies}, Connection} =
ssh_connection:channel_data(ChannelId, Type, Data, D0#data.connection_state, From),
{Repls,D} = send_replies(Replies, D0#data{connection_state = Connection}),
@@ -1159,8 +1157,7 @@ handle_event({call,From}, {data, ChannelId, Type, Data, Timeout}, StateName, D0)
{keep_state, D, Repls};
handle_event({call,From}, {eof, ChannelId}, StateName, D0)
- when element(1,StateName) == connected ;
- element(1,StateName) == ext_info ->
+ when ?CONNECTED(StateName) ->
case ssh_channel:cache_lookup(cache(D0), ChannelId) of
#channel{remote_id = Id, sent_close = false} ->
D = send_msg(ssh_connection:channel_eof_msg(Id), D0),
@@ -1172,8 +1169,7 @@ handle_event({call,From}, {eof, ChannelId}, StateName, D0)
handle_event({call,From},
{open, ChannelPid, Type, InitialWindowSize, MaxPacketSize, Data, Timeout},
StateName,
- D0) when element(1,StateName) == connected ;
- element(1,StateName) == ext_info ->
+ D0) when ?CONNECTED(StateName) ->
erlang:monitor(process, ChannelPid),
{ChannelId, D1} = new_channel_id(D0),
D2 = send_msg(ssh_connection:channel_open_msg(Type, ChannelId,
@@ -1194,8 +1190,7 @@ handle_event({call,From},
{keep_state, cache_cancel_idle_timer(D)};
handle_event({call,From}, {send_window, ChannelId}, StateName, D)
- when element(1,StateName) == connected ;
- element(1,StateName) == ext_info ->
+ when ?CONNECTED(StateName) ->
Reply = case ssh_channel:cache_lookup(cache(D), ChannelId) of
#channel{send_window_size = WinSize,
send_packet_size = Packsize} ->
@@ -1206,8 +1201,7 @@ handle_event({call,From}, {send_window, ChannelId}, StateName, D)
{keep_state_and_data, [{reply,From,Reply}]};
handle_event({call,From}, {recv_window, ChannelId}, StateName, D)
- when element(1,StateName) == connected ;
- element(1,StateName) == ext_info ->
+ when ?CONNECTED(StateName) ->
Reply = case ssh_channel:cache_lookup(cache(D), ChannelId) of
#channel{recv_window_size = WinSize,
recv_packet_size = Packsize} ->
@@ -1218,8 +1212,7 @@ handle_event({call,From}, {recv_window, ChannelId}, StateName, D)
{keep_state_and_data, [{reply,From,Reply}]};
handle_event({call,From}, {close, ChannelId}, StateName, D0)
- when element(1,StateName) == connected ;
- element(1,StateName) == ext_info ->
+ when ?CONNECTED(StateName) ->
case ssh_channel:cache_lookup(cache(D0), ChannelId) of
#channel{remote_id = Id} = Channel ->
D1 = send_msg(ssh_connection:channel_close_msg(Id), D0),
--
cgit v1.2.3
From 519f89016e7ce755775a88730814fa34af21676c Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 19 Apr 2017 12:01:26 +0200
Subject: ssh: server-sig-algs, client side
---
lib/ssh/src/ssh.hrl | 2 +-
lib/ssh/src/ssh_auth.erl | 85 +++++++++++++++-------------------
lib/ssh/src/ssh_connection_handler.erl | 23 +++++++--
lib/ssh/src/ssh_options.erl | 20 ++------
4 files changed, 61 insertions(+), 69 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh.hrl b/lib/ssh/src/ssh.hrl
index 1a95bb27e7..cf2a359e6c 100644
--- a/lib/ssh/src/ssh.hrl
+++ b/lib/ssh/src/ssh.hrl
@@ -38,7 +38,6 @@
-define(MAX_RND_PADDING_LEN, 15).
-define(SUPPORTED_AUTH_METHODS, "publickey,keyboard-interactive,password").
--define(SUPPORTED_USER_KEYS, ['ssh-rsa','ssh-dss','ecdsa-sha2-nistp256','ecdsa-sha2-nistp384','ecdsa-sha2-nistp521']).
-define(FALSE, 0).
-define(TRUE, 1).
@@ -201,6 +200,7 @@
userauth_quiet_mode, % boolean()
userauth_methods, % list( string() ) eg ["keyboard-interactive", "password"]
userauth_supported_methods, % string() eg "keyboard-interactive,password"
+ userauth_pubkeys,
kb_tries_left = 0, % integer(), num tries left for "keyboard-interactive"
userauth_preference,
available_host_keys,
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl
index 51df54341f..aadd1ad6dc 100644
--- a/lib/ssh/src/ssh_auth.erl
+++ b/lib/ssh/src/ssh_auth.erl
@@ -136,34 +136,40 @@ keyboard_interactive_msg([#ssh{user = User,
Ssh)
end.
-publickey_msg([Alg, #ssh{user = User,
+publickey_msg([SigAlg, #ssh{user = User,
session_id = SessionId,
service = Service,
opts = Opts} = Ssh]) ->
- Hash = ssh_transport:sha(Alg),
+ Hash = ssh_transport:sha(SigAlg),
+ KeyAlg = key_alg(SigAlg),
{KeyCb,KeyCbOpts} = ?GET_OPT(key_cb, Opts),
UserOpts = ?GET_OPT(user_options, Opts),
- case KeyCb:user_key(Alg, [{key_cb_private,KeyCbOpts}|UserOpts]) of
+ case KeyCb:user_key(KeyAlg, [{key_cb_private,KeyCbOpts}|UserOpts]) of
{ok, PrivKey} ->
- StrAlgo = atom_to_list(Alg),
- case encode_public_key(StrAlgo, ssh_transport:extract_public_key(PrivKey)) of
- not_ok ->
- {not_ok, Ssh};
+ SigAlgStr = atom_to_list(SigAlg),
+ try
+ Key = ssh_transport:extract_public_key(PrivKey),
+ public_key:ssh_encode(Key, ssh2_pubkey)
+ of
PubKeyBlob ->
- SigData = build_sig_data(SessionId,
- User, Service, PubKeyBlob, StrAlgo),
+ SigData = build_sig_data(SessionId, User, Service,
+ PubKeyBlob, SigAlgStr),
Sig = ssh_transport:sign(SigData, Hash, PrivKey),
- SigBlob = list_to_binary([?string(StrAlgo), ?binary(Sig)]),
+ SigBlob = list_to_binary([?string(SigAlgStr),
+ ?binary(Sig)]),
ssh_transport:ssh_packet(
#ssh_msg_userauth_request{user = User,
service = Service,
method = "publickey",
data = [?TRUE,
- ?string(StrAlgo),
+ ?string(SigAlgStr),
?binary(PubKeyBlob),
?binary(SigBlob)]},
Ssh)
- end;
+ catch
+ _:_ ->
+ {not_ok, Ssh}
+ end;
_Error ->
{not_ok, Ssh}
end.
@@ -190,8 +196,7 @@ init_userauth_request_msg(#ssh{opts = Opts} = Ssh) ->
method = "none",
data = <<>>},
Ssh#ssh{user = User,
- userauth_preference =
- method_preference(?GET_OPT(pref_public_key_algs, Opts)),
+ userauth_preference = method_preference(Ssh#ssh.userauth_pubkeys),
userauth_methods = none,
service = "ssh-connection"}
)
@@ -265,8 +270,7 @@ handle_userauth_request(#ssh_msg_userauth_request{user = User,
#ssh{opts = Opts,
userauth_supported_methods = Methods} = Ssh) ->
- case pre_verify_sig(User, binary_to_list(BAlg),
- KeyBlob, Opts) of
+ case pre_verify_sig(User, KeyBlob, Opts) of
true ->
{not_authorized, {User, undefined},
ssh_transport:ssh_packet(
@@ -446,10 +450,10 @@ handle_userauth_info_response(#ssh_msg_userauth_info_response{},
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
-method_preference(PubKeyAlgs) ->
+method_preference(SigKeyAlgs) ->
%% PubKeyAlgs: List of user (client) public key algorithms to try to use.
%% All of the acceptable algorithms is the default values.
- PubKeyDefs = [{"publickey", ?MODULE, publickey_msg, [A]} || A <- PubKeyAlgs],
+ PubKeyDefs = [{"publickey", ?MODULE, publickey_msg, [A]} || A <- SigKeyAlgs],
NonPKmethods = [{"password", ?MODULE, password_msg, []},
{"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []}
],
@@ -492,9 +496,9 @@ get_password_option(Opts, User) ->
false -> ?GET_OPT(password, Opts)
end.
-pre_verify_sig(User, Alg, KeyBlob, Opts) ->
+pre_verify_sig(User, KeyBlob, Opts) ->
try
- {ok, Key} = decode_public_key_v2(KeyBlob, Alg),
+ Key = public_key:ssh_decode(KeyBlob, ssh2_pubkey), % or exception
{KeyCb,KeyCbOpts} = ?GET_OPT(key_cb, Opts),
UserOpts = ?GET_OPT(user_options, Opts),
KeyCb:is_auth_key(Key, User, [{key_cb_private,KeyCbOpts}|UserOpts])
@@ -505,21 +509,19 @@ pre_verify_sig(User, Alg, KeyBlob, Opts) ->
verify_sig(SessionId, User, Service, Alg, KeyBlob, SigWLen, Opts) ->
try
- {ok, Key} = decode_public_key_v2(KeyBlob, Alg),
-
{KeyCb,KeyCbOpts} = ?GET_OPT(key_cb, Opts),
UserOpts = ?GET_OPT(user_options, Opts),
- case KeyCb:is_auth_key(Key, User, [{key_cb_private,KeyCbOpts}|UserOpts]) of
- true ->
- PlainText = build_sig_data(SessionId, User,
- Service, KeyBlob, Alg),
- <> = SigWLen,
- <> = AlgSig,
- ssh_transport:verify(PlainText, ssh_transport:sha(list_to_atom(Alg)), Sig, Key);
- false ->
- false
- end
+ Key0 = public_key:ssh_decode(KeyBlob, ssh2_pubkey), % or exception
+ true = KeyCb:is_auth_key(Key0, User, [{key_cb_private,KeyCbOpts}|UserOpts]),
+ Key0
+ of
+ Key ->
+ PlainText = build_sig_data(SessionId, User, Service,
+ KeyBlob, Alg),
+ <> = SigWLen,
+ <> = AlgSig,
+ ssh_transport:verify(PlainText, ssh_transport:sha(list_to_atom(Alg)), Sig, Key)
catch
_:_ ->
false
@@ -591,18 +593,7 @@ keyboard_interact_fun(KbdInteractFun, Name, Instr, PromptInfos, NumPrompts) ->
language = "en"}})
end.
-decode_public_key_v2(Bin, _Type) ->
- try
- public_key:ssh_decode(Bin, ssh2_pubkey)
- of
- Key -> {ok, Key}
- catch
- _:_ -> {error, bad_format}
- end.
-encode_public_key(_Alg, Key) ->
- try
- public_key:ssh_encode(Key, ssh2_pubkey)
- catch
- _:_ -> not_ok
- end.
+key_alg('rsa-sha2-256') -> 'ssh-rsa';
+key_alg('rsa-sha2-512') -> 'ssh-rsa';
+key_alg(Alg) -> Alg.
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 128a9175f5..ac1b792f32 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -464,6 +464,7 @@ init_ssh_record(Role, _Socket, PeerAddr, Opts) ->
true -> ssh_io;
false -> ssh_no_io
end,
+ userauth_pubkeys = ?GET_OPT(pref_public_key_algs, Opts),
userauth_quiet_mode = ?GET_OPT(quiet_mode, Opts),
peer = {PeerName, PeerAddr}
};
@@ -711,7 +712,7 @@ handle_event(internal, Msg, {ext_info,Role,init}, D) when is_tuple(Msg) ->
%% If something else arrives, goto next state and handle the event in that one
{next_state, {service_request,Role}, D, [postpone]};
-handle_event(internal, Msg, {ext_info,Role,renegotiate}, D) when is_tuple(Msg) ->
+handle_event(internal, Msg, {ext_info,Role,_ReNegFlag}, D) when is_tuple(Msg) ->
%% If something else arrives, goto next state and handle the event in that one
{next_state, {connected,Role}, D, [postpone]};
@@ -1131,6 +1132,7 @@ handle_event({call,From}, stop, StateName, D0) ->
{Repls,D} = send_replies(Replies, D0),
{stop_and_reply, normal, [{reply,From,ok}|Repls], D#data{connection_state=Connection}};
+
handle_event({call,_}, _, StateName, _) when not ?CONNECTED(StateName) ->
{keep_state_and_data, [postpone]};
@@ -1380,12 +1382,16 @@ handle_event(info, UnexpectedMessage, StateName, D = #data{ssh_params = Ssh}) ->
handle_event(internal, {disconnect,Msg,_Reason}, StateName, D) ->
disconnect(Msg, StateName, D);
+handle_event(_Type, _Msg, {ext_info,Role,_ReNegFlag}, D) ->
+ %% If something else arrives, goto next state and handle the event in that one
+ {next_state, {connected,Role}, D, [postpone]};
+
handle_event(Type, Ev, StateName, D) ->
Descr =
case catch atom_to_list(element(1,Ev)) of
"ssh_msg_" ++_ when Type==internal ->
%% "Message in wrong state";
-lists:flatten(io_lib:format("Message ~p in wrong state (~p)", [element(1,Ev), StateName]));
+ lists:flatten(io_lib:format("Message ~p in wrong state (~p)", [element(1,Ev), StateName]));
_ ->
"Internal error"
end,
@@ -1689,11 +1695,20 @@ cache(#data{connection_state=C}) -> C#connection.channel_cache.
handle_ssh_msg_ext_info(#ssh_msg_ext_info{}, D=#data{ssh_params = #ssh{recv_ext_info=false}} ) ->
% The peer sent this although we didn't allow it!
D;
+
handle_ssh_msg_ext_info(#ssh_msg_ext_info{data=Data}, D0) ->
lists:foldl(fun ext_info/2, D0, Data).
-%% ext_info({ExtName,ExtValue}, D0) ->
-%% D0;
+
+ext_info({"server-sig-algs",SigAlgs}, D0 = #data{ssh_params=#ssh{role=client}=Ssh0}) ->
+ %% Make strings to eliminate risk of beeing bombed with odd strings that fills the atom table:
+ SupportedAlgs = lists:map(fun erlang:atom_to_list/1, ssh_transport:supported_algorithms(public_key)),
+ Ssh = Ssh0#ssh{userauth_pubkeys =
+ [list_to_atom(SigAlg) || SigAlg <- string:tokens(SigAlgs,","),
+ lists:member(SigAlg, SupportedAlgs)
+ ]},
+ D0#data{ssh_params = Ssh};
+
ext_info(_, D0) ->
%% Not implemented
D0.
diff --git a/lib/ssh/src/ssh_options.erl b/lib/ssh/src/ssh_options.erl
index 6e898b4fde..0886d5b34d 100644
--- a/lib/ssh/src/ssh_options.erl
+++ b/lib/ssh/src/ssh_options.erl
@@ -437,9 +437,7 @@ default(client) ->
{pref_public_key_algs, def} =>
#{default =>
- %% Get dynamically supported keys in the order of the ?SUPPORTED_USER_KEYS
- [A || A <- ?SUPPORTED_USER_KEYS,
- lists:member(A, ssh_transport:supported_algorithms(public_key))],
+ ssh_transport:supported_algorithms(public_key),
chk =>
fun check_pref_public_key_algs/1,
class =>
@@ -670,20 +668,8 @@ check_pref_public_key_algs(V) ->
PKs = ssh_transport:supported_algorithms(public_key),
CHK = fun(A, Ack) ->
case lists:member(A, PKs) of
- true ->
- [A|Ack];
- false ->
- %% Check with the documented options, that is,
- %% the one we can handle
- case lists:member(A,?SUPPORTED_USER_KEYS) of
- false ->
- %% An algorithm ssh never can handle
- error_in_check(A, "Not supported public key");
- true ->
- %% An algorithm ssh can handle, but not in
- %% this very call
- Ack
- end
+ true -> [A|Ack];
+ false -> error_in_check(A, "Not supported public key")
end
end,
case lists:foldr(
--
cgit v1.2.3
From a053401a7a7142d4d2a068b2945ef91cb7957f89 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 19 Apr 2017 14:04:05 +0200
Subject: ssh: server-sig-algs, server side
---
lib/ssh/src/ssh_transport.erl | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index d623d24529..3c2c345261 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -710,12 +710,12 @@ kex_ext_info(Role, Opts) ->
end.
ext_info_message(#ssh{role=client,
- algorithms=#alg{send_ext_info=true}} = Ssh0) ->
- %% FIXME: no extensions implemented for clients
+ send_ext_info=true} = Ssh0) ->
+ %% FIXME: no extensions implemented
{ok, "", Ssh0};
ext_info_message(#ssh{role=server,
- algorithms=#alg{send_ext_info=true}} = Ssh0) ->
+ send_ext_info=true} = Ssh0) ->
AlgsList = lists:map(fun erlang:atom_to_list/1,
ssh_transport:default_algorithms(public_key)),
Msg = #ssh_msg_ext_info{nr_extensions = 1,
@@ -729,10 +729,8 @@ ext_info_message(Ssh0) ->
%%%----------------------------------------------------------------
%% select session id
-sid(#ssh{session_id = undefined}, H) ->
- H;
-sid(#ssh{session_id = Id}, _) ->
- Id.
+sid(#ssh{session_id = undefined}, H) -> H;
+sid(#ssh{session_id = Id}, _) -> Id.
%%
%% The host key should be read from storage
--
cgit v1.2.3
From 2e55f44545504aa1ba109e072e6833f5c045b58f Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 19 Apr 2017 14:10:29 +0200
Subject: ssh: Implement signature algorithms rsa-sha2-*.
draft-ietf-curdle-rsa-sha2
---
lib/ssh/src/ssh_connection_handler.erl | 53 +++++----
lib/ssh/src/ssh_file.erl | 24 ++--
lib/ssh/src/ssh_message.erl | 19 ++-
lib/ssh/src/ssh_transport.erl | 205 ++++++++++++++++++---------------
4 files changed, 167 insertions(+), 134 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index ac1b792f32..220b05e6b0 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -490,20 +490,32 @@ init_ssh_record(Role, _Socket, PeerAddr, Opts) ->
-type renegotiate_flag() :: init | renegotiate.
-type state_name() ::
- {hello, role()}
- | {kexinit, role(), renegotiate_flag()}
- | {key_exchange, role(), renegotiate_flag()}
- | {key_exchange_dh_gex_init, server, renegotiate_flag()}
+ {hello, role() }
+ | {kexinit, role(), renegotiate_flag()}
+ | {key_exchange, role(), renegotiate_flag()}
+ | {key_exchange_dh_gex_init, server, renegotiate_flag()}
| {key_exchange_dh_gex_reply, client, renegotiate_flag()}
- | {new_keys, role()}
- | {ext_info, role(), renegotiate_flag()}
- | {service_request, role()}
- | {userauth, role()}
- | {userauth_keyboard_interactive, role()}
- | {connected, role()}
+ | {new_keys, role(), renegotiate_flag()}
+ | {ext_info, role(), renegotiate_flag()}
+ | {service_request, role() }
+ | {userauth, role() }
+ | {userauth_keyboard_interactive, role() }
+ | {userauth_keyboard_interactive_extra, server }
+ | {userauth_keyboard_interactive_info_response, client }
+ | {connected, role() }
.
--type handle_event_result() :: gen_statem:handle_event_result().
+%% The state names must fulfill some rules regarding
+%% where the role() and the renegotiate_flag() is placed:
+
+-spec role(state_name()) -> role().
+role({_,Role}) -> Role;
+role({_,Role,_}) -> Role.
+
+-spec renegotiation(state_name()) -> boolean().
+renegotiation({_,_,ReNeg}) -> ReNeg == renegotiation;
+renegotiation(_) -> false.
+
-define(CONNECTED(StateName),
(element(1,StateName) == connected orelse
@@ -513,7 +525,7 @@ init_ssh_record(Role, _Socket, PeerAddr, Opts) ->
event_content(),
state_name(),
#data{}
- ) -> handle_event_result().
+ ) -> gen_statem:event_handler_result(state_name()) .
%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
@@ -1530,16 +1542,6 @@ finalize_termination(_StateName, #data{transport_cb = Transport,
peer_role(client) -> server;
peer_role(server) -> client.
-%%--------------------------------------------------------------------
-%% StateName to Role
-role({_,Role}) -> Role;
-role({_,Role,_}) -> Role.
-
-%%--------------------------------------------------------------------
-%% Check the StateName to see if we are in the renegotiation phase
-renegotiation({_,_,ReNeg}) -> ReNeg == renegotiation;
-renegotiation(_) -> false.
-
%%--------------------------------------------------------------------
supported_host_keys(client, _, Options) ->
try
@@ -1576,8 +1578,11 @@ find_sup_hkeys(Options) ->
%% Alg :: atom()
available_host_key({KeyCb,KeyCbOpts}, Alg, Opts) ->
UserOpts = ?GET_OPT(user_options, Opts),
- element(1,
- catch KeyCb:host_key(Alg, [{key_cb_private,KeyCbOpts}|UserOpts])) == ok.
+ case KeyCb:host_key(Alg, [{key_cb_private,KeyCbOpts}|UserOpts]) of
+ {ok,_} -> true;
+ _ -> false
+ end.
+
send_msg(Msg, State=#data{ssh_params=Ssh0}) when is_tuple(Msg) ->
{Bytes, Ssh} = ssh_transport:ssh_packet(Msg, Ssh0),
diff --git a/lib/ssh/src/ssh_file.erl b/lib/ssh/src/ssh_file.erl
index 88f4d10792..4498c70d34 100644
--- a/lib/ssh/src/ssh_file.erl
+++ b/lib/ssh/src/ssh_file.erl
@@ -75,17 +75,12 @@ host_key(Algorithm, Opts) ->
Password = proplists:get_value(identity_pass_phrase(Algorithm), Opts, ignore),
case decode(File, Password) of
{ok,Key} ->
- case {Key,Algorithm} of
- {#'RSAPrivateKey'{}, 'ssh-rsa'} -> {ok,Key};
- {#'DSAPrivateKey'{}, 'ssh-dss'} -> {ok,Key};
- {#'ECPrivateKey'{parameters = {namedCurve, ?'secp256r1'}}, 'ecdsa-sha2-nistp256'} -> {ok,Key};
- {#'ECPrivateKey'{parameters = {namedCurve, ?'secp384r1'}}, 'ecdsa-sha2-nistp384'} -> {ok,Key};
- {#'ECPrivateKey'{parameters = {namedCurve, ?'secp521r1'}}, 'ecdsa-sha2-nistp521'} -> {ok,Key};
- _ ->
- {error,bad_keytype_in_file}
+ case ssh_transport:valid_key_sha_alg(Key,Algorithm) of
+ true -> {ok,Key};
+ false -> {error,bad_keytype_in_file}
end;
- Other ->
- Other
+ {error,DecodeError} ->
+ {error,DecodeError}
end.
is_auth_key(Key, User,Opts) ->
@@ -115,6 +110,9 @@ user_key(Algorithm, Opts) ->
%% Internal functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
file_base_name('ssh-rsa' ) -> "ssh_host_rsa_key";
+file_base_name('rsa-sha2-256' ) -> "ssh_host_rsa_key";
+file_base_name('rsa-sha2-384' ) -> "ssh_host_rsa_key";
+file_base_name('rsa-sha2-512' ) -> "ssh_host_rsa_key";
file_base_name('ssh-dss' ) -> "ssh_host_dsa_key";
file_base_name('ecdsa-sha2-nistp256') -> "ssh_host_ecdsa_key";
file_base_name('ecdsa-sha2-nistp384') -> "ssh_host_ecdsa_key";
@@ -253,12 +251,18 @@ do_lookup_host_key(KeyToMatch, Host, Alg, Opts) ->
identity_key_filename('ssh-dss' ) -> "id_dsa";
identity_key_filename('ssh-rsa' ) -> "id_rsa";
+identity_key_filename('rsa-sha2-256' ) -> "id_rsa";
+identity_key_filename('rsa-sha2-384' ) -> "id_rsa";
+identity_key_filename('rsa-sha2-512' ) -> "id_rsa";
identity_key_filename('ecdsa-sha2-nistp256') -> "id_ecdsa";
identity_key_filename('ecdsa-sha2-nistp384') -> "id_ecdsa";
identity_key_filename('ecdsa-sha2-nistp521') -> "id_ecdsa".
identity_pass_phrase("ssh-dss" ) -> dsa_pass_phrase;
identity_pass_phrase("ssh-rsa" ) -> rsa_pass_phrase;
+identity_pass_phrase("rsa-sha2-256" ) -> rsa_pass_phrase;
+identity_pass_phrase("rsa-sha2-384" ) -> rsa_pass_phrase;
+identity_pass_phrase("rsa-sha2-512" ) -> rsa_pass_phrase;
identity_pass_phrase("ecdsa-sha2-"++_) -> ecdsa_pass_phrase;
identity_pass_phrase(P) when is_atom(P) ->
identity_pass_phrase(atom_to_list(P)).
diff --git a/lib/ssh/src/ssh_message.erl b/lib/ssh/src/ssh_message.erl
index 56f678876c..21c0eabcd3 100644
--- a/lib/ssh/src/ssh_message.erl
+++ b/lib/ssh/src/ssh_message.erl
@@ -602,11 +602,22 @@ decode_signature(<>) ->
Signature.
-encode_signature(#'RSAPublicKey'{}, Signature) ->
- <>), ?Ebinary(Signature)>>;
-encode_signature({_, #'Dss-Parms'{}}, Signature) ->
+encode_signature({#'RSAPublicKey'{},Sign}, Signature) ->
+ SignName = list_to_binary(atom_to_list(Sign)),
+ <>;
+encode_signature({{_, #'Dss-Parms'{}},_}, Signature) ->
<>), ?Ebinary(Signature)>>;
-encode_signature({#'ECPoint'{}, {namedCurve,OID}}, Signature) ->
+encode_signature({{#'ECPoint'{}, {namedCurve,OID}},_}, Signature) ->
CurveName = public_key:oid2ssh_curvename(OID),
<>), ?Ebinary(Signature)>>.
+%% encode_signature(#'RSAPublicKey'{}, Signature) ->
+%% SignName = <<"ssh-rsa">>,
+%% <>;
+%% encode_signature({_, #'Dss-Parms'{}}, Signature) ->
+%% <>), ?Ebinary(Signature)>>;
+%% encode_signature({#'ECPoint'{}, {namedCurve,OID}}, Signature) ->
+%% CurveName = public_key:oid2ssh_curvename(OID),
+%% <>), ?Ebinary(Signature)>>.
+
+
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 3c2c345261..3cf1e60634 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -48,6 +48,7 @@
parallell_gen_key/1,
extract_public_key/1,
ssh_packet/2, pack/2,
+ valid_key_sha_alg/2,
sha/1, sign/3, verify/4]).
%%% For test suites
@@ -117,6 +118,9 @@ supported_algorithms(public_key) ->
{'ecdsa-sha2-nistp384', [{public_keys,ecdsa}, {hashs,sha384}, {ec_curve,secp384r1}]},
{'ecdsa-sha2-nistp521', [{public_keys,ecdsa}, {hashs,sha512}, {ec_curve,secp521r1}]},
{'ecdsa-sha2-nistp256', [{public_keys,ecdsa}, {hashs,sha256}, {ec_curve,secp256r1}]},
+ {'rsa-sha2-256', [{public_keys,rsa}, {hashs,sha256} ]},
+ {'rsa-sha2-384', [{public_keys,rsa}, {hashs,sha384} ]},
+ {'rsa-sha2-512', [{public_keys,rsa}, {hashs,sha512} ]},
{'ssh-rsa', [{public_keys,rsa}, {hashs,sha} ]},
{'ssh-dss', [{public_keys,dss}, {hashs,sha} ]} % Gone in OpenSSH 7.3.p1
]);
@@ -377,7 +381,8 @@ key_exchange_first_msg(Kex, Ssh0) when Kex == 'ecdh-sha2-nistp256' ;
%%% diffie-hellman-group18-sha512
%%%
handle_kexdh_init(#ssh_msg_kexdh_init{e = E},
- Ssh0 = #ssh{algorithms = #alg{kex=Kex} = Algs}) ->
+ Ssh0 = #ssh{algorithms = #alg{kex=Kex,
+ hkey=SignAlg} = Algs}) ->
%% server
{G, P} = dh_group(Kex),
if
@@ -385,12 +390,12 @@ handle_kexdh_init(#ssh_msg_kexdh_init{e = E},
Sz = dh_bits(Algs),
{Public, Private} = generate_key(dh, [P,G,2*Sz]),
K = compute_key(dh, E, Private, [P,G]),
- MyPrivHostKey = get_host_key(Ssh0),
+ MyPrivHostKey = get_host_key(Ssh0, SignAlg),
MyPubHostKey = extract_public_key(MyPrivHostKey),
- H = kex_h(Ssh0, MyPubHostKey, E, Public, K),
- H_SIG = sign_host_key(Ssh0, MyPrivHostKey, H),
+ H = kex_hash(Ssh0, MyPubHostKey, SignAlg, sha(Kex), {E,Public,K}),
+ H_SIG = sign(H, sha(SignAlg), MyPrivHostKey),
{SshPacket, Ssh1} =
- ssh_packet(#ssh_msg_kexdh_reply{public_host_key = MyPubHostKey,
+ ssh_packet(#ssh_msg_kexdh_reply{public_host_key = {MyPubHostKey,SignAlg},
f = Public,
h_sig = H_SIG
}, Ssh0),
@@ -411,13 +416,14 @@ handle_kexdh_init(#ssh_msg_kexdh_init{e = E},
handle_kexdh_reply(#ssh_msg_kexdh_reply{public_host_key = PeerPubHostKey,
f = F,
h_sig = H_SIG},
- #ssh{keyex_key = {{Private, Public}, {G, P}}} = Ssh0) ->
+ #ssh{keyex_key = {{Private, Public}, {G, P}},
+ algorithms = #alg{kex=Kex,
+ hkey=SignAlg}} = Ssh0) ->
%% client
if
1=
K = compute_key(dh, F, Private, [P,G]),
- H = kex_h(Ssh0, PeerPubHostKey, Public, F, K),
-
+ H = kex_hash(Ssh0, PeerPubHostKey, SignAlg, sha(Kex), {Public,F,K}),
case verify_host_key(Ssh0, PeerPubHostKey, H, H_SIG) of
ok ->
{SshPacket, Ssh} = ssh_packet(#ssh_msg_newkeys{}, Ssh0),
@@ -493,7 +499,7 @@ handle_kex_dh_gex_request(#ssh_msg_kex_dh_gex_request_old{n = NBits},
ssh_packet(#ssh_msg_kex_dh_gex_group{p = P, g = G}, Ssh0),
{ok, SshPacket,
Ssh#ssh{keyex_key = {x, {G, P}},
- keyex_info = {-1, -1, NBits} % flag for kex_h hash calc
+ keyex_info = {-1, -1, NBits} % flag for kex_hash calc
}};
{error,_} ->
ssh_connection_handler:disconnect(
@@ -539,20 +545,21 @@ handle_kex_dh_gex_group(#ssh_msg_kex_dh_gex_group{p = P, g = G}, Ssh0) ->
handle_kex_dh_gex_init(#ssh_msg_kex_dh_gex_init{e = E},
#ssh{keyex_key = {{Private, Public}, {G, P}},
- keyex_info = {Min, Max, NBits}} =
- Ssh0) ->
+ keyex_info = {Min, Max, NBits},
+ algorithms = #alg{kex=Kex,
+ hkey=SignAlg}} = Ssh0) ->
%% server
if
1=
K = compute_key(dh, E, Private, [P,G]),
if
1
- MyPrivHostKey = get_host_key(Ssh0),
+ MyPrivHostKey = get_host_key(Ssh0, SignAlg),
MyPubHostKey = extract_public_key(MyPrivHostKey),
- H = kex_h(Ssh0, MyPubHostKey, Min, NBits, Max, P, G, E, Public, K),
- H_SIG = sign_host_key(Ssh0, MyPrivHostKey, H),
+ H = kex_hash(Ssh0, MyPubHostKey, SignAlg, sha(Kex), {Min,NBits,Max,P,G,E,Public,K}),
+ H_SIG = sign(H, sha(SignAlg), MyPrivHostKey),
{SshPacket, Ssh} =
- ssh_packet(#ssh_msg_kex_dh_gex_reply{public_host_key = MyPubHostKey,
+ ssh_packet(#ssh_msg_kex_dh_gex_reply{public_host_key = {MyPubHostKey,SignAlg},
f = Public,
h_sig = H_SIG}, Ssh0),
{ok, SshPacket, Ssh#ssh{shared_secret = ssh_bits:mpint(K),
@@ -578,7 +585,9 @@ handle_kex_dh_gex_reply(#ssh_msg_kex_dh_gex_reply{public_host_key = PeerPubHostK
f = F,
h_sig = H_SIG},
#ssh{keyex_key = {{Private, Public}, {G, P}},
- keyex_info = {Min, Max, NBits}} =
+ keyex_info = {Min, Max, NBits},
+ algorithms = #alg{kex=Kex,
+ hkey=SignAlg}} =
Ssh0) ->
%% client
if
@@ -586,8 +595,7 @@ handle_kex_dh_gex_reply(#ssh_msg_kex_dh_gex_reply{public_host_key = PeerPubHostK
K = compute_key(dh, F, Private, [P,G]),
if
1
- H = kex_h(Ssh0, PeerPubHostKey, Min, NBits, Max, P, G, Public, F, K),
-
+ H = kex_hash(Ssh0, PeerPubHostKey, SignAlg, sha(Kex), {Min,NBits,Max,P,G,Public,F,K}),
case verify_host_key(Ssh0, PeerPubHostKey, H, H_SIG) of
ok ->
{SshPacket, Ssh} = ssh_packet(#ssh_msg_newkeys{}, Ssh0),
@@ -623,7 +631,8 @@ handle_kex_dh_gex_reply(#ssh_msg_kex_dh_gex_reply{public_host_key = PeerPubHostK
%%% diffie-hellman-ecdh-sha2-*
%%%
handle_kex_ecdh_init(#ssh_msg_kex_ecdh_init{q_c = PeerPublic},
- Ssh0 = #ssh{algorithms = #alg{kex=Kex}}) ->
+ Ssh0 = #ssh{algorithms = #alg{kex=Kex,
+ hkey=SignAlg}}) ->
%% at server
Curve = ecdh_curve(Kex),
{MyPublic, MyPrivate} = generate_key(ecdh, Curve),
@@ -631,12 +640,12 @@ handle_kex_ecdh_init(#ssh_msg_kex_ecdh_init{q_c = PeerPublic},
compute_key(ecdh, PeerPublic, MyPrivate, Curve)
of
K ->
- MyPrivHostKey = get_host_key(Ssh0),
+ MyPrivHostKey = get_host_key(Ssh0, SignAlg),
MyPubHostKey = extract_public_key(MyPrivHostKey),
- H = kex_h(Ssh0, Curve, MyPubHostKey, PeerPublic, MyPublic, K),
- H_SIG = sign_host_key(Ssh0, MyPrivHostKey, H),
+ H = kex_hash(Ssh0, MyPubHostKey, SignAlg, sha(Curve), {PeerPublic, MyPublic, K}),
+ H_SIG = sign(H, sha(SignAlg), MyPrivHostKey),
{SshPacket, Ssh1} =
- ssh_packet(#ssh_msg_kex_ecdh_reply{public_host_key = MyPubHostKey,
+ ssh_packet(#ssh_msg_kex_ecdh_reply{public_host_key = {MyPubHostKey,SignAlg},
q_s = MyPublic,
h_sig = H_SIG},
Ssh0),
@@ -656,14 +665,15 @@ handle_kex_ecdh_init(#ssh_msg_kex_ecdh_init{q_c = PeerPublic},
handle_kex_ecdh_reply(#ssh_msg_kex_ecdh_reply{public_host_key = PeerPubHostKey,
q_s = PeerPublic,
h_sig = H_SIG},
- #ssh{keyex_key = {{MyPublic,MyPrivate}, Curve}} = Ssh0
+ #ssh{keyex_key = {{MyPublic,MyPrivate}, Curve},
+ algorithms = #alg{hkey=SignAlg}} = Ssh0
) ->
%% at client
try
compute_key(ecdh, PeerPublic, MyPrivate, Curve)
of
K ->
- H = kex_h(Ssh0, Curve, PeerPubHostKey, MyPublic, PeerPublic, K),
+ H = kex_hash(Ssh0, PeerPubHostKey, SignAlg, sha(Curve), {MyPublic,PeerPublic,K}),
case verify_host_key(Ssh0, PeerPubHostKey, H, H_SIG) of
ok ->
{SshPacket, Ssh} = ssh_packet(#ssh_msg_newkeys{}, Ssh0),
@@ -735,25 +745,14 @@ sid(#ssh{session_id = Id}, _) -> Id.
%%
%% The host key should be read from storage
%%
-get_host_key(SSH) ->
- #ssh{key_cb = {KeyCb,KeyCbOpts}, opts = Opts, algorithms = ALG} = SSH,
+get_host_key(SSH, SignAlg) ->
+ #ssh{key_cb = {KeyCb,KeyCbOpts}, opts = Opts} = SSH,
UserOpts = ?GET_OPT(user_options, Opts),
- case KeyCb:host_key(ALG#alg.hkey, [{key_cb_private,KeyCbOpts}|UserOpts]) of
- {ok, #'RSAPrivateKey'{} = Key} -> Key;
- {ok, #'DSAPrivateKey'{} = Key} -> Key;
- {ok, #'ECPrivateKey'{} = Key} -> Key;
- Result ->
- exit({error, {Result, unsupported_key_type}})
+ case KeyCb:host_key(SignAlg, [{key_cb_private,KeyCbOpts}|UserOpts]) of
+ {ok, PrivHostKey} -> PrivHostKey;
+ Result -> exit({error, {Result, unsupported_key_type}})
end.
-sign_host_key(_Ssh, PrivateKey, H) ->
- sign(H, sign_host_key_sha(PrivateKey), PrivateKey).
-
-sign_host_key_sha(#'ECPrivateKey'{parameters = {namedCurve,OID}}) -> sha(OID);
-sign_host_key_sha(#'RSAPrivateKey'{}) -> sha;
-sign_host_key_sha(#'DSAPrivateKey'{}) -> sha.
-
-
extract_public_key(#'RSAPrivateKey'{modulus = N, publicExponent = E}) ->
#'RSAPublicKey'{modulus = N, publicExponent = E};
extract_public_key(#'DSAPrivateKey'{y = Y, p = P, q = Q, g = G}) ->
@@ -763,8 +762,8 @@ extract_public_key(#'ECPrivateKey'{parameters = {namedCurve,OID},
{#'ECPoint'{point=Q}, {namedCurve,OID}}.
-verify_host_key(SSH, PublicKey, Digest, Signature) ->
- case verify(Digest, host_key_sha(PublicKey), Signature, PublicKey) of
+verify_host_key(#ssh{algorithms=Alg}=SSH, PublicKey, Digest, Signature) ->
+ case verify(Digest, sha(Alg#alg.hkey), Signature, PublicKey) of
false ->
{error, bad_signature};
true ->
@@ -772,16 +771,6 @@ verify_host_key(SSH, PublicKey, Digest, Signature) ->
end.
-host_key_sha(#'RSAPublicKey'{}) -> sha;
-host_key_sha({_, #'Dss-Parms'{}}) -> sha;
-host_key_sha({#'ECPoint'{},{namedCurve,OID}}) -> sha(OID).
-
-public_algo(#'RSAPublicKey'{}) -> 'ssh-rsa';
-public_algo({_, #'Dss-Parms'{}}) -> 'ssh-dss';
-public_algo({#'ECPoint'{},{namedCurve,OID}}) ->
- Curve = public_key:oid2ssh_curvename(OID),
- list_to_atom("ecdsa-sha2-" ++ binary_to_list(Curve)).
-
accepted_host(Ssh, PeerName, Public, Opts) ->
case ?GET_OPT(silently_accept_hosts, Opts) of
@@ -1201,29 +1190,29 @@ payload(<>) ->
<> = PayloadAndPadding,
Payload.
-sign(SigData, Hash, #'DSAPrivateKey'{} = Key) ->
- DerSignature = public_key:sign(SigData, Hash, Key),
+sign(SigData, HashAlg, #'DSAPrivateKey'{} = Key) ->
+ DerSignature = public_key:sign(SigData, HashAlg, Key),
#'Dss-Sig-Value'{r = R, s = S} = public_key:der_decode('Dss-Sig-Value', DerSignature),
<>;
-sign(SigData, Hash, Key = #'ECPrivateKey'{}) ->
- DerEncodedSign = public_key:sign(SigData, Hash, Key),
+sign(SigData, HashAlg, Key = #'ECPrivateKey'{}) ->
+ DerEncodedSign = public_key:sign(SigData, HashAlg, Key),
#'ECDSA-Sig-Value'{r=R, s=S} = public_key:der_decode('ECDSA-Sig-Value', DerEncodedSign),
<>;
-sign(SigData, Hash, Key) ->
- public_key:sign(SigData, Hash, Key).
+sign(SigData, HashAlg, Key) ->
+ public_key:sign(SigData, HashAlg, Key).
-verify(PlainText, Hash, Sig, {_, #'Dss-Parms'{}} = Key) ->
+verify(PlainText, HashAlg, Sig, {_, #'Dss-Parms'{}} = Key) ->
<> = Sig,
Signature = public_key:der_encode('Dss-Sig-Value', #'Dss-Sig-Value'{r = R, s = S}),
- public_key:verify(PlainText, Hash, Signature, Key);
-verify(PlainText, Hash, Sig, {#'ECPoint'{},_} = Key) ->
+ public_key:verify(PlainText, HashAlg, Signature, Key);
+verify(PlainText, HashAlg, Sig, {#'ECPoint'{},_} = Key) ->
<> = Sig,
Sval = #'ECDSA-Sig-Value'{r=R, s=S},
DerEncodedSig = public_key:der_encode('ECDSA-Sig-Value',Sval),
- public_key:verify(PlainText, Hash, DerEncodedSig, Key);
-verify(PlainText, Hash, Sig, Key) ->
- public_key:verify(PlainText, Hash, Sig, Key).
+ public_key:verify(PlainText, HashAlg, DerEncodedSig, Key);
+verify(PlainText, HashAlg, Sig, Key) ->
+ public_key:verify(PlainText, HashAlg, Sig, Key).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1730,39 +1719,63 @@ hash(K, H, Ki, N, HashAlg) ->
hash(K, H, <>, N-128, HashAlg).
%%%----------------------------------------------------------------
-kex_h(SSH, Key, E, F, K) ->
- KeyBin = public_key:ssh_encode(Key, ssh2_pubkey),
- L = <>,
- crypto:hash(sha((SSH#ssh.algorithms)#alg.kex), L).
-
-kex_h(SSH, Curve, Key, Q_c, Q_s, K) ->
- KeyBin = public_key:ssh_encode(Key, ssh2_pubkey),
- L = <>,
- crypto:hash(sha(Curve), L).
-
-kex_h(SSH, Key, Min, NBits, Max, Prime, Gen, E, F, K) ->
- KeyBin = public_key:ssh_encode(Key, ssh2_pubkey),
- L = if Min==-1; Max==-1 ->
- %% flag from 'ssh_msg_kex_dh_gex_request_old'
- %% It was like this before that message was supported,
- %% why?
- <>;
- true ->
- <>
- end,
- crypto:hash(sha((SSH#ssh.algorithms)#alg.kex), L).
-
+kex_hash(SSH, Key, SignAlg, HashAlg, Args) ->
+ crypto:hash(HashAlg, kex_plaintext(SSH,Key,SignAlg,Args)).
+
+kex_plaintext(SSH, Key, SignAlg, Args) ->
+ EncodedKey = public_key:ssh_encode({Key,SignAlg}, ssh2_pubkey),
+ <>.
+
+kex_alg_dependent({E, F, K}) ->
+ %% diffie-hellman and ec diffie-hellman (with E = Q_c, F = Q_s)
+ <>;
+
+kex_alg_dependent({-1, _, -1, _, _, E, F, K}) ->
+ %% ssh_msg_kex_dh_gex_request_old
+ <>;
+
+kex_alg_dependent({Min, NBits, Max, Prime, Gen, E, F, K}) ->
+ %% diffie-hellman group exchange
+ <>.
+
+%%%----------------------------------------------------------------
+
+valid_key_sha_alg(#'RSAPublicKey'{}, 'rsa-sha2-512') -> true;
+valid_key_sha_alg(#'RSAPublicKey'{}, 'rsa-sha2-384') -> true;
+valid_key_sha_alg(#'RSAPublicKey'{}, 'rsa-sha2-256') -> true;
+valid_key_sha_alg(#'RSAPublicKey'{}, 'ssh-rsa' ) -> true;
+
+valid_key_sha_alg(#'RSAPrivateKey'{}, 'rsa-sha2-512') -> true;
+valid_key_sha_alg(#'RSAPrivateKey'{}, 'rsa-sha2-384') -> true;
+valid_key_sha_alg(#'RSAPrivateKey'{}, 'rsa-sha2-256') -> true;
+valid_key_sha_alg(#'RSAPrivateKey'{}, 'ssh-rsa' ) -> true;
+
+valid_key_sha_alg({_, #'Dss-Parms'{}}, 'ssh-dss') -> true;
+valid_key_sha_alg(#'DSAPrivateKey'{}, 'ssh-dss') -> true;
+
+valid_key_sha_alg({#'ECPoint'{},{namedCurve,OID}}, Alg) -> sha(OID) == sha(Alg);
+valid_key_sha_alg(#'ECPrivateKey'{parameters = {namedCurve,OID}}, Alg) -> sha(OID) == sha(Alg);
+valid_key_sha_alg(_, _) -> false.
+
+
+
+public_algo(#'RSAPublicKey'{}) -> 'ssh-rsa'; % FIXME: Not right with draft-curdle-rsa-sha2
+public_algo({_, #'Dss-Parms'{}}) -> 'ssh-dss';
+public_algo({#'ECPoint'{},{namedCurve,OID}}) ->
+ Curve = public_key:oid2ssh_curvename(OID),
+ list_to_atom("ecdsa-sha2-" ++ binary_to_list(Curve)).
+
+
+
sha('ssh-rsa') -> sha;
+sha('rsa-sha2-256') -> sha256;
+sha('rsa-sha2-384') -> sha384;
+sha('rsa-sha2-512') -> sha512;
sha('ssh-dss') -> sha;
sha('ecdsa-sha2-nistp256') -> sha(secp256r1);
sha('ecdsa-sha2-nistp384') -> sha(secp384r1);
--
cgit v1.2.3
From 98fa13854707fc1f4aecb6d2f7bc167f478bdd6f Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Tue, 25 Apr 2017 13:43:56 +0200
Subject: ssh: test case adjustments
---
lib/ssh/test/ssh_basic_SUITE.erl | 1 +
lib/ssh/test/ssh_protocol_SUITE.erl | 1 +
lib/ssh/test/ssh_test_lib.erl | 13 +++++++++----
3 files changed, 11 insertions(+), 4 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index 089d191fea..34928ab0e9 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -651,6 +651,7 @@ exec_key_differs_fail(Config) when is_list(Config) ->
IO = ssh_test_lib:start_io_server(),
ssh_test_lib:start_shell(Port, IO, [{user_dir,UserDir},
+ {recv_ext_info, false},
{preferred_algorithms,[{public_key,['ssh-rsa']}]},
{pref_public_key_algs,['ssh-dss']}]),
receive
diff --git a/lib/ssh/test/ssh_protocol_SUITE.erl b/lib/ssh/test/ssh_protocol_SUITE.erl
index 2c4fa8be88..9e7d1a5fa3 100644
--- a/lib/ssh/test/ssh_protocol_SUITE.erl
+++ b/lib/ssh/test/ssh_protocol_SUITE.erl
@@ -752,6 +752,7 @@ connect_and_kex(Config, InitialState) ->
{cipher,?DEFAULT_CIPHERS}
]},
{silently_accept_hosts, true},
+ {recv_ext_info, false},
{user_dir, user_dir(Config)},
{user_interaction, false}]},
receive_hello,
diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl
index 6186d44890..ab44fc8275 100644
--- a/lib/ssh/test/ssh_test_lib.erl
+++ b/lib/ssh/test/ssh_test_lib.erl
@@ -858,8 +858,9 @@ get_kex_init(Conn) ->
get_kex_init(Conn, Ref, TRef) ->
%% First, validate the key exchange is complete (StateName == connected)
- case sys:get_state(Conn) of
- {{connected,_}, S} ->
+ {State, S} = sys:get_state(Conn),
+ case expected_state(State) of
+ true ->
timer:cancel(TRef),
%% Next, walk through the elements of the #state record looking
%% for the #ssh_msg_kexinit record. This method is robust against
@@ -873,8 +874,8 @@ get_kex_init(Conn, Ref, TRef) ->
KexInit
end;
- {OtherState, S} ->
- ct:log("Not in 'connected' state: ~p",[OtherState]),
+ false ->
+ ct:log("Not in 'connected' state: ~p",[State]),
receive
{reneg_timeout,Ref} ->
ct:log("S = ~p", [S]),
@@ -886,6 +887,10 @@ get_kex_init(Conn, Ref, TRef) ->
end
end.
+expected_state({ext_info,_,_}) -> true;
+expected_state({connected,_}) -> true;
+expected_state(_) -> false.
+
%%%----------------------------------------------------------------
%%% Return a string with N random characters
%%%
--
cgit v1.2.3
From 6036156abfa955aed1ac384919a627843106c48e Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 13 Apr 2017 15:52:54 +0200
Subject: ssh: Handle node-names with ' in ssh_basic_SUITE
---
lib/ssh/test/ssh_basic_SUITE.erl | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index 089d191fea..54d9f2c095 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -1366,13 +1366,25 @@ new_do_shell(IO, N, Ops=[{Order,Arg}|More]) ->
ct:log("Skip newline ~p",[_X]),
new_do_shell(IO, N, Ops);
- < ">> when (P1-$0)==N ->
+ < ">> when (P1-$0)==N ->
+ new_do_shell_prompt(IO, N, Order, Arg, More);
+ <<"(",Pfx:PfxSize/binary,")",P1,"> ">> when (P1-$0)==N ->
+ new_do_shell_prompt(IO, N, Order, Arg, More);
+ <<"('",Pfx:PfxSize/binary,"')",P1,"> ">> when (P1-$0)==N ->
new_do_shell_prompt(IO, N, Order, Arg, More);
- < ">> when (P1-$0)*10 + (P2-$0) == N ->
+ < ">> when (P1-$0)*10 + (P2-$0) == N ->
+ new_do_shell_prompt(IO, N, Order, Arg, More);
+ <<"(",Pfx:PfxSize/binary,")",P1,P2,"> ">> when (P1-$0)*10 + (P2-$0) == N ->
+ new_do_shell_prompt(IO, N, Order, Arg, More);
+ <<"('",Pfx:PfxSize/binary,"')",P1,P2,"> ">> when (P1-$0)*10 + (P2-$0) == N ->
new_do_shell_prompt(IO, N, Order, Arg, More);
- < ">> when (P1-$0)*100 + (P2-$0)*10 + (P3-$0) == N ->
+ < ">> when (P1-$0)*100 + (P2-$0)*10 + (P3-$0) == N ->
+ new_do_shell_prompt(IO, N, Order, Arg, More);
+ <<"(",Pfx:PfxSize/binary,")",P1,P2,P3,"> ">> when (P1-$0)*100 + (P2-$0)*10 + (P3-$0) == N ->
+ new_do_shell_prompt(IO, N, Order, Arg, More);
+ <<"('",Pfx:PfxSize/binary,"')",P1,P2,P3,"> ">> when (P1-$0)*100 + (P2-$0)*10 + (P3-$0) == N ->
new_do_shell_prompt(IO, N, Order, Arg, More);
Err when element(1,Err)==error ->
@@ -1408,7 +1420,7 @@ prompt_prefix() ->
case node() of
nonode@nohost -> <<>>;
Node -> list_to_binary(
- lists:concat(["(",Node,")"]))
+ atom_to_list(Node))
end.
--
cgit v1.2.3
From dfb0fed48117669bd69fd44d37fa83f264f5ca36 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 20 Apr 2017 20:47:13 +0200
Subject: ssh: add msg traceing on one testcase
ssh: Misc test case error logging improvments
Conflicts:
lib/ssh/test/ssh_to_openssh_SUITE.erl
---
lib/ssh/test/ssh_relay.erl | 4 ++--
lib/ssh/test/ssh_test_lib.erl | 5 +++--
lib/ssh/test/ssh_to_openssh_SUITE.erl | 25 +++++++++++++++----------
3 files changed, 20 insertions(+), 14 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_relay.erl b/lib/ssh/test/ssh_relay.erl
index 1e3810e9d4..763130358b 100644
--- a/lib/ssh/test/ssh_relay.erl
+++ b/lib/ssh/test/ssh_relay.erl
@@ -242,11 +242,11 @@ handle_info(stop, State) ->
{stop, normal, State};
handle_info({'DOWN', _Ref, _process, LPid, Reason}, S) when S#state.lpid == LPid ->
- io:format("Acceptor has finished: ~p~n", [Reason]),
+ io:format("Acceptor in ~p has finished: ~p~n", [?MODULE,Reason]),
{noreply, S};
handle_info(_Info, State) ->
- io:format("Unhandled info: ~p~n", [_Info]),
+ io:format("~p:~p Unhandled info: ~p~n", [?MODULE,?LINE,_Info]),
{noreply, State}.
%%--------------------------------------------------------------------
diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl
index 6186d44890..d0919a7bec 100644
--- a/lib/ssh/test/ssh_test_lib.erl
+++ b/lib/ssh/test/ssh_test_lib.erl
@@ -39,8 +39,9 @@ connect(Port, Options) when is_integer(Port) ->
connect(any, Port, Options) ->
connect(hostname(), Port, Options);
connect(Host, Port, Options) ->
- ct:log("~p:~p Calling ssh:connect(~p, ~p, ~p)",[?MODULE,?LINE,Host, Port, Options]),
- {ok, ConnectionRef} = ssh:connect(Host, Port, Options),
+ R = ssh:connect(Host, Port, Options),
+ ct:log("~p:~p ssh:connect(~p, ~p, ~p)~n -> ~p",[?MODULE,?LINE,Host, Port, Options, R]),
+ {ok, ConnectionRef} = R,
ConnectionRef.
%%%----------------------------------------------------------------
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl
index 35e3ee3edf..6b3055ebab 100644
--- a/lib/ssh/test/ssh_to_openssh_SUITE.erl
+++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl
@@ -153,7 +153,7 @@ erlang_shell_client_openssh_server(Config) when is_list(Config) ->
IO = ssh_test_lib:start_io_server(),
Shell = ssh_test_lib:start_shell(?SSH_DEFAULT_PORT, IO),
IO ! {input, self(), "echo Hej\n"},
- receive_data("Hej"),
+ receive_data("Hej", undefined),
IO ! {input, self(), "exit\n"},
receive_logout(),
receive_normal_exit(Shell).
@@ -451,7 +451,6 @@ erlang_server_openssh_client_renegotiate(Config) ->
%%--------------------------------------------------------------------
erlang_client_openssh_server_renegotiate(_Config) ->
process_flag(trap_exit, true),
-
IO = ssh_test_lib:start_io_server(),
Ref = make_ref(),
Parent = self(),
@@ -487,11 +486,11 @@ erlang_client_openssh_server_renegotiate(_Config) ->
ct:fail("Error=~p",[Error]);
{ok, Ref, ConnectionRef} ->
IO ! {input, self(), "echo Hej1\n"},
- receive_data("Hej1"),
+ receive_data("Hej1", ConnectionRef),
Kex1 = ssh_test_lib:get_kex_init(ConnectionRef),
ssh_connection_handler:renegotiate(ConnectionRef),
IO ! {input, self(), "echo Hej2\n"},
- receive_data("Hej2"),
+ receive_data("Hej2", ConnectionRef),
Kex2 = ssh_test_lib:get_kex_init(ConnectionRef),
IO ! {input, self(), "exit\n"},
receive_logout(),
@@ -554,23 +553,29 @@ erlang_client_openssh_server_nonexistent_subsystem(Config) when is_list(Config)
%%--------------------------------------------------------------------
%%% Internal functions -----------------------------------------------
%%--------------------------------------------------------------------
-receive_data(Data) ->
+receive_data(Data, Conn) ->
receive
Info when is_binary(Info) ->
Lines = string:tokens(binary_to_list(Info), "\r\n "),
case lists:member(Data, Lines) of
true ->
- ct:log("Expected result found in lines: ~p~n", [Lines]),
+ ct:log("Expected result ~p found in lines: ~p~n", [Data,Lines]),
ok;
false ->
ct:log("Extra info: ~p~n", [Info]),
- receive_data(Data)
+ receive_data(Data, Conn)
end;
Other ->
ct:log("Unexpected: ~p",[Other]),
- receive_data(Data)
- after
- 30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE])
+ receive_data(Data, Conn)
+ after
+ 30000 ->
+ {State, _} = case Conn of
+ undefined -> {'??','??'};
+ _ -> sys:get_state(Conn)
+ end,
+ ct:log("timeout ~p:~p~nExpect ~p~nState = ~p",[?MODULE,?LINE,Data,State]),
+ ct:fail("timeout ~p:~p",[?MODULE,?LINE])
end.
receive_logout() ->
--
cgit v1.2.3
From 9bcd621df2abf35394cd9f68b42c446d3ab83f11 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 26 Apr 2017 16:52:05 +0200
Subject: ssh: Codenomicon/Defensics fixes
---
lib/ssh/src/ssh_auth.erl | 24 ++++++++++--------------
lib/ssh/src/ssh_connection_handler.erl | 13 ++++++++-----
lib/ssh/src/ssh_transport.erl | 27 ++++++++++++++++++---------
3 files changed, 36 insertions(+), 28 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl
index aadd1ad6dc..9eb11a53dc 100644
--- a/lib/ssh/src/ssh_auth.erl
+++ b/lib/ssh/src/ssh_auth.erl
@@ -296,8 +296,7 @@ handle_userauth_request(#ssh_msg_userauth_request{user = User,
userauth_supported_methods = Methods} = Ssh) ->
case verify_sig(SessionId, User, "ssh-connection",
- binary_to_list(BAlg),
- KeyBlob, SigWLen, Opts) of
+ BAlg, KeyBlob, SigWLen, Opts) of
true ->
{authorized, User,
ssh_transport:ssh_packet(
@@ -507,21 +506,18 @@ pre_verify_sig(User, KeyBlob, Opts) ->
false
end.
-verify_sig(SessionId, User, Service, Alg, KeyBlob, SigWLen, Opts) ->
+verify_sig(SessionId, User, Service, AlgBin, KeyBlob, SigWLen, Opts) ->
try
+ Alg = binary_to_list(AlgBin),
{KeyCb,KeyCbOpts} = ?GET_OPT(key_cb, Opts),
UserOpts = ?GET_OPT(user_options, Opts),
- Key0 = public_key:ssh_decode(KeyBlob, ssh2_pubkey), % or exception
- true = KeyCb:is_auth_key(Key0, User, [{key_cb_private,KeyCbOpts}|UserOpts]),
- Key0
- of
- Key ->
- PlainText = build_sig_data(SessionId, User, Service,
- KeyBlob, Alg),
- <> = SigWLen,
- <> = AlgSig,
- ssh_transport:verify(PlainText, ssh_transport:sha(list_to_atom(Alg)), Sig, Key)
+ Key = public_key:ssh_decode(KeyBlob, ssh2_pubkey), % or exception
+ true = KeyCb:is_auth_key(Key, User, [{key_cb_private,KeyCbOpts}|UserOpts]),
+ PlainText = build_sig_data(SessionId, User, Service, KeyBlob, Alg),
+ <> = SigWLen,
+ <> = AlgSig,
+ ssh_transport:verify(PlainText, ssh_transport:sha(Alg), Sig, Key)
catch
_:_ ->
false
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 220b05e6b0..74e14a233f 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -1710,6 +1710,7 @@ ext_info({"server-sig-algs",SigAlgs}, D0 = #data{ssh_params=#ssh{role=client}=Ss
SupportedAlgs = lists:map(fun erlang:atom_to_list/1, ssh_transport:supported_algorithms(public_key)),
Ssh = Ssh0#ssh{userauth_pubkeys =
[list_to_atom(SigAlg) || SigAlg <- string:tokens(SigAlgs,","),
+ %% length of SigAlg is implicitly checked by member:
lists:member(SigAlg, SupportedAlgs)
]},
D0#data{ssh_params = Ssh};
@@ -2008,12 +2009,14 @@ handshake(Pid, Ref, Timeout) ->
end.
update_inet_buffers(Socket) ->
- {ok, BufSzs0} = inet:getopts(Socket, [sndbuf,recbuf]),
- MinVal = 655360,
- case
- [{Tag,MinVal} || {Tag,Val} <- BufSzs0,
- Val < MinVal]
+ try
+ {ok, BufSzs0} = inet:getopts(Socket, [sndbuf,recbuf]),
+ MinVal = 655360,
+ [{Tag,MinVal} || {Tag,Val} <- BufSzs0,
+ Val < MinVal]
of
[] -> ok;
NewOpts -> inet:setopts(Socket, NewOpts)
+ catch
+ _:_ -> ok
end.
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 3cf1e60634..09b5d1ac81 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -1202,15 +1202,23 @@ sign(SigData, HashAlg, Key) ->
public_key:sign(SigData, HashAlg, Key).
verify(PlainText, HashAlg, Sig, {_, #'Dss-Parms'{}} = Key) ->
- <> = Sig,
- Signature = public_key:der_encode('Dss-Sig-Value', #'Dss-Sig-Value'{r = R, s = S}),
- public_key:verify(PlainText, HashAlg, Signature, Key);
+ case Sig of
+ <> ->
+ Signature = public_key:der_encode('Dss-Sig-Value', #'Dss-Sig-Value'{r = R, s = S}),
+ public_key:verify(PlainText, HashAlg, Signature, Key);
+ _ ->
+ false
+ end;
verify(PlainText, HashAlg, Sig, {#'ECPoint'{},_} = Key) ->
- <> = Sig,
- Sval = #'ECDSA-Sig-Value'{r=R, s=S},
- DerEncodedSig = public_key:der_encode('ECDSA-Sig-Value',Sval),
- public_key:verify(PlainText, HashAlg, DerEncodedSig, Key);
+ case Sig of
+ <> ->
+ Sval = #'ECDSA-Sig-Value'{r=R, s=S},
+ DerEncodedSig = public_key:der_encode('ECDSA-Sig-Value',Sval),
+ public_key:verify(PlainText, HashAlg, DerEncodedSig, Key);
+ _ ->
+ false
+ end;
verify(PlainText, HashAlg, Sig, Key) ->
public_key:verify(PlainText, HashAlg, Sig, Key).
@@ -1795,7 +1803,8 @@ sha(?'secp384r1') -> sha(secp384r1);
sha(?'secp521r1') -> sha(secp521r1);
sha('ecdh-sha2-nistp256') -> sha(secp256r1);
sha('ecdh-sha2-nistp384') -> sha(secp384r1);
-sha('ecdh-sha2-nistp521') -> sha(secp521r1).
+sha('ecdh-sha2-nistp521') -> sha(secp521r1);
+sha(Str) when is_list(Str), length(Str)<50 -> sha(list_to_atom(Str)).
mac_key_bytes('hmac-sha1') -> 20;
--
cgit v1.2.3
From 6f26467274a77d0838596775f3e7e6a33aad7273 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 27 Apr 2017 14:58:47 +0200
Subject: ssh: Don't expose new rsa-sha2-* as default
---
lib/ssh/src/ssh_transport.erl | 4 ++++
1 file changed, 4 insertions(+)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 09b5d1ac81..7c7dda7a1e 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -92,6 +92,10 @@ default_algorithms(cipher) ->
default_algorithms(mac) ->
supported_algorithms(mac, same(['AEAD_AES_128_GCM',
'AEAD_AES_256_GCM']));
+default_algorithms(public_key) ->
+ supported_algorithms(public_key, ['rsa-sha2-256',
+ 'rsa-sha2-384',
+ 'rsa-sha2-512']);
default_algorithms(Alg) ->
supported_algorithms(Alg, []).
--
cgit v1.2.3
From 83e20c62057ebc1d8064bf57b01be560cd244e1d Mon Sep 17 00:00:00 2001
From: Raimo Niskanen
Date: Thu, 4 May 2017 15:42:21 +0200
Subject: Update copyright year
---
lib/ssh/doc/src/notes.xml | 2 +-
lib/ssh/doc/src/ssh.xml | 2 +-
lib/ssh/doc/src/ssh_app.xml | 2 +-
lib/ssh/doc/src/using_ssh.xml | 2 +-
lib/ssh/src/Makefile | 2 +-
lib/ssh/src/ssh.erl | 2 +-
lib/ssh/src/ssh.hrl | 2 +-
lib/ssh/src/ssh_acceptor.erl | 2 +-
lib/ssh/src/ssh_acceptor_sup.erl | 2 +-
lib/ssh/src/ssh_auth.erl | 2 +-
lib/ssh/src/ssh_cli.erl | 2 +-
lib/ssh/src/ssh_connect.hrl | 2 +-
lib/ssh/src/ssh_connection.erl | 2 +-
lib/ssh/src/ssh_connection_handler.erl | 2 +-
lib/ssh/src/ssh_connection_sup.erl | 2 +-
lib/ssh/src/ssh_dbg.erl | 2 +-
lib/ssh/src/ssh_file.erl | 2 +-
lib/ssh/src/ssh_io.erl | 2 +-
lib/ssh/src/ssh_message.erl | 2 +-
lib/ssh/src/ssh_sftp.erl | 2 +-
lib/ssh/src/ssh_sftpd.erl | 2 +-
lib/ssh/src/ssh_sftpd_file_api.erl | 2 +-
lib/ssh/src/ssh_subsystem_sup.erl | 2 +-
lib/ssh/src/ssh_sup.erl | 2 +-
lib/ssh/src/ssh_system_sup.erl | 2 +-
lib/ssh/src/ssh_transport.erl | 2 +-
lib/ssh/src/ssh_transport.hrl | 2 +-
lib/ssh/src/sshc_sup.erl | 2 +-
lib/ssh/src/sshd_sup.erl | 2 +-
lib/ssh/test/Makefile | 2 +-
lib/ssh/test/property_test/ssh_eqc_encode_decode.erl | 2 +-
lib/ssh/test/ssh_algorithms_SUITE.erl | 2 +-
lib/ssh/test/ssh_basic_SUITE.erl | 2 +-
lib/ssh/test/ssh_bench_SUITE.erl | 2 +-
lib/ssh/test/ssh_bench_dev_null.erl | 2 +-
lib/ssh/test/ssh_connection_SUITE.erl | 2 +-
lib/ssh/test/ssh_key_cb.erl | 2 +-
lib/ssh/test/ssh_key_cb_options.erl | 2 +-
lib/ssh/test/ssh_options_SUITE.erl | 2 +-
lib/ssh/test/ssh_protocol_SUITE.erl | 2 +-
lib/ssh/test/ssh_sftp_SUITE.erl | 2 +-
lib/ssh/test/ssh_sftpd_SUITE.erl | 2 +-
lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl | 2 +-
lib/ssh/test/ssh_sup_SUITE.erl | 2 +-
lib/ssh/test/ssh_test_lib.erl | 2 +-
lib/ssh/test/ssh_to_openssh_SUITE.erl | 2 +-
lib/ssh/test/ssh_trpt_test_lib.erl | 2 +-
47 files changed, 47 insertions(+), 47 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index c8c6e61cc8..bddae00dd2 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -4,7 +4,7 @@
- 20042016
+ 20042017
Ericsson AB. All Rights Reserved.
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index 368261968d..84b7cdd7a1 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -4,7 +4,7 @@
- 20042016
+ 20042017
Ericsson AB. All Rights Reserved.
diff --git a/lib/ssh/doc/src/ssh_app.xml b/lib/ssh/doc/src/ssh_app.xml
index 515b0639d5..74c4111338 100644
--- a/lib/ssh/doc/src/ssh_app.xml
+++ b/lib/ssh/doc/src/ssh_app.xml
@@ -4,7 +4,7 @@
- 20122016
+ 20122017
Ericsson AB. All Rights Reserved.
diff --git a/lib/ssh/doc/src/using_ssh.xml b/lib/ssh/doc/src/using_ssh.xml
index 864378b640..ab307624e6 100644
--- a/lib/ssh/doc/src/using_ssh.xml
+++ b/lib/ssh/doc/src/using_ssh.xml
@@ -5,7 +5,7 @@
2012
- 2016
+ 2017
Ericsson AB. All Rights Reserved.
diff --git a/lib/ssh/src/Makefile b/lib/ssh/src/Makefile
index f826fdfd9b..9e8d80c71f 100644
--- a/lib/ssh/src/Makefile
+++ b/lib/ssh/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2016. All Rights Reserved.
+# Copyright Ericsson AB 2004-2017. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 3e80a04b70..5ebab43c30 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -1,7 +1,7 @@
%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh.hrl b/lib/ssh/src/ssh.hrl
index cf2a359e6c..d6d412db43 100644
--- a/lib/ssh/src/ssh.hrl
+++ b/lib/ssh/src/ssh.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_acceptor.erl b/lib/ssh/src/ssh_acceptor.erl
index f7fbd7ccad..d66a34c58a 100644
--- a/lib/ssh/src/ssh_acceptor.erl
+++ b/lib/ssh/src/ssh_acceptor.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_acceptor_sup.erl b/lib/ssh/src/ssh_acceptor_sup.erl
index 26defcfdbd..a24664793b 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-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl
index 9eb11a53dc..6cf659f830 100644
--- a/lib/ssh/src/ssh_auth.erl
+++ b/lib/ssh/src/ssh_auth.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_cli.erl b/lib/ssh/src/ssh_cli.erl
index 4c4f61e036..62854346b0 100644
--- a/lib/ssh/src/ssh_cli.erl
+++ b/lib/ssh/src/ssh_cli.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_connect.hrl b/lib/ssh/src/ssh_connect.hrl
index c91c56435e..a8de5f9a2f 100644
--- a/lib/ssh/src/ssh_connect.hrl
+++ b/lib/ssh/src/ssh_connect.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl
index 930ccecb4c..7e9ee78fd2 100644
--- a/lib/ssh/src/ssh_connection.erl
+++ b/lib/ssh/src/ssh_connection.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 74e14a233f..342583306b 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_connection_sup.erl b/lib/ssh/src/ssh_connection_sup.erl
index fad796f196..60ee8b7c73 100644
--- a/lib/ssh/src/ssh_connection_sup.erl
+++ b/lib/ssh/src/ssh_connection_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_dbg.erl b/lib/ssh/src/ssh_dbg.erl
index 9431bf1817..7dfbfc3b4b 100644
--- a/lib/ssh/src/ssh_dbg.erl
+++ b/lib/ssh/src/ssh_dbg.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_file.erl b/lib/ssh/src/ssh_file.erl
index 4498c70d34..6692432fcf 100644
--- a/lib/ssh/src/ssh_file.erl
+++ b/lib/ssh/src/ssh_file.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_io.erl b/lib/ssh/src/ssh_io.erl
index 6828fd4760..8ba759ad60 100644
--- a/lib/ssh/src/ssh_io.erl
+++ b/lib/ssh/src/ssh_io.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_message.erl b/lib/ssh/src/ssh_message.erl
index 21c0eabcd3..609040826f 100644
--- a/lib/ssh/src/ssh_message.erl
+++ b/lib/ssh/src/ssh_message.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_sftp.erl b/lib/ssh/src/ssh_sftp.erl
index f1f7b57e8d..c1558a19b1 100644
--- a/lib/ssh/src/ssh_sftp.erl
+++ b/lib/ssh/src/ssh_sftp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_sftpd.erl b/lib/ssh/src/ssh_sftpd.erl
index b879116393..427edf01ab 100644
--- a/lib/ssh/src/ssh_sftpd.erl
+++ b/lib/ssh/src/ssh_sftpd.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_sftpd_file_api.erl b/lib/ssh/src/ssh_sftpd_file_api.erl
index e444e52ac0..81f181f1fc 100644
--- a/lib/ssh/src/ssh_sftpd_file_api.erl
+++ b/lib/ssh/src/ssh_sftpd_file_api.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_subsystem_sup.erl b/lib/ssh/src/ssh_subsystem_sup.erl
index cf409ade6b..8db051095c 100644
--- a/lib/ssh/src/ssh_subsystem_sup.erl
+++ b/lib/ssh/src/ssh_subsystem_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_sup.erl b/lib/ssh/src/ssh_sup.erl
index 26574763e4..eaec7a54e4 100644
--- a/lib/ssh/src/ssh_sup.erl
+++ b/lib/ssh/src/ssh_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_system_sup.erl b/lib/ssh/src/ssh_system_sup.erl
index 84b4cd3241..e70abf59c2 100644
--- a/lib/ssh/src/ssh_system_sup.erl
+++ b/lib/ssh/src/ssh_system_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 7c7dda7a1e..25c64a4f25 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_transport.hrl b/lib/ssh/src/ssh_transport.hrl
index faae6008f2..87c3719514 100644
--- a/lib/ssh/src/ssh_transport.hrl
+++ b/lib/ssh/src/ssh_transport.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/sshc_sup.erl b/lib/ssh/src/sshc_sup.erl
index c71b81dc6d..133b2c6450 100644
--- a/lib/ssh/src/sshc_sup.erl
+++ b/lib/ssh/src/sshc_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/sshd_sup.erl b/lib/ssh/src/sshd_sup.erl
index 449ba20d02..c23e65d955 100644
--- a/lib/ssh/src/sshd_sup.erl
+++ b/lib/ssh/src/sshd_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/Makefile b/lib/ssh/test/Makefile
index fab79a7a43..32e76cf077 100644
--- a/lib/ssh/test/Makefile
+++ b/lib/ssh/test/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2016. All Rights Reserved.
+# Copyright Ericsson AB 2004-2017. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl b/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl
index 8ca29b9399..410a9ea983 100644
--- a/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl
+++ b/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_algorithms_SUITE.erl b/lib/ssh/test/ssh_algorithms_SUITE.erl
index 2990d1e02a..6e6269d3e0 100644
--- a/lib/ssh/test/ssh_algorithms_SUITE.erl
+++ b/lib/ssh/test/ssh_algorithms_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index c271ff49ef..b80c3ed5e2 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_bench_SUITE.erl b/lib/ssh/test/ssh_bench_SUITE.erl
index 317e50ed1d..2c0cd8fc8e 100644
--- a/lib/ssh/test/ssh_bench_SUITE.erl
+++ b/lib/ssh/test/ssh_bench_SUITE.erl
@@ -1,7 +1,7 @@
%%%-------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_bench_dev_null.erl b/lib/ssh/test/ssh_bench_dev_null.erl
index 0e390b7712..5166247714 100644
--- a/lib/ssh/test/ssh_bench_dev_null.erl
+++ b/lib/ssh/test/ssh_bench_dev_null.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_connection_SUITE.erl b/lib/ssh/test/ssh_connection_SUITE.erl
index b911cf0e9e..9bbd9da817 100644
--- a/lib/ssh/test/ssh_connection_SUITE.erl
+++ b/lib/ssh/test/ssh_connection_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_key_cb.erl b/lib/ssh/test/ssh_key_cb.erl
index 12ff79efcd..5564b9d873 100644
--- a/lib/ssh/test/ssh_key_cb.erl
+++ b/lib/ssh/test/ssh_key_cb.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_key_cb_options.erl b/lib/ssh/test/ssh_key_cb_options.erl
index 946a1254d0..c104a2f129 100644
--- a/lib/ssh/test/ssh_key_cb_options.erl
+++ b/lib/ssh/test/ssh_key_cb_options.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_options_SUITE.erl b/lib/ssh/test/ssh_options_SUITE.erl
index 344a042d79..b710ca8fb7 100644
--- a/lib/ssh/test/ssh_options_SUITE.erl
+++ b/lib/ssh/test/ssh_options_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_protocol_SUITE.erl b/lib/ssh/test/ssh_protocol_SUITE.erl
index 9e7d1a5fa3..5a6e0638a7 100644
--- a/lib/ssh/test/ssh_protocol_SUITE.erl
+++ b/lib/ssh/test/ssh_protocol_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. 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
diff --git a/lib/ssh/test/ssh_sftp_SUITE.erl b/lib/ssh/test/ssh_sftp_SUITE.erl
index 7efeb3a0ad..680a8ef52e 100644
--- a/lib/ssh/test/ssh_sftp_SUITE.erl
+++ b/lib/ssh/test/ssh_sftp_SUITE.erl
@@ -1,7 +1,7 @@
%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_sftpd_SUITE.erl b/lib/ssh/test/ssh_sftpd_SUITE.erl
index 379c0bcb0a..763649a12f 100644
--- a/lib/ssh/test/ssh_sftpd_SUITE.erl
+++ b/lib/ssh/test/ssh_sftpd_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl b/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl
index 9b5d6b5fae..417b5c4f16 100644
--- a/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl
+++ b/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_sup_SUITE.erl b/lib/ssh/test/ssh_sup_SUITE.erl
index dd7c4b1473..3920a1c592 100644
--- a/lib/ssh/test/ssh_sup_SUITE.erl
+++ b/lib/ssh/test/ssh_sup_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl
index ded47ca4f6..36ae2525da 100644
--- a/lib/ssh/test/ssh_test_lib.erl
+++ b/lib/ssh/test/ssh_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl
index 6b3055ebab..a3d596a1c9 100644
--- a/lib/ssh/test/ssh_to_openssh_SUITE.erl
+++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_trpt_test_lib.erl b/lib/ssh/test/ssh_trpt_test_lib.erl
index 781889ddd1..8de550af15 100644
--- a/lib/ssh/test/ssh_trpt_test_lib.erl
+++ b/lib/ssh/test/ssh_trpt_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2017. 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
--
cgit v1.2.3
From dc57404252c47520f352834ad9be45ad684f96c9 Mon Sep 17 00:00:00 2001
From: Erlang/OTP
Date: Thu, 4 May 2017 17:05:25 +0200
Subject: Prepare release
---
lib/ssh/doc/src/notes.xml | 117 ++++++++++++++++++++++++++++++++++++++++++++++
lib/ssh/vsn.mk | 2 +-
2 files changed, 118 insertions(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index bddae00dd2..ac31ab14a6 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -30,6 +30,123 @@
notes.xml
+Ssh 4.5
+
+ Improvements and New Features
+
+ -
+
+ The internal handling of SSH options is re-written.
+
+ Previously there were no checks if a client option was
+ given to a daemon or vice versa. This is corrected now.
+ If your code has e.g. a client-only option in a call to
+ start a daemon, the call will fail.
+
+ *** POTENTIAL INCOMPATIBILITY ***
+
+ Own Id: OTP-12872
+
+ -
+
+ Modernization of diffie-hellman algorithms. Removed an
+ outdated weak algorithm and added stronger replacements
+ to keep interoperability with other ssh clients and
+ servers. The default ordering is also adjusted.
+
+ Retired: key-exchange diffie-hellman-group1-sha1.
+ It is not enabled by default, but can be enabled with the
+ option preferred-algorithms.
+
+ Added: key-exchange diffie-hellman-group16-sha512,
+ diffie-hellman-group18-sha512 and
+ diffie-hellman-group14-sha256.
+
+ *** POTENTIAL INCOMPATIBILITY ***
+
+ Own Id: OTP-14110
+
+ -
+
+ Modernized internal representation of sftp by use of
+ maps.
+
+ Own Id: OTP-14117
+
+ -
+
+ The draft-ietf-curdle-ssh-ext-info-05 and
+ draft-ietf-curdle-rsa-sha2-05 are (partially)
+ implemented.
+
+ The extension server-sig-algs and the signature
+ algorithms rsa-sha2-256 and rsa-sha2-512
+ are implemented. The rsa-sha2-* are not enabled by
+ default yet since they has a bug. Use option
+ preferred_algorithms with key public key to try them.
+
+ Own Id: OTP-14193
+
+ -
+
+ Ssh:connect, ssh:shell and ssh:start_channel now accept
+ an IP-tuple as Host destination argument.
+
+ Own Id: OTP-14243
+
+ -
+
+ The function ssh:daemon_info/1 now returns Host
+ and Profile as well as the Port info.
+
+ Own Id: OTP-14259
+
+ -
+
+ Removed the option public_key_alg which was
+ deprecated in 18.2. Use pref_public_key_algs
+ instead.
+
+ *** POTENTIAL INCOMPATIBILITY ***
+
+ Own Id: OTP-14263
+
+ -
+
+ The ssh application is refactored regarding daemon
+ starting. The resolution of contradicting Host
+ argument and ip option were not described. There
+ were also strange corner cases when the 'any'
+ value was used in Host argument or ip
+ option. This is (hopefully) resolved now, but it may
+ cause incompatibilities for code using both Host
+ and the ip option. The value 'loopback' has been
+ added for a correct way of naming those addresses.
+
+ *** POTENTIAL INCOMPATIBILITY ***
+
+ Own Id: OTP-14264
+
+ -
+
+ The supervisor code is refactored. The naming of
+ listening IP-Port-Profile tripples are slightly changed
+ to improve consistency in strange corner cases as
+ resolved by OTP-14264
+
+ Own Id: OTP-14267 Aux Id: OTP-14266
+
+ -
+
+ The idle_time option can now be used in daemons.
+
+ Own Id: OTP-14312
+
+
+
+
+
+
Ssh 4.4.2
Fixed Bugs and Malfunctions
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index 48332d2e5a..7208baca6e 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,5 +1,5 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 4.4.2
+SSH_VSN = 4.5
APP_VSN = "ssh-$(SSH_VSN)"
--
cgit v1.2.3
From eace29905be436d77245656b2511c9a9c2c67c90 Mon Sep 17 00:00:00 2001
From: Raimo Niskanen
Date: Fri, 5 May 2017 13:15:42 +0200
Subject: Revert "Prepare release"
This reverts commit dc57404252c47520f352834ad9be45ad684f96c9.
---
lib/ssh/doc/src/notes.xml | 117 ----------------------------------------------
lib/ssh/vsn.mk | 2 +-
2 files changed, 1 insertion(+), 118 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index ac31ab14a6..bddae00dd2 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -30,123 +30,6 @@
notes.xml
-Ssh 4.5
-
- Improvements and New Features
-
- -
-
- The internal handling of SSH options is re-written.
-
- Previously there were no checks if a client option was
- given to a daemon or vice versa. This is corrected now.
- If your code has e.g. a client-only option in a call to
- start a daemon, the call will fail.
-
- *** POTENTIAL INCOMPATIBILITY ***
-
- Own Id: OTP-12872
-
- -
-
- Modernization of diffie-hellman algorithms. Removed an
- outdated weak algorithm and added stronger replacements
- to keep interoperability with other ssh clients and
- servers. The default ordering is also adjusted.
-
- Retired: key-exchange diffie-hellman-group1-sha1.
- It is not enabled by default, but can be enabled with the
- option preferred-algorithms.
-
- Added: key-exchange diffie-hellman-group16-sha512,
- diffie-hellman-group18-sha512 and
- diffie-hellman-group14-sha256.
-
- *** POTENTIAL INCOMPATIBILITY ***
-
- Own Id: OTP-14110
-
- -
-
- Modernized internal representation of sftp by use of
- maps.
-
- Own Id: OTP-14117
-
- -
-
- The draft-ietf-curdle-ssh-ext-info-05 and
- draft-ietf-curdle-rsa-sha2-05 are (partially)
- implemented.
-
- The extension server-sig-algs and the signature
- algorithms rsa-sha2-256 and rsa-sha2-512
- are implemented. The rsa-sha2-* are not enabled by
- default yet since they has a bug. Use option
- preferred_algorithms with key public key to try them.
-
- Own Id: OTP-14193
-
- -
-
- Ssh:connect, ssh:shell and ssh:start_channel now accept
- an IP-tuple as Host destination argument.
-
- Own Id: OTP-14243
-
- -
-
- The function ssh:daemon_info/1 now returns Host
- and Profile as well as the Port info.
-
- Own Id: OTP-14259
-
- -
-
- Removed the option public_key_alg which was
- deprecated in 18.2. Use pref_public_key_algs
- instead.
-
- *** POTENTIAL INCOMPATIBILITY ***
-
- Own Id: OTP-14263
-
- -
-
- The ssh application is refactored regarding daemon
- starting. The resolution of contradicting Host
- argument and ip option were not described. There
- were also strange corner cases when the 'any'
- value was used in Host argument or ip
- option. This is (hopefully) resolved now, but it may
- cause incompatibilities for code using both Host
- and the ip option. The value 'loopback' has been
- added for a correct way of naming those addresses.
-
- *** POTENTIAL INCOMPATIBILITY ***
-
- Own Id: OTP-14264
-
- -
-
- The supervisor code is refactored. The naming of
- listening IP-Port-Profile tripples are slightly changed
- to improve consistency in strange corner cases as
- resolved by OTP-14264
-
- Own Id: OTP-14267 Aux Id: OTP-14266
-
- -
-
- The idle_time option can now be used in daemons.
-
- Own Id: OTP-14312
-
-
-
-
-
-
Ssh 4.4.2
Fixed Bugs and Malfunctions
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index 7208baca6e..48332d2e5a 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,5 +1,5 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 4.5
+SSH_VSN = 4.4.2
APP_VSN = "ssh-$(SSH_VSN)"
--
cgit v1.2.3
From efbae4afb84ef03364a1de349d98413211946ad4 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Tue, 9 May 2017 18:38:35 +0200
Subject: ssh: Option 'auth_methods' available not only in server but also in
client
---
lib/ssh/src/ssh_connection_handler.erl | 6 +-----
lib/ssh/src/ssh_options.erl | 12 ++++++------
2 files changed, 7 insertions(+), 11 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 342583306b..39bd54869f 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -434,11 +434,7 @@ init_ssh_record(Role, Socket, Opts) ->
init_ssh_record(Role, _Socket, PeerAddr, Opts) ->
KeyCb = ?GET_OPT(key_cb, Opts),
- AuthMethods =
- case Role of
- server -> ?GET_OPT(auth_methods, Opts);
- client -> undefined
- end,
+ AuthMethods = ?GET_OPT(auth_methods, Opts),
S0 = #ssh{role = Role,
key_cb = KeyCb,
opts = Opts,
diff --git a/lib/ssh/src/ssh_options.erl b/lib/ssh/src/ssh_options.erl
index 0886d5b34d..6bd6ab74c3 100644
--- a/lib/ssh/src/ssh_options.erl
+++ b/lib/ssh/src/ssh_options.erl
@@ -293,12 +293,6 @@ default(server) ->
class => user_options
},
- {auth_methods, def} =>
- #{default => ?SUPPORTED_AUTH_METHODS,
- chk => fun check_string/1,
- class => user_options
- },
-
{auth_method_kb_interactive_data, def} =>
#{default => undefined, % Default value can be constructed when User is known
chk => fun({S1,S2,S3,B}) ->
@@ -583,6 +577,12 @@ default(common) ->
},
%%%%% Undocumented
+ {auth_methods, def} =>
+ #{default => ?SUPPORTED_AUTH_METHODS,
+ chk => fun check_string/1,
+ class => user_options
+ },
+
{transport, def} =>
#{default => ?DEFAULT_TRANSPORT,
chk => fun({A,B,C}) ->
--
cgit v1.2.3
From 6e9f9cbfc1f69735788651369bf6e288e23fbced Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 10 May 2017 12:39:02 +0200
Subject: ssh: Doc option 'auth_methods' for client
---
lib/ssh/doc/src/ssh.xml | 13 +++++++++++++
lib/ssh/src/ssh_options.erl | 2 +-
2 files changed, 14 insertions(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index 84b7cdd7a1..c659e093b9 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -293,6 +293,15 @@
connection. For gen_tcp the time is in milli-seconds and the default value is
infinity.
+
+
+ -
+
Comma-separated string that determines which
+ authentication methods that the client shall support and
+ in which order they are tried. Defaults to
+
+
+
-
Provides a username. If this option is not given, ssh
@@ -300,6 +309,7 @@
on UNIX,
on Windows).
+
-
Provides a password for password authentication.
@@ -307,6 +317,7 @@
password, if the password authentication method is
attempted.
+
-
Module implementing the behaviour
+
-
If true, the client does not print anything on authorization.
@@ -466,6 +478,7 @@
authentication methods that the server is to support and
in what order they are tried. Defaults to
+ Note that the client is free to use any order and to exclude methods.
diff --git a/lib/ssh/src/ssh_options.erl b/lib/ssh/src/ssh_options.erl
index 6bd6ab74c3..f98422c324 100644
--- a/lib/ssh/src/ssh_options.erl
+++ b/lib/ssh/src/ssh_options.erl
@@ -576,13 +576,13 @@ default(common) ->
class => user_options
},
-%%%%% Undocumented
{auth_methods, def} =>
#{default => ?SUPPORTED_AUTH_METHODS,
chk => fun check_string/1,
class => user_options
},
+%%%%% Undocumented
{transport, def} =>
#{default => ?DEFAULT_TRANSPORT,
chk => fun({A,B,C}) ->
--
cgit v1.2.3
From 242dddbc918c87571013e7e0acd29b4abbe12911 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 10 May 2017 11:42:09 +0200
Subject: ssh: Better error checking for option 'auth_methods'
---
lib/ssh/src/ssh_options.erl | 11 ++++++++++-
lib/ssh/test/ssh_basic_SUITE.erl | 7 ++-----
2 files changed, 12 insertions(+), 6 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_options.erl b/lib/ssh/src/ssh_options.erl
index f98422c324..78f68dbcb1 100644
--- a/lib/ssh/src/ssh_options.erl
+++ b/lib/ssh/src/ssh_options.erl
@@ -578,7 +578,16 @@ default(common) ->
{auth_methods, def} =>
#{default => ?SUPPORTED_AUTH_METHODS,
- chk => fun check_string/1,
+ chk => fun(As) ->
+ try
+ Sup = string:tokens(?SUPPORTED_AUTH_METHODS, ","),
+ New = string:tokens(As, ","),
+ [] == [X || X <- New,
+ not lists:member(X,Sup)]
+ catch
+ _:_ -> false
+ end
+ end,
class => user_options
},
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index b80c3ed5e2..1e591bc295 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -1173,13 +1173,10 @@ login_bad_pwd_no_retry3(Config) ->
login_bad_pwd_no_retry(Config, "password,publickey,keyboard-interactive").
login_bad_pwd_no_retry4(Config) ->
- login_bad_pwd_no_retry(Config, "password,other,keyboard-interactive").
+ login_bad_pwd_no_retry(Config, "password,keyboard-interactive").
login_bad_pwd_no_retry5(Config) ->
- login_bad_pwd_no_retry(Config, "password,other,keyboard-interactive,password,password").
-
-
-
+ login_bad_pwd_no_retry(Config, "password,keyboard-interactive,password,password").
login_bad_pwd_no_retry(Config, AuthMethods) ->
--
cgit v1.2.3
From 1af2d325a63ca378e250eef6c3c97d065a9eff3d Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 12 May 2017 12:45:36 +0200
Subject: ssh: Tests for ext-info extension (ext-info-s)
---
lib/ssh/test/ssh_protocol_SUITE.erl | 64 ++++++++++++++++++++++++++++++++++---
1 file changed, 59 insertions(+), 5 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_protocol_SUITE.erl b/lib/ssh/test/ssh_protocol_SUITE.erl
index 5a6e0638a7..cdabd839b6 100644
--- a/lib/ssh/test/ssh_protocol_SUITE.erl
+++ b/lib/ssh/test/ssh_protocol_SUITE.erl
@@ -59,7 +59,8 @@ all() ->
{group,service_requests},
{group,authentication},
{group,packet_size_error},
- {group,field_size_error}
+ {group,field_size_error},
+ {group,ext_info}
].
groups() ->
@@ -90,7 +91,11 @@ groups() ->
bad_service_name_then_correct
]},
{authentication, [], [client_handles_keyboard_interactive_0_pwds
- ]}
+ ]},
+ {ext_info, [], [no_ext_info_s1,
+ no_ext_info_s2,
+ ext_info_s
+ ]}
].
@@ -644,7 +649,54 @@ client_info_line(_Config) ->
ok
end.
-
+%%%--------------------------------------------------------------------
+%%% The server does not send the extension because
+%%% the client does not tell the server to send it
+no_ext_info_s1(Config) ->
+ %% Start the dameon
+ Server = {Pid,_,_} = ssh_test_lib:daemon([{send_ext_info,true},
+ {system_dir, system_dir(Config)}]),
+ {ok,AfterKexState} = connect_and_kex([{server,Server}|Config]),
+ {ok,_} =
+ ssh_trpt_test_lib:exec(
+ [{send, #ssh_msg_service_request{name = "ssh-userauth"}},
+ {match, #ssh_msg_service_accept{name = "ssh-userauth"}, receive_msg}
+ ], AfterKexState),
+ ssh:stop_daemon(Pid).
+
+%%%--------------------------------------------------------------------
+%%% The server does not send the extension because
+%%% the server is not configured to send it
+no_ext_info_s2(Config) ->
+ %% Start the dameon
+ Server = {Pid,_,_} = ssh_test_lib:daemon([{send_ext_info,false},
+ {system_dir, system_dir(Config)}]),
+ {ok,AfterKexState} = connect_and_kex([{extra_options,[{recv_ext_info,true}]},
+ {server,Server}
+ | Config]),
+ {ok,_} =
+ ssh_trpt_test_lib:exec(
+ [{send, #ssh_msg_service_request{name = "ssh-userauth"}},
+ {match, #ssh_msg_service_accept{name = "ssh-userauth"}, receive_msg}
+ ], AfterKexState),
+ ssh:stop_daemon(Pid).
+
+%%%--------------------------------------------------------------------
+%%% The server sends the extension
+ext_info_s(Config) ->
+ %% Start the dameon
+ Server = {Pid,_,_} = ssh_test_lib:daemon([{send_ext_info,true},
+ {system_dir, system_dir(Config)}]),
+ {ok,AfterKexState} = connect_and_kex([{extra_options,[{recv_ext_info,true}]},
+ {server,Server}
+ | Config]),
+ {ok,_} =
+ ssh_trpt_test_lib:exec(
+ [{match, #ssh_msg_ext_info{_='_'}, receive_msg}
+ ],
+ AfterKexState),
+ ssh:stop_daemon(Pid).
+
%%%================================================================
%%%==== Internal functions ========================================
%%%================================================================
@@ -751,10 +803,12 @@ connect_and_kex(Config, InitialState) ->
[{preferred_algorithms,[{kex,[?DEFAULT_KEX]},
{cipher,?DEFAULT_CIPHERS}
]},
- {silently_accept_hosts, true},
+ {silently_accept_hosts, true},
{recv_ext_info, false},
{user_dir, user_dir(Config)},
- {user_interaction, false}]},
+ {user_interaction, false}
+ | proplists:get_value(extra_options,Config,[])
+ ]},
receive_hello,
{send, hello},
{send, ssh_msg_kexinit},
--
cgit v1.2.3
From de3c2e70b3bf3387877b6624b6772395664039d6 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 12 May 2017 16:11:13 +0200
Subject: ssh: Tests for ext-info extension (ext-info-c)
---
lib/ssh/src/ssh_transport.erl | 18 +++++++++--
lib/ssh/test/ssh_protocol_SUITE.erl | 62 ++++++++++++++++++++++++++++++++++++-
2 files changed, 76 insertions(+), 4 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 25c64a4f25..bd1cb4bd22 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -724,9 +724,21 @@ kex_ext_info(Role, Opts) ->
end.
ext_info_message(#ssh{role=client,
- send_ext_info=true} = Ssh0) ->
- %% FIXME: no extensions implemented
- {ok, "", Ssh0};
+ send_ext_info=true,
+ opts=Opts} = Ssh0) ->
+ %% Since no extension sent by the client is implemented, we add a fake one
+ %% to be able to test the framework.
+ %% Remove this when there is one and update ssh_protocol_SUITE whare it is used.
+ case proplists:get_value(ext_info_client, ?GET_OPT(tstflg,Opts)) of
+ true ->
+ Msg = #ssh_msg_ext_info{nr_extensions = 1,
+ data = [{"test@erlang.org", "Testing,PleaseIgnore"}]
+ },
+ {SshPacket, Ssh} = ssh_packet(Msg, Ssh0),
+ {ok, SshPacket, Ssh};
+ _ ->
+ {ok, "", Ssh0}
+ end;
ext_info_message(#ssh{role=server,
send_ext_info=true} = Ssh0) ->
diff --git a/lib/ssh/test/ssh_protocol_SUITE.erl b/lib/ssh/test/ssh_protocol_SUITE.erl
index cdabd839b6..0385e30ad1 100644
--- a/lib/ssh/test/ssh_protocol_SUITE.erl
+++ b/lib/ssh/test/ssh_protocol_SUITE.erl
@@ -94,7 +94,8 @@ groups() ->
]},
{ext_info, [], [no_ext_info_s1,
no_ext_info_s2,
- ext_info_s
+ ext_info_s,
+ ext_info_c
]}
].
@@ -697,6 +698,65 @@ ext_info_s(Config) ->
AfterKexState),
ssh:stop_daemon(Pid).
+%%%--------------------------------------------------------------------
+%%% The client sends the extension
+ext_info_c(Config) ->
+ {User,_Pwd} = server_user_password(Config),
+
+ %% Create a listening socket as server socket:
+ {ok,InitialState} = ssh_trpt_test_lib:exec(listen),
+ HostPort = ssh_trpt_test_lib:server_host_port(InitialState),
+
+ Parent = self(),
+ %% Start a process handling one connection on the server side:
+ Pid =
+ spawn_link(
+ fun() ->
+ Result =
+ ssh_trpt_test_lib:exec(
+ [{set_options, [print_ops, print_messages]},
+ {accept, [{system_dir, system_dir(Config)},
+ {user_dir, user_dir(Config)},
+ {recv_ext_info, true}
+ ]},
+ receive_hello,
+ {send, hello},
+
+ {send, ssh_msg_kexinit},
+ {match, #ssh_msg_kexinit{_='_'}, receive_msg},
+
+ {match, #ssh_msg_kexdh_init{_='_'}, receive_msg},
+ {send, ssh_msg_kexdh_reply},
+
+ {send, #ssh_msg_newkeys{}},
+ {match, #ssh_msg_newkeys{_='_'}, receive_msg},
+
+ {match, #ssh_msg_ext_info{_='_'}, receive_msg},
+
+ close_socket,
+ print_state
+ ],
+ InitialState),
+ Parent ! {result,self(),Result}
+ end),
+
+ %% connect to it with a regular Erlang SSH client
+ %% (expect error due to the close_socket in daemon):
+ {error,_} = std_connect(HostPort, Config,
+ [{preferred_algorithms,[{kex,[?DEFAULT_KEX]},
+ {cipher,?DEFAULT_CIPHERS}
+ ]},
+ {tstflg, [{ext_info_client,true}]},
+ {send_ext_info, true}
+ ]
+ ),
+
+ %% Check that the daemon got expected result:
+ receive
+ {result, Pid, {ok,_}} -> ok;
+ {result, Pid, Error} -> ct:fail("Error: ~p",[Error])
+ end.
+
%%%================================================================
%%%==== Internal functions ========================================
%%%================================================================
--
cgit v1.2.3
From 77371ab686d408e13dc8549085c0fdb9a5b30733 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 15 May 2017 13:58:27 +0200
Subject: ssh: ssh_file:user_key/2 checks ec keytype
---
lib/ssh/src/ssh_file.erl | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_file.erl b/lib/ssh/src/ssh_file.erl
index 6692432fcf..33792da38f 100644
--- a/lib/ssh/src/ssh_file.erl
+++ b/lib/ssh/src/ssh_file.erl
@@ -75,10 +75,7 @@ host_key(Algorithm, Opts) ->
Password = proplists:get_value(identity_pass_phrase(Algorithm), Opts, ignore),
case decode(File, Password) of
{ok,Key} ->
- case ssh_transport:valid_key_sha_alg(Key,Algorithm) of
- true -> {ok,Key};
- false -> {error,bad_keytype_in_file}
- end;
+ check_key_type(Key, Algorithm);
{error,DecodeError} ->
{error,DecodeError}
end.
@@ -104,10 +101,20 @@ is_host_key(Key, PeerName, Algorithm, Opts) ->
user_key(Algorithm, Opts) ->
File = file_name(user, identity_key_filename(Algorithm), Opts),
Password = proplists:get_value(identity_pass_phrase(Algorithm), Opts, ignore),
- decode(File, Password).
+ case decode(File, Password) of
+ {ok, Key} ->
+ check_key_type(Key, Algorithm);
+ Error ->
+ Error
+ end.
%% Internal functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+check_key_type(Key, Algorithm) ->
+ case ssh_transport:valid_key_sha_alg(Key,Algorithm) of
+ true -> {ok,Key};
+ false -> {error,bad_keytype_in_file}
+ end.
file_base_name('ssh-rsa' ) -> "ssh_host_rsa_key";
file_base_name('rsa-sha2-256' ) -> "ssh_host_rsa_key";
--
cgit v1.2.3
From df8ec436495f62cff4f433aaf9129505ee41e189 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 15 May 2017 19:30:14 +0200
Subject: ssh: Enable rsa-sha2-*
Conflicts:
lib/ssh/src/ssh_transport.erl
---
lib/ssh/src/ssh_transport.erl | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index bd1cb4bd22..aaec733f3c 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -92,10 +92,7 @@ default_algorithms(cipher) ->
default_algorithms(mac) ->
supported_algorithms(mac, same(['AEAD_AES_128_GCM',
'AEAD_AES_256_GCM']));
-default_algorithms(public_key) ->
- supported_algorithms(public_key, ['rsa-sha2-256',
- 'rsa-sha2-384',
- 'rsa-sha2-512']);
+
default_algorithms(Alg) ->
supported_algorithms(Alg, []).
@@ -122,10 +119,9 @@ supported_algorithms(public_key) ->
{'ecdsa-sha2-nistp384', [{public_keys,ecdsa}, {hashs,sha384}, {ec_curve,secp384r1}]},
{'ecdsa-sha2-nistp521', [{public_keys,ecdsa}, {hashs,sha512}, {ec_curve,secp521r1}]},
{'ecdsa-sha2-nistp256', [{public_keys,ecdsa}, {hashs,sha256}, {ec_curve,secp256r1}]},
+ {'ssh-rsa', [{public_keys,rsa}, {hashs,sha} ]},
{'rsa-sha2-256', [{public_keys,rsa}, {hashs,sha256} ]},
- {'rsa-sha2-384', [{public_keys,rsa}, {hashs,sha384} ]},
{'rsa-sha2-512', [{public_keys,rsa}, {hashs,sha512} ]},
- {'ssh-rsa', [{public_keys,rsa}, {hashs,sha} ]},
{'ssh-dss', [{public_keys,dss}, {hashs,sha} ]} % Gone in OpenSSH 7.3.p1
]);
--
cgit v1.2.3
From 235472ad819537bb357e254f48bae506a1e63213 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 12 May 2017 18:34:48 +0200
Subject: ssh: make ssh_algorithms_SUITE test public user and host keys
Conflicts:
lib/ssh/src/ssh_transport.erl
---
lib/ssh/test/ssh_algorithms_SUITE.erl | 163 +++++++++++++++++++++++-----------
lib/ssh/test/ssh_test_lib.erl | 6 +-
2 files changed, 114 insertions(+), 55 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_algorithms_SUITE.erl b/lib/ssh/test/ssh_algorithms_SUITE.erl
index 6e6269d3e0..cebd1296fa 100644
--- a/lib/ssh/test/ssh_algorithms_SUITE.erl
+++ b/lib/ssh/test/ssh_algorithms_SUITE.erl
@@ -68,7 +68,7 @@ groups() ->
TagGroupSet ++ AlgoTcSet.
-tags() -> [kex,cipher,mac,compression].
+tags() -> [kex,cipher,mac,compression,public_key].
two_way_tags() -> [cipher,mac,compression].
%%--------------------------------------------------------------------
@@ -123,20 +123,35 @@ init_per_group(Group, Config) ->
Tag = proplists:get_value(name,
hd(proplists:get_value(tc_group_path, Config))),
Alg = Group,
- PA =
- case split(Alg) of
- [_] ->
- [Alg];
- [A1,A2] ->
- [{client2server,[A1]},
- {server2client,[A2]}]
- end,
- ct:log("Init tests for tag=~p alg=~p",[Tag,PA]),
- PrefAlgs = {preferred_algorithms,[{Tag,PA}]},
- start_std_daemon([PrefAlgs],
- [{pref_algs,PrefAlgs} | Config])
+ init_per_group(Tag, Alg, Config)
end.
+
+init_per_group(public_key=Tag, Alg, Config) ->
+ ct:log("Init tests for public_key ~p",[Alg]),
+ PrefAlgs = {preferred_algorithms,[{Tag,[Alg]}]},
+ %% Daemon started later in init_per_testcase
+ [{pref_algs,PrefAlgs},
+ {tag_alg,{Tag,Alg}}
+ | Config];
+
+init_per_group(Tag, Alg, Config) ->
+ PA =
+ case split(Alg) of
+ [_] ->
+ [Alg];
+ [A1,A2] ->
+ [{client2server,[A1]},
+ {server2client,[A2]}]
+ end,
+ ct:log("Init tests for tag=~p alg=~p",[Tag,PA]),
+ PrefAlgs = {preferred_algorithms,[{Tag,PA}]},
+ start_std_daemon([PrefAlgs],
+ [{pref_algs,PrefAlgs},
+ {tag_alg,{Tag,Alg}}
+ | Config]).
+
+
end_per_group(_Alg, Config) ->
case proplists:get_value(srvr_pid,Config) of
Pid when is_pid(Pid) ->
@@ -148,23 +163,49 @@ end_per_group(_Alg, Config) ->
-init_per_testcase(sshc_simple_exec_os_cmd, Config) ->
- start_pubkey_daemon([proplists:get_value(pref_algs,Config)], Config);
-init_per_testcase(_TC, Config) ->
- Config.
+init_per_testcase(TC, Config) ->
+ init_per_testcase(TC, proplists:get_value(tag_alg,Config), Config).
-end_per_testcase(sshc_simple_exec_os_cmd, Config) ->
- case proplists:get_value(srvr_pid,Config) of
- Pid when is_pid(Pid) ->
- ssh:stop_daemon(Pid),
- ct:log("stopped ~p",[proplists:get_value(srvr_addr,Config)]);
- _ ->
- ok
+init_per_testcase(_, {public_key,Alg}, Config) ->
+ Opts = pubkey_opts(Config),
+ case {ssh_file:user_key(Alg,Opts), ssh_file:host_key(Alg,Opts)} of
+ {{ok,_}, {ok,_}} ->
+ start_pubkey_daemon([proplists:get_value(pref_algs,Config)],
+ [{extra_daemon,true}|Config]);
+ {{ok,_}, _} ->
+ {skip, "No host key"};
+
+ {_, {ok,_}} ->
+ {skip, "No user key"};
+
+ _ ->
+ {skip, "Neither host nor user key"}
end;
-end_per_testcase(_TC, Config) ->
+
+init_per_testcase(sshc_simple_exec_os_cmd, _, Config) ->
+ start_pubkey_daemon([proplists:get_value(pref_algs,Config)],
+ [{extra_daemon,true}|Config]);
+
+init_per_testcase(_, _, Config) ->
Config.
+
+end_per_testcase(_TC, Config) ->
+ case proplists:get_value(extra_daemon, Config, false) of
+ true ->
+ case proplists:get_value(srvr_pid,Config) of
+ Pid when is_pid(Pid) ->
+ ssh:stop_daemon(Pid),
+ ct:log("stopped ~p",[proplists:get_value(srvr_addr,Config)]),
+ Config;
+ _ ->
+ Config
+ end;
+ _ ->
+ Config
+ end.
+
%%--------------------------------------------------------------------
%% Test Cases --------------------------------------------------------
%%--------------------------------------------------------------------
@@ -318,29 +359,32 @@ concat(A1, A2) -> list_to_atom(lists:concat([A1," + ",A2])).
split(Alg) -> ssh_test_lib:to_atoms(string:tokens(atom_to_list(Alg), " + ")).
specific_test_cases(Tag, Alg, SshcAlgos, SshdAlgos, TypeSSH) ->
- [simple_exec, simple_sftp] ++
- case supports(Tag, Alg, SshcAlgos) of
- true when TypeSSH == openSSH ->
- [sshc_simple_exec_os_cmd];
- _ ->
- []
- end ++
- case supports(Tag, Alg, SshdAlgos) of
- true ->
- [sshd_simple_exec];
- _ ->
- []
- end ++
- case {Tag,Alg} of
- {kex,_} when Alg == 'diffie-hellman-group-exchange-sha1' ;
- Alg == 'diffie-hellman-group-exchange-sha256' ->
- [simple_exec_groups,
- simple_exec_groups_no_match_too_large,
- simple_exec_groups_no_match_too_small
- ];
- _ ->
- []
- end.
+ case Tag of
+ public_key -> [];
+ _ -> [simple_exec, simple_sftp]
+ end
+ ++ case supports(Tag, Alg, SshcAlgos) of
+ true when TypeSSH == openSSH ->
+ [sshc_simple_exec_os_cmd];
+ _ ->
+ []
+ end ++
+ case supports(Tag, Alg, SshdAlgos) of
+ true ->
+ [sshd_simple_exec];
+ _ ->
+ []
+ end ++
+ case {Tag,Alg} of
+ {kex,_} when Alg == 'diffie-hellman-group-exchange-sha1' ;
+ Alg == 'diffie-hellman-group-exchange-sha256' ->
+ [simple_exec_groups,
+ simple_exec_groups_no_match_too_large,
+ simple_exec_groups_no_match_too_small
+ ];
+ _ ->
+ []
+ end.
supports(Tag, Alg, Algos) ->
lists:all(fun(A) ->
@@ -370,19 +414,30 @@ start_std_daemon(Opts, Config) ->
ct:log("started ~p:~p ~p",[Host,Port,Opts]),
[{srvr_pid,Pid},{srvr_addr,{Host,Port}} | Config].
+
start_pubkey_daemon(Opts0, Config) ->
- Opts = [{auth_methods,"publickey"}|Opts0],
- {Pid, Host, Port} = ssh_test_lib:std_daemon1(Config, Opts),
- ct:log("started pubkey_daemon ~p:~p ~p",[Host,Port,Opts]),
+ ct:log("starting pubkey_daemon",[]),
+ Opts = pubkey_opts(Config) ++ Opts0,
+ {Pid, Host, Port} = ssh_test_lib:daemon([{failfun, fun ssh_test_lib:failfun/2}
+ | Opts]),
+ ct:log("started ~p:~p ~p",[Host,Port,Opts]),
[{srvr_pid,Pid},{srvr_addr,{Host,Port}} | Config].
+pubkey_opts(Config) ->
+ SystemDir = filename:join(proplists:get_value(priv_dir,Config), "system"),
+ [{auth_methods,"publickey"},
+ {system_dir, SystemDir}].
+
+
setup_pubkey(Config) ->
DataDir = proplists:get_value(data_dir, Config),
UserDir = proplists:get_value(priv_dir, Config),
- ssh_test_lib:setup_dsa(DataDir, UserDir),
- ssh_test_lib:setup_rsa(DataDir, UserDir),
- ssh_test_lib:setup_ecdsa("256", DataDir, UserDir),
+ Keys =
+ [ssh_test_lib:setup_dsa(DataDir, UserDir),
+ ssh_test_lib:setup_rsa(DataDir, UserDir),
+ ssh_test_lib:setup_ecdsa("256", DataDir, UserDir)],
+ ssh_test_lib:write_auth_keys(Keys, UserDir), % 'authorized_keys' shall contain ALL pub keys
Config.
diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl
index 36ae2525da..7b273fecef 100644
--- a/lib/ssh/test/ssh_test_lib.erl
+++ b/lib/ssh/test/ssh_test_lib.erl
@@ -500,8 +500,12 @@ setup_ecdsa_auth_keys(_Size, Dir, UserDir) ->
setup_auth_keys(Keys, Dir) ->
AuthKeys = public_key:ssh_encode(Keys, auth_keys),
AuthKeysFile = filename:join(Dir, "authorized_keys"),
- file:write_file(AuthKeysFile, AuthKeys).
+ ok = file:write_file(AuthKeysFile, AuthKeys),
+ AuthKeys.
+write_auth_keys(Keys, Dir) ->
+ AuthKeysFile = filename:join(Dir, "authorized_keys"),
+ file:write_file(AuthKeysFile, Keys).
del_dirs(Dir) ->
case file:list_dir(Dir) of
--
cgit v1.2.3
From f4cf6605e8ddf4accb553c155a77878031850128 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 5 May 2017 16:18:00 +0200
Subject: ssh: fix broken preferred_algorithms and pref_public_key_algs options
---
lib/ssh/doc/src/ssh.xml | 8 +++++---
lib/ssh/src/ssh_options.erl | 28 ++++++++++++++++------------
2 files changed, 21 insertions(+), 15 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index c659e093b9..5c9ce3d5fb 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -246,10 +246,12 @@
-
List of user (client) public key algorithms to try to use.
- The default value is
-
+
The default value is the public_key entry in
+ ssh:default_algorithms/0.
+
+ If there is no public key of a specified type available, the corresponding entry is ignored.
+ Note that the available set is dependent on the underlying cryptolib and current user's public keys.
- If there is no public key of a specified type available, the corresponding entry is ignored.
diff --git a/lib/ssh/src/ssh_options.erl b/lib/ssh/src/ssh_options.erl
index 78f68dbcb1..aebb5a7062 100644
--- a/lib/ssh/src/ssh_options.erl
+++ b/lib/ssh/src/ssh_options.erl
@@ -430,12 +430,9 @@ default(client) ->
},
{pref_public_key_algs, def} =>
- #{default =>
- ssh_transport:supported_algorithms(public_key),
- chk =>
- fun check_pref_public_key_algs/1,
- class =>
- ssh
+ #{default => ssh_transport:default_algorithms(public_key),
+ chk => fun check_pref_public_key_algs/1,
+ class => user_options
},
{dh_gex_limits, def} =>
@@ -817,16 +814,23 @@ valid_hash(X, _) -> error_in_check(X, "Expect atom or list in fingerprint spec"
%%%----------------------------------------------------------------
check_preferred_algorithms(Algs) ->
+ [error_in_check(K,"Bad preferred_algorithms key")
+ || {K,_} <- Algs,
+ not lists:keymember(K,1,ssh:default_algorithms())],
+
try alg_duplicates(Algs, [], [])
of
[] ->
{true,
- [try ssh_transport:supported_algorithms(Key)
- of
- DefAlgs -> handle_pref_alg(Key,Vals,DefAlgs)
- catch
- _:_ -> error_in_check(Key,"Bad preferred_algorithms key")
- end || {Key,Vals} <- Algs]
+ [case proplists:get_value(Key, Algs) of
+ undefined ->
+ {Key,DefAlgs};
+ Vals ->
+ handle_pref_alg(Key,Vals,SupAlgs)
+ end
+ || {{Key,DefAlgs}, {Key,SupAlgs}} <- lists:zip(ssh:default_algorithms(),
+ ssh_transport:supported_algorithms())
+ ]
};
Dups ->
--
cgit v1.2.3
From ebd2baf9c433d489aff66f14505b5c221ba04165 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 8 May 2017 14:57:11 +0200
Subject: ssh: Use 'server-sig-algs' for client's selection of algs
---
lib/ssh/src/ssh_connection_handler.erl | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 39bd54869f..6a6b9896cb 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -1701,15 +1701,18 @@ handle_ssh_msg_ext_info(#ssh_msg_ext_info{data=Data}, D0) ->
lists:foldl(fun ext_info/2, D0, Data).
-ext_info({"server-sig-algs",SigAlgs}, D0 = #data{ssh_params=#ssh{role=client}=Ssh0}) ->
+ext_info({"server-sig-algs",SigAlgs}, D0 = #data{ssh_params=#ssh{role=client,
+ userauth_pubkeys=ClientSigAlgs}=Ssh0}) ->
%% Make strings to eliminate risk of beeing bombed with odd strings that fills the atom table:
SupportedAlgs = lists:map(fun erlang:atom_to_list/1, ssh_transport:supported_algorithms(public_key)),
- Ssh = Ssh0#ssh{userauth_pubkeys =
- [list_to_atom(SigAlg) || SigAlg <- string:tokens(SigAlgs,","),
- %% length of SigAlg is implicitly checked by member:
- lists:member(SigAlg, SupportedAlgs)
- ]},
- D0#data{ssh_params = Ssh};
+ ServerSigAlgs = [list_to_atom(SigAlg) || SigAlg <- string:tokens(SigAlgs,","),
+ %% length of SigAlg is implicitly checked by the comparison
+ %% in member/2:
+ lists:member(SigAlg, SupportedAlgs)
+ ],
+ CommonAlgs = [Alg || Alg <- ServerSigAlgs,
+ lists:member(Alg, ClientSigAlgs)],
+ D0#data{ssh_params = Ssh0#ssh{userauth_pubkeys = CommonAlgs} };
ext_info(_, D0) ->
%% Not implemented
--
cgit v1.2.3
From 90de09b680d33bf4e048771381134ac8d7e0fa70 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 11 May 2017 15:19:18 +0200
Subject: ssh: select server-sig-algs from configured algos
(preferred_algorithms)
---
lib/ssh/src/ssh_transport.erl | 6 ++++--
lib/ssh/test/ssh_basic_SUITE.erl | 2 +-
2 files changed, 5 insertions(+), 3 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index bd1cb4bd22..cebbec7792 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -741,9 +741,11 @@ ext_info_message(#ssh{role=client,
end;
ext_info_message(#ssh{role=server,
- send_ext_info=true} = Ssh0) ->
+ send_ext_info=true,
+ opts = Opts} = Ssh0) ->
AlgsList = lists:map(fun erlang:atom_to_list/1,
- ssh_transport:default_algorithms(public_key)),
+ proplists:get_value(public_key,
+ ?GET_OPT(preferred_algorithms, Opts))),
Msg = #ssh_msg_ext_info{nr_extensions = 1,
data = [{"server-sig-algs", string:join(AlgsList,",")}]
},
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index 1e591bc295..62e2a585e4 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -612,7 +612,7 @@ exec_key_differs(Config, UserPKAlgs) ->
{_Pid, _Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
{user_dir, SystemUserDir},
{preferred_algorithms,
- [{public_key,['ssh-rsa']}]}]),
+ [{public_key,['ssh-rsa'|UserPKAlgs]}]}]),
ct:sleep(500),
IO = ssh_test_lib:start_io_server(),
--
cgit v1.2.3
From 4d7ff0a8169141d18335638cf7c6e48d4c18cdf2 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Tue, 16 May 2017 11:52:45 +0200
Subject: ssh: disable rsa-sha2-* for clients because there is a bug in the
client verification code for those algorithms
---
lib/ssh/src/ssh_options.erl | 29 ++++++++++++++++++++++-------
1 file changed, 22 insertions(+), 7 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_options.erl b/lib/ssh/src/ssh_options.erl
index aebb5a7062..12c0190082 100644
--- a/lib/ssh/src/ssh_options.erl
+++ b/lib/ssh/src/ssh_options.erl
@@ -392,6 +392,12 @@ default(server) ->
class => user_options
},
+ {preferred_algorithms, def} =>
+ #{default => ssh:default_algorithms(),
+ chk => fun check_preferred_algorithms/1,
+ class => user_options
+ },
+
%%%%% Undocumented
{infofun, def} =>
#{default => fun(_,_,_) -> void end,
@@ -430,11 +436,26 @@ default(client) ->
},
{pref_public_key_algs, def} =>
- #{default => ssh_transport:default_algorithms(public_key),
+ #{default => ssh_transport:default_algorithms(public_key) -- ['rsa-sha2-256',
+ 'rsa-sha2-512'],
chk => fun check_pref_public_key_algs/1,
class => user_options
},
+ {preferred_algorithms, def} =>
+ #{default => [{K,Vs} || {K,Vs0} <- ssh:default_algorithms(),
+ Vs <- [case K of
+ public_key ->
+ Vs0 -- ['rsa-sha2-256',
+ 'rsa-sha2-512'];
+ _ ->
+ Vs0
+ end]
+ ],
+ chk => fun check_preferred_algorithms/1,
+ class => user_options
+ },
+
{dh_gex_limits, def} =>
#{default => {1024, 6144, 8192}, % FIXME: Is this true nowadays?
chk => fun({Min,I,Max}) ->
@@ -500,12 +521,6 @@ default(common) ->
class => user_options
},
- {preferred_algorithms, def} =>
- #{default => ssh:default_algorithms(),
- chk => fun check_preferred_algorithms/1,
- class => user_options
- },
-
{id_string, def} =>
#{default => undefined, % FIXME: see ssh_transport:ssh_vsn/0
chk => fun(random) ->
--
cgit v1.2.3
From 48a3dc284f0f214ffda9e32a9ef2282cace0e80b Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 10 May 2017 15:00:09 +0200
Subject: ssh: fix end_per_suite in property testcase
---
lib/ssh/test/ssh_property_test_SUITE.erl | 3 +++
1 file changed, 3 insertions(+)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_property_test_SUITE.erl b/lib/ssh/test/ssh_property_test_SUITE.erl
index 9b2a84d8e4..5ea60d8a8f 100644
--- a/lib/ssh/test/ssh_property_test_SUITE.erl
+++ b/lib/ssh/test/ssh_property_test_SUITE.erl
@@ -55,6 +55,9 @@ groups() ->
init_per_suite(Config) ->
ct_property_test:init_per_suite(Config).
+end_per_suite(Config) ->
+ Config.
+
%%% One group in this suite happens to support only QuickCheck, so skip it
%%% if we run proper.
init_per_group(client_server, Config) ->
--
cgit v1.2.3
From 0df70c244df12c0a0678b04401e891e4683d7f69 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 10 May 2017 15:27:30 +0200
Subject: ssh: update property test for sign-algorithm
---
lib/ssh/test/property_test/ssh_eqc_encode_decode.erl | 10 ++++++++++
1 file changed, 10 insertions(+)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl b/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl
index 410a9ea983..0995182623 100644
--- a/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl
+++ b/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl
@@ -284,8 +284,18 @@ fix_asym(#ssh_msg_global_request{name=N} = M) -> M#ssh_msg_global_request{name =
fix_asym(#ssh_msg_debug{message=D,language=L} = M) -> M#ssh_msg_debug{message = binary_to_list(D),
language = binary_to_list(L)};
fix_asym(#ssh_msg_kexinit{cookie=C} = M) -> M#ssh_msg_kexinit{cookie = <>};
+
+fix_asym(#ssh_msg_kexdh_reply{public_host_key = Key} = M) -> M#ssh_msg_kexdh_reply{public_host_key = key_sigalg(Key)};
+fix_asym(#ssh_msg_kex_dh_gex_reply{public_host_key = Key} = M) -> M#ssh_msg_kex_dh_gex_reply{public_host_key = key_sigalg(Key)};
+fix_asym(#ssh_msg_kex_ecdh_reply{public_host_key = Key} = M) -> M#ssh_msg_kex_ecdh_reply{public_host_key = key_sigalg(Key)};
+
fix_asym(M) -> M.
+%%% Keys now contains an sig-algorithm name
+key_sigalg(#'RSAPublicKey'{} = Key) -> {Key,'ssh-rsa'};
+key_sigalg({_, #'Dss-Parms'{}} = Key) -> {Key,'ssh-dss'};
+key_sigalg({#'ECPoint'{}, {namedCurve,OID}} = Key) -> {Key,"ecdsa-sha2-256"}.
+
%%% Message codes 30 and 31 are overloaded depending on kex family so arrange the decoder
%%% input as the test object does
decode_state(<<30,_/binary>>=Msg, KexFam) -> <>;
--
cgit v1.2.3
From 18354f6a90f15e035ad76cda9c572c8b7a976a9a Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 15 May 2017 10:21:57 +0200
Subject: ssh: test case didn't set preferred_algorithms
---
lib/ssh/test/ssh_algorithms_SUITE.erl | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_algorithms_SUITE.erl b/lib/ssh/test/ssh_algorithms_SUITE.erl
index 6e6269d3e0..c94309bb3e 100644
--- a/lib/ssh/test/ssh_algorithms_SUITE.erl
+++ b/lib/ssh/test/ssh_algorithms_SUITE.erl
@@ -260,8 +260,9 @@ sshc_simple_exec_os_cmd(Config) ->
%%--------------------------------------------------------------------
%% Connect to the ssh server of the OS
-sshd_simple_exec(_Config) ->
+sshd_simple_exec(Config) ->
ConnectionRef = ssh_test_lib:connect(22, [{silently_accept_hosts, true},
+ proplists:get_value(pref_algs,Config),
{user_interaction, false}]),
{ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity),
success = ssh_connection:exec(ConnectionRef, ChannelId0,
--
cgit v1.2.3
From 8ce069a1ad162d18d6f986e6d1a7498ca3404e08 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 15 May 2017 12:55:10 +0200
Subject: ssh: update testcase in ssh_to_openssh
---
lib/ssh/test/ssh_to_openssh_SUITE.erl | 68 +++++++++++++----------------------
1 file changed, 25 insertions(+), 43 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl
index a3d596a1c9..4d6aa93d4e 100644
--- a/lib/ssh/test/ssh_to_openssh_SUITE.erl
+++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl
@@ -107,6 +107,9 @@ init_per_testcase(erlang_server_openssh_client_public_key_rsa, Config) ->
chk_key(sshc, 'ssh-rsa', ".ssh/id_rsa", Config);
init_per_testcase(erlang_client_openssh_server_publickey_dsa, Config) ->
chk_key(sshd, 'ssh-dss', ".ssh/id_dsa", Config);
+init_per_testcase(erlang_client_openssh_server_publickey_rsa, Config) ->
+ chk_key(sshd, 'ssh-rsa', ".ssh/id_rsa", Config);
+
init_per_testcase(erlang_server_openssh_client_renegotiate, Config) ->
case os:type() of
{unix,_} -> ssh:start(), Config;
@@ -322,65 +325,44 @@ erlang_client_openssh_server_setenv(Config) when is_list(Config) ->
%% setenv not meaningfull on erlang ssh daemon!
%%--------------------------------------------------------------------
-erlang_client_openssh_server_publickey_rsa() ->
- [{doc, "Validate using rsa publickey."}].
-erlang_client_openssh_server_publickey_rsa(Config) when is_list(Config) ->
- {ok,[[Home]]} = init:get_argument(home),
- KeyFile = filename:join(Home, ".ssh/id_rsa"),
- case file:read_file(KeyFile) of
- {ok, Pem} ->
- case public_key:pem_decode(Pem) of
- [{_,_, not_encrypted}] ->
- ConnectionRef =
- ssh_test_lib:connect(?SSH_DEFAULT_PORT,
- [{pref_public_key_algs, ['ssh-rsa','ssh-dss']},
- {user_interaction, false},
- silently_accept_hosts]),
- {ok, Channel} =
- ssh_connection:session_channel(ConnectionRef, infinity),
- ok = ssh_connection:close(ConnectionRef, Channel),
- ok = ssh:close(ConnectionRef);
- _ ->
- {skip, {error, "Has pass phrase can not be used by automated test case"}}
- end;
- _ ->
- {skip, "no ~/.ssh/id_rsa"}
- end.
-
+erlang_client_openssh_server_publickey_rsa(Config) ->
+ erlang_client_openssh_server_publickey_X(Config, 'ssh-rsa').
+
+erlang_client_openssh_server_publickey_dsa(Config) ->
+ erlang_client_openssh_server_publickey_X(Config, 'ssh-dss').
-%%--------------------------------------------------------------------
-erlang_client_openssh_server_publickey_dsa() ->
- [{doc, "Validate using dsa publickey."}].
-erlang_client_openssh_server_publickey_dsa(Config) when is_list(Config) ->
+
+erlang_client_openssh_server_publickey_X(Config, Alg) ->
ConnectionRef =
- ssh_test_lib:connect(?SSH_DEFAULT_PORT,
- [{pref_public_key_algs, ['ssh-dss','ssh-rsa']},
- {user_interaction, false},
- silently_accept_hosts]),
+ ssh_test_lib:connect(?SSH_DEFAULT_PORT,
+ [{pref_public_key_algs, [Alg]},
+ {user_interaction, false},
+ {auth_methods, "publickey"},
+ silently_accept_hosts]),
{ok, Channel} =
- ssh_connection:session_channel(ConnectionRef, infinity),
+ ssh_connection:session_channel(ConnectionRef, infinity),
ok = ssh_connection:close(ConnectionRef, Channel),
ok = ssh:close(ConnectionRef).
%%--------------------------------------------------------------------
erlang_server_openssh_client_public_key_dsa() ->
- [{timetrap, {seconds,(?TIMEOUT div 1000)+10}},
- {doc, "Validate using dsa publickey."}].
+ [{timetrap, {seconds,(?TIMEOUT div 1000)+10}}].
erlang_server_openssh_client_public_key_dsa(Config) when is_list(Config) ->
- erlang_server_openssh_client_public_key_X(Config, ssh_dsa).
+ erlang_server_openssh_client_public_key_X(Config, 'ssh-dss').
-erlang_server_openssh_client_public_key_rsa() ->
- [{timetrap, {seconds,(?TIMEOUT div 1000)+10}},
- {doc, "Validate using rsa publickey."}].
+erlang_server_openssh_client_public_key_rsa() ->
+ [{timetrap, {seconds,(?TIMEOUT div 1000)+10}}].
erlang_server_openssh_client_public_key_rsa(Config) when is_list(Config) ->
- erlang_server_openssh_client_public_key_X(Config, ssh_rsa).
+ erlang_server_openssh_client_public_key_X(Config, 'ssh-rsa').
-erlang_server_openssh_client_public_key_X(Config, _PubKeyAlg) ->
+erlang_server_openssh_client_public_key_X(Config, Alg) ->
SystemDir = proplists:get_value(data_dir, Config),
PrivDir = proplists:get_value(priv_dir, Config),
KnownHosts = filename:join(PrivDir, "known_hosts"),
{Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ {preferred_algorithms,[{public_key, [Alg]}]},
+ {auth_methods, "publickey"},
{failfun, fun ssh_test_lib:failfun/2}]),
ct:sleep(500),
@@ -401,7 +383,7 @@ erlang_server_openssh_client_renegotiate(Config) ->
KnownHosts = filename:join(PrivDir, "known_hosts"),
{Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
- {failfun, fun ssh_test_lib:failfun/2}]),
+ {failfun, fun ssh_test_lib:failfun/2}]),
ct:sleep(500),
RenegLimitK = 3,
--
cgit v1.2.3
From 594d84311dd22658df695f238ac562fdcba9f060 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 18 May 2017 20:52:53 +0200
Subject: Revert "ssh: disable rsa-sha2-* for clients"
This reverts commit 4d7ff0a8169141d18335638cf7c6e48d4c18cdf2.
---
lib/ssh/src/ssh_options.erl | 29 +++++++----------------------
1 file changed, 7 insertions(+), 22 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_options.erl b/lib/ssh/src/ssh_options.erl
index 12c0190082..aebb5a7062 100644
--- a/lib/ssh/src/ssh_options.erl
+++ b/lib/ssh/src/ssh_options.erl
@@ -392,12 +392,6 @@ default(server) ->
class => user_options
},
- {preferred_algorithms, def} =>
- #{default => ssh:default_algorithms(),
- chk => fun check_preferred_algorithms/1,
- class => user_options
- },
-
%%%%% Undocumented
{infofun, def} =>
#{default => fun(_,_,_) -> void end,
@@ -436,26 +430,11 @@ default(client) ->
},
{pref_public_key_algs, def} =>
- #{default => ssh_transport:default_algorithms(public_key) -- ['rsa-sha2-256',
- 'rsa-sha2-512'],
+ #{default => ssh_transport:default_algorithms(public_key),
chk => fun check_pref_public_key_algs/1,
class => user_options
},
- {preferred_algorithms, def} =>
- #{default => [{K,Vs} || {K,Vs0} <- ssh:default_algorithms(),
- Vs <- [case K of
- public_key ->
- Vs0 -- ['rsa-sha2-256',
- 'rsa-sha2-512'];
- _ ->
- Vs0
- end]
- ],
- chk => fun check_preferred_algorithms/1,
- class => user_options
- },
-
{dh_gex_limits, def} =>
#{default => {1024, 6144, 8192}, % FIXME: Is this true nowadays?
chk => fun({Min,I,Max}) ->
@@ -521,6 +500,12 @@ default(common) ->
class => user_options
},
+ {preferred_algorithms, def} =>
+ #{default => ssh:default_algorithms(),
+ chk => fun check_preferred_algorithms/1,
+ class => user_options
+ },
+
{id_string, def} =>
#{default => undefined, % FIXME: see ssh_transport:ssh_vsn/0
chk => fun(random) ->
--
cgit v1.2.3
From c99b6f0aa70457453b37533adf6d3872f7009fac Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 18 May 2017 10:03:34 +0200
Subject: ssh: Handle if server-sig-algs and client has empty intersection In
case server-sig-algs names only algorithms unknown to the client, the client
will try with the ones it knows
---
lib/ssh/src/ssh_connection_handler.erl | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 6a6b9896cb..a77cfe51b5 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -1712,7 +1712,12 @@ ext_info({"server-sig-algs",SigAlgs}, D0 = #data{ssh_params=#ssh{role=client,
],
CommonAlgs = [Alg || Alg <- ServerSigAlgs,
lists:member(Alg, ClientSigAlgs)],
- D0#data{ssh_params = Ssh0#ssh{userauth_pubkeys = CommonAlgs} };
+ SelectedAlgs =
+ case CommonAlgs of
+ [] -> ClientSigAlgs; % server-sig-algs value is just an advice
+ _ -> CommonAlgs
+ end,
+ D0#data{ssh_params = Ssh0#ssh{userauth_pubkeys = SelectedAlgs} };
ext_info(_, D0) ->
%% Not implemented
--
cgit v1.2.3
From 3507ea008839ad68dc16060a2696e3efde551684 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 18 May 2017 20:33:14 +0200
Subject: ssh: fix the rsa-sha2-* hostkey verify error
---
lib/ssh/src/ssh_message.erl | 4 ++--
lib/ssh/src/ssh_transport.erl | 18 +++++++++++-------
2 files changed, 13 insertions(+), 9 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_message.erl b/lib/ssh/src/ssh_message.erl
index 609040826f..4f2eeca026 100644
--- a/lib/ssh/src/ssh_message.erl
+++ b/lib/ssh/src/ssh_message.erl
@@ -598,8 +598,8 @@ decode_kex_init(<>, Acc, N) ->
%%% Signature decode/encode
%%%
-decode_signature(<>) ->
- Signature.
+decode_signature(<>) ->
+ {binary_to_list(Alg), Signature}.
encode_signature({#'RSAPublicKey'{},Sign}, Signature) ->
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 1a15798080..412f5de9de 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -776,16 +776,20 @@ extract_public_key(#'ECPrivateKey'{parameters = {namedCurve,OID},
{#'ECPoint'{point=Q}, {namedCurve,OID}}.
-verify_host_key(#ssh{algorithms=Alg}=SSH, PublicKey, Digest, Signature) ->
- case verify(Digest, sha(Alg#alg.hkey), Signature, PublicKey) of
- false ->
- {error, bad_signature};
- true ->
- known_host_key(SSH, PublicKey, public_algo(PublicKey))
+verify_host_key(#ssh{algorithms=Alg}=SSH, PublicKey, Digest, {AlgStr,Signature}) ->
+ case atom_to_list(Alg#alg.hkey) of
+ AlgStr ->
+ case verify(Digest, sha(Alg#alg.hkey), Signature, PublicKey) of
+ false ->
+ {error, bad_signature};
+ true ->
+ known_host_key(SSH, PublicKey, public_algo(PublicKey))
+ end;
+ _ ->
+ {error, bad_signature_name}
end.
-
accepted_host(Ssh, PeerName, Public, Opts) ->
case ?GET_OPT(silently_accept_hosts, Opts) of
--
cgit v1.2.3
From 8343f1a9c8b6b9e506a298d286eb5e480f516fd3 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 18 May 2017 17:53:27 +0200
Subject: ssh: remove extra options copy from internal state
---
lib/ssh/src/ssh_connection_handler.erl | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 6a6b9896cb..5ca040f7ec 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -346,7 +346,7 @@ renegotiate_data(ConnectionHandler) ->
| undefined,
last_size_rekey = 0 :: non_neg_integer(),
event_queue = [] :: list(),
- opts :: ssh_options:options(),
+% opts :: ssh_options:options(),
inet_initial_recbuf_size :: pos_integer()
| undefined
}).
@@ -398,8 +398,7 @@ init([Role,Socket,Opts]) ->
transport_protocol = Protocol,
transport_cb = Callback,
transport_close_tag = CloseTag,
- ssh_params = init_ssh_record(Role, Socket, PeerAddr, Opts),
- opts = Opts
+ ssh_params = init_ssh_record(Role, Socket, PeerAddr, Opts)
},
D = case Role of
client ->
@@ -1012,7 +1011,7 @@ handle_event(cast, renegotiate, _, _) ->
handle_event(cast, data_size, {connected,Role}, D) ->
{ok, [{send_oct,Sent0}]} = inet:getstat(D#data.socket, [send_oct]),
Sent = Sent0 - D#data.last_size_rekey,
- MaxSent = ?GET_OPT(rekey_limit, D#data.opts),
+ MaxSent = ?GET_OPT(rekey_limit, (D#data.ssh_params)#ssh.opts),
timer:apply_after(?REKEY_DATA_TIMOUT, gen_statem, cast, [self(), data_size]),
case Sent >= MaxSent of
true ->
@@ -1862,7 +1861,7 @@ get_repl(X, Acc) ->
exit({get_repl,X,Acc}).
%%%----------------------------------------------------------------
--define(CALL_FUN(Key,D), catch (?GET_OPT(Key, D#data.opts)) ).
+-define(CALL_FUN(Key,D), catch (?GET_OPT(Key, (D#data.ssh_params)#ssh.opts)) ).
disconnect_fun({disconnect,Msg}, D) -> ?CALL_FUN(disconnectfun,D)(Msg);
disconnect_fun(Reason, D) -> ?CALL_FUN(disconnectfun,D)(Reason).
@@ -1912,7 +1911,7 @@ retry_fun(User, Reason, #data{ssh_params = #ssh{opts = Opts,
%%% channels open for a while.
cache_init_idle_timer(D) ->
- case ?GET_OPT(idle_time, D#data.opts) of
+ case ?GET_OPT(idle_time, (D#data.ssh_params)#ssh.opts) of
infinity ->
D#data{idle_timer_value = infinity,
idle_timer_ref = infinity % A flag used later...
--
cgit v1.2.3
From 580dc012238b4fd2839730c0c44edaef55dc9b4b Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 22 May 2017 15:03:09 +0200
Subject: ssh: fix ssh_property_test
---
lib/ssh/src/ssh_message.erl | 10 ----------
lib/ssh/test/property_test/ssh_eqc_encode_decode.erl | 18 +++++++++---------
2 files changed, 9 insertions(+), 19 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_message.erl b/lib/ssh/src/ssh_message.erl
index 4f2eeca026..b1fc05ae33 100644
--- a/lib/ssh/src/ssh_message.erl
+++ b/lib/ssh/src/ssh_message.erl
@@ -611,13 +611,3 @@ encode_signature({{#'ECPoint'{}, {namedCurve,OID}},_}, Signature) ->
CurveName = public_key:oid2ssh_curvename(OID),
<>), ?Ebinary(Signature)>>.
-%% encode_signature(#'RSAPublicKey'{}, Signature) ->
-%% SignName = <<"ssh-rsa">>,
-%% <>;
-%% encode_signature({_, #'Dss-Parms'{}}, Signature) ->
-%% <>), ?Ebinary(Signature)>>;
-%% encode_signature({#'ECPoint'{}, {namedCurve,OID}}, Signature) ->
-%% CurveName = public_key:oid2ssh_curvename(OID),
-%% <>), ?Ebinary(Signature)>>.
-
-
diff --git a/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl b/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl
index 0995182623..165274241c 100644
--- a/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl
+++ b/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl
@@ -280,21 +280,21 @@ msg_code(Num) -> Name
-include_lib("ssh/src/ssh_transport.hrl").
%%% Encoding and decodeing is asymetric so out=binary in=string. Sometimes. :(
+-define(fix_asym_Xdh_reply(S),
+ fix_asym(#S{public_host_key = Key, h_sig = {Alg,Sig}} = M) ->
+ M#S{public_host_key = {Key, list_to_atom(Alg)}, h_sig = Sig}
+).
+
+
fix_asym(#ssh_msg_global_request{name=N} = M) -> M#ssh_msg_global_request{name = binary_to_list(N)};
fix_asym(#ssh_msg_debug{message=D,language=L} = M) -> M#ssh_msg_debug{message = binary_to_list(D),
language = binary_to_list(L)};
fix_asym(#ssh_msg_kexinit{cookie=C} = M) -> M#ssh_msg_kexinit{cookie = <>};
-
-fix_asym(#ssh_msg_kexdh_reply{public_host_key = Key} = M) -> M#ssh_msg_kexdh_reply{public_host_key = key_sigalg(Key)};
-fix_asym(#ssh_msg_kex_dh_gex_reply{public_host_key = Key} = M) -> M#ssh_msg_kex_dh_gex_reply{public_host_key = key_sigalg(Key)};
-fix_asym(#ssh_msg_kex_ecdh_reply{public_host_key = Key} = M) -> M#ssh_msg_kex_ecdh_reply{public_host_key = key_sigalg(Key)};
-
+?fix_asym_Xdh_reply(ssh_msg_kexdh_reply);
+?fix_asym_Xdh_reply(ssh_msg_kex_dh_gex_reply);
+?fix_asym_Xdh_reply(ssh_msg_kex_ecdh_reply);
fix_asym(M) -> M.
-%%% Keys now contains an sig-algorithm name
-key_sigalg(#'RSAPublicKey'{} = Key) -> {Key,'ssh-rsa'};
-key_sigalg({_, #'Dss-Parms'{}} = Key) -> {Key,'ssh-dss'};
-key_sigalg({#'ECPoint'{}, {namedCurve,OID}} = Key) -> {Key,"ecdsa-sha2-256"}.
%%% Message codes 30 and 31 are overloaded depending on kex family so arrange the decoder
%%% input as the test object does
--
cgit v1.2.3
From 254422231e50ced8014eb84b9d80136b45483cc2 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 22 May 2017 15:36:52 +0200
Subject: ssh: disable faulty ssh_upgrade_SUITE
---
lib/ssh/test/ssh.spec | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh.spec b/lib/ssh/test/ssh.spec
index 68268cb20d..b4e3d36072 100644
--- a/lib/ssh/test/ssh.spec
+++ b/lib/ssh/test/ssh.spec
@@ -1,6 +1,7 @@
{suites,"../ssh_test",all}.
-{skip_suites, "../ssh_test", [ssh_bench_SUITE
+{skip_suites, "../ssh_test", [ssh_bench_SUITE,
+ ssh_upgrade_SUITE
],
"Benchmarks run separately"}.
--
cgit v1.2.3
From 917712f10dd5e8dea17d12f7c9835680ad32ba9f Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Fri, 19 May 2017 16:48:08 +0200
Subject: ssh: ssh_dbg print some server-sig-algs info
---
lib/ssh/src/ssh_dbg.erl | 25 ++++++++++++++++++++++++-
1 file changed, 24 insertions(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_dbg.erl b/lib/ssh/src/ssh_dbg.erl
index 7dfbfc3b4b..820d7ec61b 100644
--- a/lib/ssh/src/ssh_dbg.erl
+++ b/lib/ssh/src/ssh_dbg.erl
@@ -58,7 +58,8 @@ dbg_ssh_messages() ->
dbg:tp(ssh_message,decode,1, x),
dbg:tpl(ssh_transport,select_algorithm,4, x),
dbg:tp(ssh_transport,hello_version_msg,1, x),
- dbg:tp(ssh_transport,handle_hello_version,1, x).
+ dbg:tp(ssh_transport,handle_hello_version,1, x),
+ dbg:tpl(ssh_connection_handler,ext_info,2, x).
%%%----------------------------------------------------------------
stop() ->
@@ -90,6 +91,28 @@ msg_formater({trace_ts,Pid,call,{ssh_transport,handle_hello_version,[Hello]},TS}
msg_formater({trace_ts,_Pid,return_from,{ssh_transport,handle_hello_version,1},_,_TS}, D) ->
D;
+msg_formater({trace_ts,Pid,call,{ssh_connection_handler,ext_info,[{"server-sig-algs",_SigAlgs},State]},TS}, D) ->
+ try lists:keyfind(ssh, 1, tuple_to_list(State)) of
+ false ->
+ D;
+ #ssh{userauth_pubkeys = PKs} ->
+ fmt("~n~s ~p Client suggests ~p~n", [ts(TS),Pid,PKs], D)
+ catch
+ _:_ ->
+ D
+ end;
+
+msg_formater({trace_ts,Pid,return_from,{ssh_connection_handler,ext_info,2},State,TS}, D) ->
+ try lists:keyfind(ssh, 1, tuple_to_list(State)) of
+ false ->
+ D;
+ #ssh{userauth_pubkeys = PKs} ->
+ fmt("~n~s ~p Client will try public keys ~p~n", [ts(TS),Pid,PKs], D)
+ catch
+ _:_ ->
+ D
+ end;
+
msg_formater({trace_ts,Pid,send,{tcp,Sock,Bytes},Pid,TS}, D) ->
fmt("~n~s ~p TCP SEND on ~p~n ~p~n", [ts(TS),Pid,Sock, shrink_bin(Bytes)], D);
--
cgit v1.2.3
From d1a31c78d75c16a360ee1de973660b9ec1caeb58 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 22 May 2017 16:49:37 +0200
Subject: ssh: Undocumented ssh_dbg extended with auth/0 auth/1 auth/2
ct_auth/0 ct_messages/0
---
lib/ssh/src/ssh_dbg.erl | 134 ++++++++++++++++++++++++++++++++++++------------
1 file changed, 102 insertions(+), 32 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_dbg.erl b/lib/ssh/src/ssh_dbg.erl
index 820d7ec61b..003b3856e6 100644
--- a/lib/ssh/src/ssh_dbg.erl
+++ b/lib/ssh/src/ssh_dbg.erl
@@ -22,9 +22,10 @@
-module(ssh_dbg).
--export([messages/0,
- messages/1,
- messages/2,
+-export([messages/0, messages/1, messages/2,
+ ct_messages/0,
+ auth/0, auth/1, auth/2,
+ ct_auth/0,
stop/0
]).
@@ -43,15 +44,33 @@
messages() ->
messages(fun(String,_D) -> io:format(String) end).
+ct_messages() ->
+ messages(fun(String,_D) -> ct:log(String,[]) end).
+
messages(Write) when is_function(Write,2) ->
messages(Write, fun(X) -> X end).
messages(Write, MangleArg) when is_function(Write,2),
is_function(MangleArg,1) ->
- catch dbg:start(),
- setup_tracer(Write, MangleArg),
- dbg:p(new,[c,timestamp]),
- dbg_ssh_messages().
+ cond_start(msg, Write, MangleArg),
+ dbg_ssh_messages(),
+ dbg_ssh_auth().
+
+
+auth() ->
+ auth(fun(String,_D) -> io:format(String) end).
+
+ct_auth() ->
+ auth(fun(String,_D) -> ct:log(String,[]) end).
+
+auth(Write) when is_function(Write,2) ->
+ auth(Write, fun(X) -> X end).
+
+auth(Write, MangleArg) when is_function(Write,2),
+ is_function(MangleArg,1) ->
+ cond_start(auth, Write, MangleArg),
+ dbg_ssh_auth().
+
dbg_ssh_messages() ->
dbg:tp(ssh_message,encode,1, x),
@@ -61,80 +80,131 @@ dbg_ssh_messages() ->
dbg:tp(ssh_transport,handle_hello_version,1, x),
dbg:tpl(ssh_connection_handler,ext_info,2, x).
+dbg_ssh_auth() ->
+ dbg:tp(ssh_transport,hello_version_msg,1, x),
+ dbg:tp(ssh_transport,handle_hello_version,1, x),
+ dbg:tp(ssh_message,encode,1, x),
+ dbg:tpl(ssh_transport,select_algorithm,4, x),
+ dbg:tpl(ssh_connection_handler,ext_info,2, x),
+ lists:foreach(fun(F) -> dbg:tp(ssh_auth, F, x) end,
+ [publickey_msg, password_msg, keyboard_interactive_msg]).
+
%%%----------------------------------------------------------------
stop() ->
dbg:stop().
%%%================================================================
-msg_formater({trace_ts,Pid,call,{ssh_message,encode,[Msg]},TS}, D) ->
+cond_start(Type, Write, MangleArg) ->
+ try
+ dbg:start(),
+ setup_tracer(Type, Write, MangleArg),
+ dbg:p(new,[c,timestamp])
+ catch
+ _:_ -> ok
+ end.
+
+
+msg_formater(msg, {trace_ts,Pid,call,{ssh_message,encode,[Msg]},TS}, D) ->
fmt("~n~s SEND ~p ~s~n", [ts(TS),Pid,wr_record(shrink_bin(Msg))], D);
-msg_formater({trace_ts,_Pid,return_from,{ssh_message,encode,1},_Res,_TS}, D) ->
+msg_formater(msg, {trace_ts,_Pid,return_from,{ssh_message,encode,1},_Res,_TS}, D) ->
D;
-msg_formater({trace_ts,_Pid,call,{ssh_message,decode,_},_TS}, D) ->
+msg_formater(msg, {trace_ts,_Pid,call,{ssh_message,decode,_},_TS}, D) ->
D;
-msg_formater({trace_ts,Pid,return_from,{ssh_message,decode,1},Msg,TS}, D) ->
+msg_formater(msg, {trace_ts,Pid,return_from,{ssh_message,decode,1},Msg,TS}, D) ->
fmt("~n~s ~p RECV ~s~n", [ts(TS),Pid,wr_record(shrink_bin(Msg))], D);
+
+msg_formater(auth, {trace_ts,Pid,return_from,{ssh_message,decode,1},#ssh_msg_userauth_failure{authentications=As},TS}, D) ->
+ fmt("~n~s ~p Client login FAILURE. Try ~s~n", [ts(TS),Pid,As], D);
-msg_formater({trace_ts,_Pid,call,{ssh_transport,select_algorithm,_},_TS}, D) ->
+msg_formater(auth, {trace_ts,Pid,return_from,{ssh_message,decode,1},#ssh_msg_userauth_success{},TS}, D) ->
+ fmt("~n~s ~p Client login SUCCESS~n", [ts(TS),Pid], D);
+
+
+msg_formater(_, {trace_ts,_Pid,call,{ssh_transport,select_algorithm,_},_TS}, D) ->
D;
-msg_formater({trace_ts,Pid,return_from,{ssh_transport,select_algorithm,_},{ok,Alg},TS}, D) ->
+msg_formater(_, {trace_ts,Pid,return_from,{ssh_transport,select_algorithm,_},{ok,Alg},TS}, D) ->
fmt("~n~s ~p ALGORITHMS~n~s~n", [ts(TS),Pid, wr_record(Alg)], D);
-msg_formater({trace_ts,_Pid,call,{ssh_transport,hello_version_msg,_},_TS}, D) ->
+msg_formater(_, {trace_ts,_Pid,call,{ssh_transport,hello_version_msg,_},_TS}, D) ->
D;
-msg_formater({trace_ts,Pid,return_from,{ssh_transport,hello_version_msg,1},Hello,TS}, D) ->
+msg_formater(_, {trace_ts,Pid,return_from,{ssh_transport,hello_version_msg,1},Hello,TS}, D) ->
fmt("~n~s ~p TCP SEND HELLO~n ~p~n", [ts(TS),Pid,lists:flatten(Hello)], D);
-msg_formater({trace_ts,Pid,call,{ssh_transport,handle_hello_version,[Hello]},TS}, D) ->
+msg_formater(_, {trace_ts,Pid,call,{ssh_transport,handle_hello_version,[Hello]},TS}, D) ->
fmt("~n~s ~p RECV HELLO~n ~p~n", [ts(TS),Pid,lists:flatten(Hello)], D);
-msg_formater({trace_ts,_Pid,return_from,{ssh_transport,handle_hello_version,1},_,_TS}, D) ->
+msg_formater(_, {trace_ts,_Pid,return_from,{ssh_transport,handle_hello_version,1},_,_TS}, D) ->
D;
-msg_formater({trace_ts,Pid,call,{ssh_connection_handler,ext_info,[{"server-sig-algs",_SigAlgs},State]},TS}, D) ->
+msg_formater(_, {trace_ts,Pid,call,{ssh_connection_handler,ext_info,[{"server-sig-algs",_SigAlgs},State]},TS}, D) ->
try lists:keyfind(ssh, 1, tuple_to_list(State)) of
false ->
D;
#ssh{userauth_pubkeys = PKs} ->
- fmt("~n~s ~p Client suggests ~p~n", [ts(TS),Pid,PKs], D)
+ fmt("~n~s ~p Client got suggestion to use user public key sig-algs~n ~p~n", [ts(TS),Pid,PKs], D)
catch
_:_ ->
D
end;
-msg_formater({trace_ts,Pid,return_from,{ssh_connection_handler,ext_info,2},State,TS}, D) ->
+msg_formater(_, {trace_ts,Pid,return_from,{ssh_connection_handler,ext_info,2},State,TS}, D) ->
try lists:keyfind(ssh, 1, tuple_to_list(State)) of
false ->
D;
#ssh{userauth_pubkeys = PKs} ->
- fmt("~n~s ~p Client will try public keys ~p~n", [ts(TS),Pid,PKs], D)
+ fmt("~n~s ~p Client will try user public key sig-algs~n ~p~n", [ts(TS),Pid,PKs], D)
catch
_:_ ->
D
end;
-msg_formater({trace_ts,Pid,send,{tcp,Sock,Bytes},Pid,TS}, D) ->
+msg_formater(_, {trace_ts,Pid,call,{ssh_auth,publickey_msg,[[SigAlg,#ssh{user=User}]]},TS}, D) ->
+ fmt("~n~s ~p Client will try to login user ~p with public key algorithm ~p~n", [ts(TS),Pid,User,SigAlg], D);
+msg_formater(_, {trace_ts,Pid,return_from,{ssh_auth,publickey_msg,1},{not_ok,#ssh{user=User}},TS}, D) ->
+ fmt("~s ~p User ~p can't login with that kind of public key~n", [ts(TS),Pid,User], D);
+
+msg_formater(_, {trace_ts,Pid,call,{ssh_auth,password_msg,[[#ssh{user=User}]]},TS}, D) ->
+ fmt("~n~s ~p Client will try to login user ~p with password~n", [ts(TS),Pid,User], D);
+msg_formater(_, {trace_ts,Pid,return_from,{ssh_auth,password_msg,1},{not_ok,#ssh{user=User}},TS}, D) ->
+ fmt("~s ~p User ~p can't login with password~n", [ts(TS),Pid,User], D);
+
+msg_formater(_, {trace_ts,Pid,call,{ssh_auth,keyboard_interactive_msg,[[#ssh{user=User}]]},TS}, D) ->
+ fmt("~n~s ~p Client will try to login user ~p with password~n", [ts(TS),Pid,User], D);
+msg_formater(_, {trace_ts,Pid,return_from,{ssh_auth,keyboard_interactive_msg,1},{not_ok,#ssh{user=User}},TS}, D) ->
+ fmt("~s ~p User ~p can't login with keyboard_interactive password~n", [ts(TS),Pid,User], D);
+
+msg_formater(msg, {trace_ts,Pid,send,{tcp,Sock,Bytes},Pid,TS}, D) ->
fmt("~n~s ~p TCP SEND on ~p~n ~p~n", [ts(TS),Pid,Sock, shrink_bin(Bytes)], D);
-msg_formater({trace_ts,Pid,send,{tcp,Sock,Bytes},Dest,TS}, D) ->
+msg_formater(msg, {trace_ts,Pid,send,{tcp,Sock,Bytes},Dest,TS}, D) ->
fmt("~n~s ~p TCP SEND from ~p TO ~p~n ~p~n", [ts(TS),Pid,Sock,Dest, shrink_bin(Bytes)], D);
-msg_formater({trace_ts,Pid,send,ErlangMsg,Dest,TS}, D) ->
+msg_formater(msg, {trace_ts,Pid,send,ErlangMsg,Dest,TS}, D) ->
fmt("~n~s ~p ERL MSG SEND TO ~p~n ~p~n", [ts(TS),Pid,Dest, shrink_bin(ErlangMsg)], D);
-msg_formater({trace_ts,Pid,'receive',{tcp,Sock,Bytes},TS}, D) ->
+msg_formater(msg, {trace_ts,Pid,'receive',{tcp,Sock,Bytes},TS}, D) ->
fmt("~n~s ~p TCP RECEIVE on ~p~n ~p~n", [ts(TS),Pid,Sock,shrink_bin(Bytes)], D);
-msg_formater({trace_ts,Pid,'receive',ErlangMsg,TS}, D) ->
+msg_formater(msg, {trace_ts,Pid,'receive',ErlangMsg,TS}, D) ->
fmt("~n~s ~p ERL MSG RECEIVE~n ~p~n", [ts(TS),Pid,shrink_bin(ErlangMsg)], D);
-msg_formater(M, D) ->
- fmt("~nDBG ~n~p~n", [shrink_bin(M)], D).
+%% msg_formater(_, {trace_ts,_Pid,return_from,MFA,_Ret,_TS}=M, D) ->
+%% case lists:member(MFA, [{ssh_auth,keyboard_interactive_msg,1},
+%% {ssh_auth,password_msg,1},
+%% {ssh_auth,publickey_msg,1}]) of
+%% true ->
+%% D;
+%% false ->
+%% fmt("~nDBG ~n~p~n", [shrink_bin(M)], D)
+%% end;
+
+%% msg_formater(_, M, D) ->
+%% fmt("~nDBG ~n~p~n", [shrink_bin(M)], D).
-%% msg_formater(_, D) ->
-%% D.
+msg_formater(_, _, D) ->
+ D.
fmt(Fmt, Args, D=#data{writer=Write,acc=Acc}) ->
@@ -146,9 +216,9 @@ ts({_,_,Usec}=Now) ->
ts(_) ->
"-".
%%%----------------------------------------------------------------
-setup_tracer(Write, MangleArg) ->
+setup_tracer(Type, Write, MangleArg) ->
Handler = fun(Arg, D) ->
- msg_formater(MangleArg(Arg), D)
+ msg_formater(Type, MangleArg(Arg), D)
end,
InitialData = #data{writer = Write},
{ok,_} = dbg:tracer(process, {Handler, InitialData}),
--
cgit v1.2.3
From 000961628c62b28d749a1e6a5f00616add4bb603 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 22 May 2017 17:13:16 +0200
Subject: ssh: Use undocumented ssh_dbg:ct_auth() in ssh_algorithms_SUITE
---
lib/ssh/test/ssh_algorithms_SUITE.erl | 2 ++
1 file changed, 2 insertions(+)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_algorithms_SUITE.erl b/lib/ssh/test/ssh_algorithms_SUITE.erl
index 736461624d..0f69910e40 100644
--- a/lib/ssh/test/ssh_algorithms_SUITE.erl
+++ b/lib/ssh/test/ssh_algorithms_SUITE.erl
@@ -171,6 +171,7 @@ init_per_testcase(_, {public_key,Alg}, Config) ->
Opts = pubkey_opts(Config),
case {ssh_file:user_key(Alg,Opts), ssh_file:host_key(Alg,Opts)} of
{{ok,_}, {ok,_}} ->
+ ssh_dbg:ct_auth(),
start_pubkey_daemon([proplists:get_value(pref_algs,Config)],
[{extra_daemon,true}|Config]);
{{ok,_}, _} ->
@@ -192,6 +193,7 @@ init_per_testcase(_, _, Config) ->
end_per_testcase(_TC, Config) ->
+ catch ssh_dbg:stop(),
case proplists:get_value(extra_daemon, Config, false) of
true ->
case proplists:get_value(srvr_pid,Config) of
--
cgit v1.2.3
From eaf8ca41dfa4850437ad270d3897399c9358ced0 Mon Sep 17 00:00:00 2001
From: Erlang/OTP
Date: Tue, 30 May 2017 16:15:30 +0200
Subject: Prepare release
---
lib/ssh/doc/src/notes.xml | 163 ++++++++++++++++++++++++++++++++++++++++++++++
lib/ssh/vsn.mk | 2 +-
2 files changed, 164 insertions(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index bddae00dd2..f6b6f53d33 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -30,6 +30,169 @@
notes.xml
+Ssh 4.5
+
+ Improvements and New Features
+
+ -
+
+ The internal handling of SSH options is re-written.
+
+ Previously there were no checks if a client option was
+ given to a daemon or vice versa. This is corrected now.
+ If your code has e.g. a client-only option in a call to
+ start a daemon, the call will fail.
+
+ *** POTENTIAL INCOMPATIBILITY ***
+
+ Own Id: OTP-12872
+
+ -
+
+ Modernization of key exchange algorithms. See
+ draft-ietf-curdle-ssh-kex-sha2 for a discussion.
+
+ Removed an outdated weak algorithm and added stronger
+ replacements to keep interoperability with other modern
+ ssh clients and servers. The default ordering of the
+ algorithms is also adjusted.
+
+ Retired: The nowadays unsecure key-exchange
+ diffie-hellman-group1-sha1 is not enabled by
+ default, but can be enabled with the option
+ preferred-algorithms.
+
+ Added: The new stronger key-exchange
+ diffie-hellman-group16-sha512,
+ diffie-hellman-group18-sha512 and
+ diffie-hellman-group14-sha256 are added and
+ enabled by default.
+
+ The questionable [RFC 6194] sha1-based algorithms
+ diffie-hellman-group-exchange-sha1 and
+ diffie-hellman-group14-sha1 are however still kept
+ enabled by default for compatibility with ancient clients
+ and servers that lack modern key-exchange alternatives.
+ When the draft-ietf-curdle-ssh-kex-sha2 becomes an rfc,
+ those sha1-based algorithms and
+ diffie-hellman-group1-sha1 will be deprecated by
+ IETF. They might then be removed from the default list in
+ Erlang/OTP.
+
+ *** POTENTIAL INCOMPATIBILITY ***
+
+ Own Id: OTP-14110
+
+ -
+
+ Modernized internal representation of sftp by use of
+ maps.
+
+ Own Id: OTP-14117
+
+ -
+
+ The Extension Negotiation Mechanism and the extension
+ server-sig-algs in
+ draft-ietf-curdle-ssh-ext-info-05 are implemented.
+
+ The related draft-ietf-curdle-rsa-sha2-05 is implemented
+ and introduces the signature algorithms
+ rsa-sha2-256 and rsa-sha2-512.
+
+ Own Id: OTP-14193
+
+ -
+
+ The functions ssh:connect, ssh:shell and
+ ssh:start_channel now accept an IP-tuple as Host
+ destination argument.
+
+ Own Id: OTP-14243
+
+ -
+
+ The function ssh:daemon_info/1 now returns Host
+ and Profile as well as the Port info in the property
+ list.
+
+ Own Id: OTP-14259
+
+ -
+
+ Removed the option public_key_alg which was
+ deprecated in 18.2. Use pref_public_key_algs
+ instead.
+
+ *** POTENTIAL INCOMPATIBILITY ***
+
+ Own Id: OTP-14263
+
+ -
+
+ The SSH application is refactored regarding daemon
+ starting. The resolution of contradicting Host
+ argument and ip option were not described. There
+ were also strange corner cases when the 'any'
+ value was used in Host argument or ip
+ option. This is (hopefully) resolved now, but it may
+ cause incompatibilities for code using both Host
+ and the ip option. The value 'loopback' has been
+ added for a correct way of naming those addresses.
+
+ *** POTENTIAL INCOMPATIBILITY ***
+
+ Own Id: OTP-14264
+
+ -
+
+ The supervisor code is refactored. The naming of
+ listening IP-Port-Profile triples are slightly changed to
+ improve consistency in strange corner cases as resolved
+ by OTP-14264
+
+ Own Id: OTP-14267 Aux Id: OTP-14266
+
+ -
+
+ The idle_time option can now be used in daemons.
+
+ Own Id: OTP-14312
+
+ -
+
+ Added test cases for IETF-CURDLE Extension Negotiation
+ (ext-info)
+
+ Own Id: OTP-14361
+
+ -
+
+ Testcases for IETF-CURDLE extension
+ server-sig-algs including rsa-sha2-*
+
+ Own Id: OTP-14362 Aux Id: OTP-14361
+
+ -
+
+ The option auth_methods can now also be used in
+ clients to select which authentication options that are
+ used and in which order.
+
+ Own Id: OTP-14399
+
+ -
+
+ Checks that a ECDSA public key (ecdsa-sha2-nistp*)
+ stored in a file has the correct size.
+
+ Own Id: OTP-14410
+
+
+
+
+
+
Ssh 4.4.2
Fixed Bugs and Malfunctions
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index 48332d2e5a..7208baca6e 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,5 +1,5 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 4.4.2
+SSH_VSN = 4.5
APP_VSN = "ssh-$(SSH_VSN)"
--
cgit v1.2.3
From 32275a2fc0b86d1f1b124706afc80f3ff92216eb Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 31 May 2017 16:21:00 +0200
Subject: Revert "Prepare release"
This reverts commit eaf8ca41dfa4850437ad270d3897399c9358ced0.
---
lib/ssh/doc/src/notes.xml | 163 ----------------------------------------------
lib/ssh/vsn.mk | 2 +-
2 files changed, 1 insertion(+), 164 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index f6b6f53d33..bddae00dd2 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -30,169 +30,6 @@
notes.xml
-Ssh 4.5
-
- Improvements and New Features
-
- -
-
- The internal handling of SSH options is re-written.
-
- Previously there were no checks if a client option was
- given to a daemon or vice versa. This is corrected now.
- If your code has e.g. a client-only option in a call to
- start a daemon, the call will fail.
-
- *** POTENTIAL INCOMPATIBILITY ***
-
- Own Id: OTP-12872
-
- -
-
- Modernization of key exchange algorithms. See
- draft-ietf-curdle-ssh-kex-sha2 for a discussion.
-
- Removed an outdated weak algorithm and added stronger
- replacements to keep interoperability with other modern
- ssh clients and servers. The default ordering of the
- algorithms is also adjusted.
-
- Retired: The nowadays unsecure key-exchange
- diffie-hellman-group1-sha1 is not enabled by
- default, but can be enabled with the option
- preferred-algorithms.
-
- Added: The new stronger key-exchange
- diffie-hellman-group16-sha512,
- diffie-hellman-group18-sha512 and
- diffie-hellman-group14-sha256 are added and
- enabled by default.
-
- The questionable [RFC 6194] sha1-based algorithms
- diffie-hellman-group-exchange-sha1 and
- diffie-hellman-group14-sha1 are however still kept
- enabled by default for compatibility with ancient clients
- and servers that lack modern key-exchange alternatives.
- When the draft-ietf-curdle-ssh-kex-sha2 becomes an rfc,
- those sha1-based algorithms and
- diffie-hellman-group1-sha1 will be deprecated by
- IETF. They might then be removed from the default list in
- Erlang/OTP.
-
- *** POTENTIAL INCOMPATIBILITY ***
-
- Own Id: OTP-14110
-
- -
-
- Modernized internal representation of sftp by use of
- maps.
-
- Own Id: OTP-14117
-
- -
-
- The Extension Negotiation Mechanism and the extension
- server-sig-algs in
- draft-ietf-curdle-ssh-ext-info-05 are implemented.
-
- The related draft-ietf-curdle-rsa-sha2-05 is implemented
- and introduces the signature algorithms
- rsa-sha2-256 and rsa-sha2-512.
-
- Own Id: OTP-14193
-
- -
-
- The functions ssh:connect, ssh:shell and
- ssh:start_channel now accept an IP-tuple as Host
- destination argument.
-
- Own Id: OTP-14243
-
- -
-
- The function ssh:daemon_info/1 now returns Host
- and Profile as well as the Port info in the property
- list.
-
- Own Id: OTP-14259
-
- -
-
- Removed the option public_key_alg which was
- deprecated in 18.2. Use pref_public_key_algs
- instead.
-
- *** POTENTIAL INCOMPATIBILITY ***
-
- Own Id: OTP-14263
-
- -
-
- The SSH application is refactored regarding daemon
- starting. The resolution of contradicting Host
- argument and ip option were not described. There
- were also strange corner cases when the 'any'
- value was used in Host argument or ip
- option. This is (hopefully) resolved now, but it may
- cause incompatibilities for code using both Host
- and the ip option. The value 'loopback' has been
- added for a correct way of naming those addresses.
-
- *** POTENTIAL INCOMPATIBILITY ***
-
- Own Id: OTP-14264
-
- -
-
- The supervisor code is refactored. The naming of
- listening IP-Port-Profile triples are slightly changed to
- improve consistency in strange corner cases as resolved
- by OTP-14264
-
- Own Id: OTP-14267 Aux Id: OTP-14266
-
- -
-
- The idle_time option can now be used in daemons.
-
- Own Id: OTP-14312
-
- -
-
- Added test cases for IETF-CURDLE Extension Negotiation
- (ext-info)
-
- Own Id: OTP-14361
-
- -
-
- Testcases for IETF-CURDLE extension
- server-sig-algs including rsa-sha2-*
-
- Own Id: OTP-14362 Aux Id: OTP-14361
-
- -
-
- The option auth_methods can now also be used in
- clients to select which authentication options that are
- used and in which order.
-
- Own Id: OTP-14399
-
- -
-
- Checks that a ECDSA public key (ecdsa-sha2-nistp*)
- stored in a file has the correct size.
-
- Own Id: OTP-14410
-
-
-
-
-
-
Ssh 4.4.2
Fixed Bugs and Malfunctions
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index 7208baca6e..48332d2e5a 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,5 +1,5 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 4.5
+SSH_VSN = 4.4.2
APP_VSN = "ssh-$(SSH_VSN)"
--
cgit v1.2.3
From 8611454d37da15627a79507ca62bf25843e62493 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Tue, 23 May 2017 13:46:43 +0200
Subject: ssh: Improve 'server-sig-algs' handling in client
---
lib/ssh/src/ssh_auth.erl | 59 +++++++++++++----------
lib/ssh/src/ssh_connection_handler.erl | 88 +++++++++++++++++++++++-----------
2 files changed, 95 insertions(+), 52 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl
index 6cf659f830..ac64a7bf14 100644
--- a/lib/ssh/src/ssh_auth.erl
+++ b/lib/ssh/src/ssh_auth.erl
@@ -28,7 +28,8 @@
-include("ssh_auth.hrl").
-include("ssh_transport.hrl").
--export([publickey_msg/1, password_msg/1, keyboard_interactive_msg/1,
+-export([get_public_key/2,
+ publickey_msg/1, password_msg/1, keyboard_interactive_msg/1,
service_request_msg/1, init_userauth_request_msg/1,
userauth_request_msg/1, handle_userauth_request/3,
handle_userauth_info_request/2, handle_userauth_info_response/2
@@ -136,41 +137,49 @@ keyboard_interactive_msg([#ssh{user = User,
Ssh)
end.
-publickey_msg([SigAlg, #ssh{user = User,
- session_id = SessionId,
- service = Service,
- opts = Opts} = Ssh]) ->
- Hash = ssh_transport:sha(SigAlg),
+
+get_public_key(SigAlg, #ssh{opts = Opts}) ->
KeyAlg = key_alg(SigAlg),
{KeyCb,KeyCbOpts} = ?GET_OPT(key_cb, Opts),
UserOpts = ?GET_OPT(user_options, Opts),
case KeyCb:user_key(KeyAlg, [{key_cb_private,KeyCbOpts}|UserOpts]) of
- {ok, PrivKey} ->
- SigAlgStr = atom_to_list(SigAlg),
+ {ok, PrivKey} ->
try
Key = ssh_transport:extract_public_key(PrivKey),
public_key:ssh_encode(Key, ssh2_pubkey)
of
- PubKeyBlob ->
- SigData = build_sig_data(SessionId, User, Service,
- PubKeyBlob, SigAlgStr),
- Sig = ssh_transport:sign(SigData, Hash, PrivKey),
- SigBlob = list_to_binary([?string(SigAlgStr),
- ?binary(Sig)]),
- ssh_transport:ssh_packet(
- #ssh_msg_userauth_request{user = User,
- service = Service,
- method = "publickey",
- data = [?TRUE,
- ?string(SigAlgStr),
- ?binary(PubKeyBlob),
- ?binary(SigBlob)]},
- Ssh)
+ PubKeyBlob -> {ok,{PrivKey,PubKeyBlob}}
catch
_:_ ->
- {not_ok, Ssh}
+ not_ok
end;
- _Error ->
+ _Error ->
+ not_ok
+ end.
+
+
+publickey_msg([SigAlg, #ssh{user = User,
+ session_id = SessionId,
+ service = Service} = Ssh]) ->
+ case get_public_key(SigAlg, Ssh) of
+ {ok, {PrivKey,PubKeyBlob}} ->
+ SigAlgStr = atom_to_list(SigAlg),
+ SigData = build_sig_data(SessionId, User, Service,
+ PubKeyBlob, SigAlgStr),
+ Hash = ssh_transport:sha(SigAlg),
+ Sig = ssh_transport:sign(SigData, Hash, PrivKey),
+ SigBlob = list_to_binary([?string(SigAlgStr),
+ ?binary(Sig)]),
+ ssh_transport:ssh_packet(
+ #ssh_msg_userauth_request{user = User,
+ service = Service,
+ method = "publickey",
+ data = [?TRUE,
+ ?string(SigAlgStr),
+ ?binary(PubKeyBlob),
+ ?binary(SigBlob)]},
+ Ssh);
+ _ ->
{not_ok, Ssh}
end.
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index f1ce337947..4c6aff5c24 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -453,16 +453,20 @@ init_ssh_record(Role, _Socket, PeerAddr, Opts) ->
PeerName0 when is_list(PeerName0) ->
PeerName0
end,
- S0#ssh{c_vsn = Vsn,
- c_version = Version,
- io_cb = case ?GET_OPT(user_interaction, Opts) of
- true -> ssh_io;
- false -> ssh_no_io
- end,
- userauth_pubkeys = ?GET_OPT(pref_public_key_algs, Opts),
- userauth_quiet_mode = ?GET_OPT(quiet_mode, Opts),
- peer = {PeerName, PeerAddr}
- };
+ S1 =
+ S0#ssh{c_vsn = Vsn,
+ c_version = Version,
+ io_cb = case ?GET_OPT(user_interaction, Opts) of
+ true -> ssh_io;
+ false -> ssh_no_io
+ end,
+ userauth_quiet_mode = ?GET_OPT(quiet_mode, Opts),
+ peer = {PeerName, PeerAddr}
+ },
+ S1#ssh{userauth_pubkeys = [K || K <- ?GET_OPT(pref_public_key_algs, Opts),
+ is_usable_user_pubkey(K, S1)
+ ]
+ };
server ->
S0#ssh{s_vsn = Vsn,
@@ -1700,28 +1704,58 @@ handle_ssh_msg_ext_info(#ssh_msg_ext_info{data=Data}, D0) ->
lists:foldl(fun ext_info/2, D0, Data).
-ext_info({"server-sig-algs",SigAlgs}, D0 = #data{ssh_params=#ssh{role=client,
- userauth_pubkeys=ClientSigAlgs}=Ssh0}) ->
- %% Make strings to eliminate risk of beeing bombed with odd strings that fills the atom table:
- SupportedAlgs = lists:map(fun erlang:atom_to_list/1, ssh_transport:supported_algorithms(public_key)),
- ServerSigAlgs = [list_to_atom(SigAlg) || SigAlg <- string:tokens(SigAlgs,","),
- %% length of SigAlg is implicitly checked by the comparison
- %% in member/2:
- lists:member(SigAlg, SupportedAlgs)
- ],
- CommonAlgs = [Alg || Alg <- ServerSigAlgs,
- lists:member(Alg, ClientSigAlgs)],
- SelectedAlgs =
- case CommonAlgs of
- [] -> ClientSigAlgs; % server-sig-algs value is just an advice
- _ -> CommonAlgs
- end,
- D0#data{ssh_params = Ssh0#ssh{userauth_pubkeys = SelectedAlgs} };
+ext_info({"server-sig-algs",SigAlgsStr},
+ D0 = #data{ssh_params=#ssh{role=client,
+ userauth_pubkeys=ClientSigAlgs}=Ssh0}) ->
+ %% ClientSigAlgs are the pub_key algortithms that:
+ %% 1) is usable, that is, the user has such a public key and
+ %% 2) is either the default list or set by the caller
+ %% with the client option 'pref_public_key_algs'
+ %%
+ %% The list is already checked for duplicates.
+
+ SigAlgs = [A || Astr <- string:tokens(SigAlgsStr, ","),
+ A <- try [list_to_existing_atom(Astr)]
+ %% list_to_existing_atom will fail for unknown algorithms
+ catch _:_ -> []
+ end],
+
+ CommonAlgs = [A || A <- SigAlgs,
+ lists:member(A, ClientSigAlgs)],
+
+ %% Re-arrange the client supported public-key algorithms so that the server
+ %% preferred ones are tried first.
+ %% Trying algorithms not mentioned by the server is ok, since the server can't know
+ %% if the client supports 'server-sig-algs' or not.
+
+ D0#data{
+ ssh_params =
+ Ssh0#ssh{
+ userauth_pubkeys =
+ CommonAlgs ++ (ClientSigAlgs -- CommonAlgs)
+ }};
+
+ %% If there are algorithms common to the client and the server, use them.
+ %% Otherwise try with ones that the client supports. The server-sig-alg
+ %% list is a suggestion, not an order.
+ %% case CommonAlgs of
+ %% [_|_] ->
+ %% D0#data{ssh_params = Ssh0#ssh{userauth_pubkeys = CommonAlgs}};
+ %% [] ->
+ %% D0
+ %% end;
ext_info(_, D0) ->
%% Not implemented
D0.
+%%%----------------------------------------------------------------
+is_usable_user_pubkey(A, Ssh) ->
+ case ssh_auth:get_public_key(A, Ssh) of
+ {ok,_} -> true;
+ _ -> false
+ end.
+
%%%----------------------------------------------------------------
handle_request(ChannelPid, ChannelId, Type, Data, WantReply, From, D) ->
case ssh_channel:cache_lookup(cache(D), ChannelId) of
--
cgit v1.2.3
From 9c4d91f4726ff84df8877fc6c73edcd116775a52 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 24 May 2017 15:04:43 +0200
Subject: ssh: ssh_options checks 'pref_public_key_algs' for dubblets
---
lib/ssh/src/ssh_options.erl | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_options.erl b/lib/ssh/src/ssh_options.erl
index aebb5a7062..7eeed70739 100644
--- a/lib/ssh/src/ssh_options.erl
+++ b/lib/ssh/src/ssh_options.erl
@@ -674,7 +674,11 @@ check_pref_public_key_algs(V) ->
PKs = ssh_transport:supported_algorithms(public_key),
CHK = fun(A, Ack) ->
case lists:member(A, PKs) of
- true -> [A|Ack];
+ true ->
+ case lists:member(A,Ack) of
+ false -> [A|Ack];
+ true -> Ack % Remove duplicates
+ end;
false -> error_in_check(A, "Not supported public key")
end
end,
--
cgit v1.2.3
From b4327e257147a64fc088d1448132f5794bad879f Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 24 May 2017 15:11:03 +0200
Subject: ssh: Change printouts for ssh_dbg:auth()
This reverts commit 4ee80fd8738393bf581e0393416befda1ca621b6.
---
lib/ssh/src/ssh_dbg.erl | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_dbg.erl b/lib/ssh/src/ssh_dbg.erl
index 003b3856e6..d5d4ab04c3 100644
--- a/lib/ssh/src/ssh_dbg.erl
+++ b/lib/ssh/src/ssh_dbg.erl
@@ -136,12 +136,13 @@ msg_formater(_, {trace_ts,Pid,call,{ssh_transport,handle_hello_version,[Hello]},
msg_formater(_, {trace_ts,_Pid,return_from,{ssh_transport,handle_hello_version,1},_,_TS}, D) ->
D;
-msg_formater(_, {trace_ts,Pid,call,{ssh_connection_handler,ext_info,[{"server-sig-algs",_SigAlgs},State]},TS}, D) ->
+msg_formater(_, {trace_ts,Pid,call,{ssh_connection_handler,ext_info,[{"server-sig-algs",SigAlgs},State]},TS}, D) ->
try lists:keyfind(ssh, 1, tuple_to_list(State)) of
false ->
D;
#ssh{userauth_pubkeys = PKs} ->
- fmt("~n~s ~p Client got suggestion to use user public key sig-algs~n ~p~n", [ts(TS),Pid,PKs], D)
+ fmt("~n~s ~p Client got suggestion to use user public key sig-algs~n ~p~n and can use~n ~p~n",
+ [ts(TS),Pid,string:tokens(SigAlgs,","),PKs], D)
catch
_:_ ->
D
--
cgit v1.2.3
From af14e88eb3dcb482dea8ca4e5fa5843b9fe9ddec Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Tue, 23 May 2017 15:31:53 +0200
Subject: ssh: Use option 'pref_public_key_algs' in ssh_algorithms_SUITE
---
lib/ssh/test/ssh_algorithms_SUITE.erl | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_algorithms_SUITE.erl b/lib/ssh/test/ssh_algorithms_SUITE.erl
index 0f69910e40..293c72af65 100644
--- a/lib/ssh/test/ssh_algorithms_SUITE.erl
+++ b/lib/ssh/test/ssh_algorithms_SUITE.erl
@@ -171,7 +171,6 @@ init_per_testcase(_, {public_key,Alg}, Config) ->
Opts = pubkey_opts(Config),
case {ssh_file:user_key(Alg,Opts), ssh_file:host_key(Alg,Opts)} of
{{ok,_}, {ok,_}} ->
- ssh_dbg:ct_auth(),
start_pubkey_daemon([proplists:get_value(pref_algs,Config)],
[{extra_daemon,true}|Config]);
{{ok,_}, _} ->
@@ -193,7 +192,6 @@ init_per_testcase(_, _, Config) ->
end_per_testcase(_TC, Config) ->
- catch ssh_dbg:stop(),
case proplists:get_value(extra_daemon, Config, false) of
true ->
case proplists:get_value(srvr_pid,Config) of
@@ -304,9 +302,19 @@ sshc_simple_exec_os_cmd(Config) ->
%%--------------------------------------------------------------------
%% Connect to the ssh server of the OS
sshd_simple_exec(Config) ->
+ case ?config(tc_group_path,Config) of
+ [[{name,public_key}]] -> ssh_dbg:ct_auth();
+ _ -> ok
+ end,
+ ClientPubKeyOpts =
+ case proplists:get_value(tag_alg,Config) of
+ {public_key,Alg} -> [{pref_public_key_algs,[Alg]}];
+ _ -> []
+ end,
ConnectionRef = ssh_test_lib:connect(22, [{silently_accept_hosts, true},
proplists:get_value(pref_algs,Config),
- {user_interaction, false}]),
+ {user_interaction, false}
+ | ClientPubKeyOpts]),
{ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity),
success = ssh_connection:exec(ConnectionRef, ChannelId0,
"echo testing", infinity),
@@ -320,6 +328,7 @@ sshd_simple_exec(Config) ->
ssh_test_lib:receive_exec_result(Data0,
ConnectionRef, ChannelId0);
Other0 ->
+ catch ssh_dbg:stop(),
ct:fail(Other0)
end,
@@ -336,8 +345,10 @@ sshd_simple_exec(Config) ->
ssh_test_lib:receive_exec_result(Data1,
ConnectionRef, ChannelId1);
Other1 ->
+ catch ssh_dbg:stop(),
ct:fail(Other1)
end,
+ catch ssh_dbg:stop(),
ssh:close(ConnectionRef).
--
cgit v1.2.3
From 0780ac168b13e6d5e89a3cd97b6e3586e17c427b Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Mon, 29 May 2017 13:32:37 +0200
Subject: ssh: Introduce test case simple_connect in ssh_algorithms_SUITE
In the test group public_key we need to control both the host key
and the user key. This new test case is aimed at faciliate the
user public key testing.
---
lib/ssh/test/ssh_algorithms_SUITE.erl | 74 +++++++++++++++++++++++++----------
1 file changed, 54 insertions(+), 20 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_algorithms_SUITE.erl b/lib/ssh/test/ssh_algorithms_SUITE.erl
index 293c72af65..98964a2c8a 100644
--- a/lib/ssh/test/ssh_algorithms_SUITE.erl
+++ b/lib/ssh/test/ssh_algorithms_SUITE.erl
@@ -131,9 +131,14 @@ init_per_group(public_key=Tag, Alg, Config) ->
ct:log("Init tests for public_key ~p",[Alg]),
PrefAlgs = {preferred_algorithms,[{Tag,[Alg]}]},
%% Daemon started later in init_per_testcase
- [{pref_algs,PrefAlgs},
- {tag_alg,{Tag,Alg}}
- | Config];
+ try
+ setup_pubkey(Alg,
+ [{pref_algs,PrefAlgs},
+ {tag_alg,{Tag,Alg}}
+ | Config])
+ catch
+ _:_ -> {skip, io_lib:format("Unsupported: ~p",[Alg])}
+ end;
init_per_group(Tag, Alg, Config) ->
PA =
@@ -167,17 +172,24 @@ init_per_testcase(TC, Config) ->
init_per_testcase(TC, proplists:get_value(tag_alg,Config), Config).
-init_per_testcase(_, {public_key,Alg}, Config) ->
- Opts = pubkey_opts(Config),
+init_per_testcase(TC, {public_key,Alg}, Config) ->
+ ExtraOpts = case TC of
+ simple_connect ->
+ [{user_dir, proplists:get_value(priv_dir,Config)}];
+ _ ->
+ []
+ end,
+ Opts = pubkey_opts(Config) ++ ExtraOpts,
case {ssh_file:user_key(Alg,Opts), ssh_file:host_key(Alg,Opts)} of
{{ok,_}, {ok,_}} ->
- start_pubkey_daemon([proplists:get_value(pref_algs,Config)],
+ start_pubkey_daemon([proplists:get_value(pref_algs,Config)
+ | ExtraOpts],
[{extra_daemon,true}|Config]);
- {{ok,_}, _} ->
- {skip, "No host key"};
+ {{ok,_}, {error,Err}} ->
+ {skip, io_lib:format("No host key: ~p",[Err])};
- {_, {ok,_}} ->
- {skip, "No user key"};
+ {{error,Err}, {ok,_}} ->
+ {skip, io_lib:format("No user key: ~p",[Err])};
_ ->
{skip, "Neither host nor user key"}
@@ -220,6 +232,19 @@ simple_exec(Config) ->
{Host,Port} = proplists:get_value(srvr_addr, Config),
ssh_test_lib:std_simple_exec(Host, Port, Config).
+%%--------------------------------------------------------------------
+%% A simple exec call
+simple_connect(Config) ->
+ {Host,Port} = proplists:get_value(srvr_addr, Config),
+ Opts =
+ case proplists:get_value(tag_alg, Config) of
+ {public_key,Alg} -> [{pref_public_key_algs,[Alg]}];
+ _ -> []
+ end,
+ ConnectionRef = ssh_test_lib:std_connect(Config, Host, Port, Opts),
+ ct:log("~p:~p connected! ~p",[?MODULE,?LINE,ConnectionRef]),
+ ssh:close(ConnectionRef).
+
%%--------------------------------------------------------------------
%% Testing if no group matches
simple_exec_groups_no_match_too_small(Config) ->
@@ -302,10 +327,6 @@ sshc_simple_exec_os_cmd(Config) ->
%%--------------------------------------------------------------------
%% Connect to the ssh server of the OS
sshd_simple_exec(Config) ->
- case ?config(tc_group_path,Config) of
- [[{name,public_key}]] -> ssh_dbg:ct_auth();
- _ -> ok
- end,
ClientPubKeyOpts =
case proplists:get_value(tag_alg,Config) of
{public_key,Alg} -> [{pref_public_key_algs,[Alg]}];
@@ -328,7 +349,6 @@ sshd_simple_exec(Config) ->
ssh_test_lib:receive_exec_result(Data0,
ConnectionRef, ChannelId0);
Other0 ->
- catch ssh_dbg:stop(),
ct:fail(Other0)
end,
@@ -345,10 +365,8 @@ sshd_simple_exec(Config) ->
ssh_test_lib:receive_exec_result(Data1,
ConnectionRef, ChannelId1);
Other1 ->
- catch ssh_dbg:stop(),
ct:fail(Other1)
end,
- catch ssh_dbg:stop(),
ssh:close(ConnectionRef).
@@ -374,8 +392,8 @@ split(Alg) -> ssh_test_lib:to_atoms(string:tokens(atom_to_list(Alg), " + ")).
specific_test_cases(Tag, Alg, SshcAlgos, SshdAlgos, TypeSSH) ->
case Tag of
- public_key -> [];
- _ -> [simple_exec, simple_sftp]
+ public_key -> [simple_connect];
+ _ -> [simple_connect, simple_exec, simple_sftp]
end
++ case supports(Tag, Alg, SshcAlgos) of
true when TypeSSH == openSSH ->
@@ -450,10 +468,26 @@ setup_pubkey(Config) ->
Keys =
[ssh_test_lib:setup_dsa(DataDir, UserDir),
ssh_test_lib:setup_rsa(DataDir, UserDir),
- ssh_test_lib:setup_ecdsa("256", DataDir, UserDir)],
+ ssh_test_lib:setup_ecdsa("256", DataDir, UserDir)
+ ],
ssh_test_lib:write_auth_keys(Keys, UserDir), % 'authorized_keys' shall contain ALL pub keys
Config.
+setup_pubkey(Alg, Config) ->
+ DataDir = proplists:get_value(data_dir, Config),
+ UserDir = proplists:get_value(priv_dir, Config),
+ ct:log("Setup keys for ~p",[Alg]),
+ case Alg of
+ 'ssh-dss' -> ssh_test_lib:setup_dsa(DataDir, UserDir);
+ 'ssh-rsa' -> ssh_test_lib:setup_rsa(DataDir, UserDir);
+ 'rsa-sha2-256' -> ssh_test_lib:setup_rsa(DataDir, UserDir);
+ 'rsa-sha2-512' -> ssh_test_lib:setup_rsa(DataDir, UserDir);
+ 'ecdsa-sha2-nistp256' -> ssh_test_lib:setup_ecdsa("256", DataDir, UserDir);
+ 'ecdsa-sha2-nistp384' -> ssh_test_lib:setup_ecdsa("384", DataDir, UserDir);
+ 'ecdsa-sha2-nistp521' -> ssh_test_lib:setup_ecdsa("521", DataDir, UserDir)
+ end,
+ Config.
+
simple_exec_group(I, Config) when is_integer(I) ->
simple_exec_group({I,I,I}, Config);
--
cgit v1.2.3
From 32d449adadc04c7d664c99bd2e99393708d71930 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Tue, 30 May 2017 17:13:26 +0200
Subject: ssh: more keys for testing
---
lib/ssh/test/ssh_algorithms_SUITE_data/id_ecdsa384 | 6 ++++++
lib/ssh/test/ssh_algorithms_SUITE_data/id_ecdsa384.pub | 1 +
lib/ssh/test/ssh_algorithms_SUITE_data/id_ecdsa521 | 7 +++++++
lib/ssh/test/ssh_algorithms_SUITE_data/id_ecdsa521.pub | 1 +
lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ecdsa_key384 | 6 ++++++
lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ecdsa_key384.pub | 1 +
lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ecdsa_key521 | 7 +++++++
lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ecdsa_key521.pub | 1 +
8 files changed, 30 insertions(+)
create mode 100644 lib/ssh/test/ssh_algorithms_SUITE_data/id_ecdsa384
create mode 100644 lib/ssh/test/ssh_algorithms_SUITE_data/id_ecdsa384.pub
create mode 100644 lib/ssh/test/ssh_algorithms_SUITE_data/id_ecdsa521
create mode 100644 lib/ssh/test/ssh_algorithms_SUITE_data/id_ecdsa521.pub
create mode 100644 lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ecdsa_key384
create mode 100644 lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ecdsa_key384.pub
create mode 100644 lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ecdsa_key521
create mode 100644 lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ecdsa_key521.pub
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_algorithms_SUITE_data/id_ecdsa384 b/lib/ssh/test/ssh_algorithms_SUITE_data/id_ecdsa384
new file mode 100644
index 0000000000..4c39e916e9
--- /dev/null
+++ b/lib/ssh/test/ssh_algorithms_SUITE_data/id_ecdsa384
@@ -0,0 +1,6 @@
+-----BEGIN EC PRIVATE KEY-----
+MIGkAgEBBDAughXu55DNyhxe6x+MNjv4oZKWUDh7bhi4CqjvxhCp9KMpsybltcq+
+lsuKTarzTdKgBwYFK4EEACKhZANiAASu1vvDL0SQoXGtzlltaPHPyDfEVMG/sKLA
+pqv8vfRN5Wcs7+yaRKw92nYEKGXfZLbhVX8ArFPMtXPWHcRHCntvL1Acn2kJQ8Gc
+7iL4NAr8JhTIUBv4YMhHDa9Pv/CH2zk=
+-----END EC PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_algorithms_SUITE_data/id_ecdsa384.pub b/lib/ssh/test/ssh_algorithms_SUITE_data/id_ecdsa384.pub
new file mode 100644
index 0000000000..caa9604c84
--- /dev/null
+++ b/lib/ssh/test/ssh_algorithms_SUITE_data/id_ecdsa384.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBK7W+8MvRJChca3OWW1o8c/IN8RUwb+wosCmq/y99E3lZyzv7JpErD3adgQoZd9ktuFVfwCsU8y1c9YdxEcKe28vUByfaQlDwZzuIvg0CvwmFMhQG/hgyEcNr0+/8IfbOQ== uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_algorithms_SUITE_data/id_ecdsa521 b/lib/ssh/test/ssh_algorithms_SUITE_data/id_ecdsa521
new file mode 100644
index 0000000000..1e16fcbd57
--- /dev/null
+++ b/lib/ssh/test/ssh_algorithms_SUITE_data/id_ecdsa521
@@ -0,0 +1,7 @@
+-----BEGIN EC PRIVATE KEY-----
+MIHbAgEBBEEWXGoVLiNwQVUwAGZWxOu6uxtU8ntxyZNlcWU4Z8pze9kq3eK7a9XH
+l/wxL75Vk1QdOiR/rE3s/L/zOuChp44o1aAHBgUrgQQAI6GBiQOBhgAEAfCrtwjO
+kQYKr4/F3uanS7Eby1+SYDdRl1ABuDFhNC3CivVBFt4CnRneV+Mf0viDAxD+HEpd
+/GaE2CdsFoVpglN5AVG+fEePY2PiCLHmjc4/pBuR+tWhErzcWAd0KLBCBuc4OAvl
+aLLYV1NAJI6COnnfGTCVvYYE5nKMG4LLX0zaWtWl
+-----END EC PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_algorithms_SUITE_data/id_ecdsa521.pub b/lib/ssh/test/ssh_algorithms_SUITE_data/id_ecdsa521.pub
new file mode 100644
index 0000000000..069683eba7
--- /dev/null
+++ b/lib/ssh/test/ssh_algorithms_SUITE_data/id_ecdsa521.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAHwq7cIzpEGCq+Pxd7mp0uxG8tfkmA3UZdQAbgxYTQtwor1QRbeAp0Z3lfjH9L4gwMQ/hxKXfxmhNgnbBaFaYJTeQFRvnxHj2Nj4gix5o3OP6QbkfrVoRK83FgHdCiwQgbnODgL5Wiy2FdTQCSOgjp53xkwlb2GBOZyjBuCy19M2lrVpQ== uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ecdsa_key384 b/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ecdsa_key384
new file mode 100644
index 0000000000..5835bcd74c
--- /dev/null
+++ b/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ecdsa_key384
@@ -0,0 +1,6 @@
+-----BEGIN EC PRIVATE KEY-----
+MIGkAgEBBDB+l0+SMLYgQ3ZRzg2Pn5u+1ZwKbEnJzXsTKTJM9QSJbKkbA7uCnjdS
+CvEW+66CoHqgBwYFK4EEACKhZANiAAT6awCCIrcCr9H4wq0bJ/rQou3tpLHyyf33
+c8D6FPn48/hNqinpx7b0le/0D+Rrhdl9edIplAf6oki7yoFFGl4yuzWtv7rag9jB
+vv6w1508ChOmyQ094rFt/xj4KVBhEHI=
+-----END EC PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ecdsa_key384.pub b/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ecdsa_key384.pub
new file mode 100644
index 0000000000..714fc4eb89
--- /dev/null
+++ b/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ecdsa_key384.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBPprAIIitwKv0fjCrRsn+tCi7e2ksfLJ/fdzwPoU+fjz+E2qKenHtvSV7/QP5GuF2X150imUB/qiSLvKgUUaXjK7Na2/utqD2MG+/rDXnTwKE6bJDT3isW3/GPgpUGEQcg== uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ecdsa_key521 b/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ecdsa_key521
new file mode 100644
index 0000000000..81aa8df39f
--- /dev/null
+++ b/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ecdsa_key521
@@ -0,0 +1,7 @@
+-----BEGIN EC PRIVATE KEY-----
+MIHbAgEBBEHHxgYEfDclsu5bW+pZfg+bkaqWpgEpXtuzLVm++FFPjhAPhMkurSRj
+WQ+CuI2TxgYkBbYFNjn9JqgdMF7FzaiojKAHBgUrgQQAI6GBiQOBhgAEAFTM8TKG
+xexxmfAGuyl/Tpk4wytB/OyuVfkF+Q3H1v17HLcpMacA5xUFr80+D5XnjxGttBsS
++X0uexR7QbPbhhPqADgQzFqvTsB1mUNAZnJBD6QNCZkfWwRRwFYQWSmisb43H6G3
+iUTKqiCXMXO8drKLA+Wi+L7VyfoI1CvatBBlDHbV
+-----END EC PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ecdsa_key521.pub b/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ecdsa_key521.pub
new file mode 100644
index 0000000000..17b9a1d834
--- /dev/null
+++ b/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ecdsa_key521.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBABUzPEyhsXscZnwBrspf06ZOMMrQfzsrlX5BfkNx9b9exy3KTGnAOcVBa/NPg+V548RrbQbEvl9LnsUe0Gz24YT6gA4EMxar07AdZlDQGZyQQ+kDQmZH1sEUcBWEFkporG+Nx+ht4lEyqoglzFzvHayiwPlovi+1cn6CNQr2rQQZQx21Q== uabhnil@elxadlj3q32
--
cgit v1.2.3
From a17b94cc89dd14cf1027e05a0b3def68f2c1e96c Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 1 Jun 2017 13:36:24 +0200
Subject: ssh: Removed out-commented code
---
lib/ssh/src/ssh_connection_handler.erl | 10 ----------
1 file changed, 10 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 4c6aff5c24..8d3ddb09a4 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -1735,16 +1735,6 @@ ext_info({"server-sig-algs",SigAlgsStr},
CommonAlgs ++ (ClientSigAlgs -- CommonAlgs)
}};
- %% If there are algorithms common to the client and the server, use them.
- %% Otherwise try with ones that the client supports. The server-sig-alg
- %% list is a suggestion, not an order.
- %% case CommonAlgs of
- %% [_|_] ->
- %% D0#data{ssh_params = Ssh0#ssh{userauth_pubkeys = CommonAlgs}};
- %% [] ->
- %% D0
- %% end;
-
ext_info(_, D0) ->
%% Not implemented
D0.
--
cgit v1.2.3
From 8ce5d8239bc49ca72df11ca0a614dfa01fbf931c Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 1 Jun 2017 16:02:12 +0200
Subject: ssh: Restructure internal tool ssh_dbg
The need for more trace patterns requires a somewhat different structure.
It was previoiusly a bit difficult to use in e.g. test suites. Now it is easier.
---
lib/ssh/src/ssh_dbg.erl | 88 ++++++++++++++++++++++++-------------------------
1 file changed, 44 insertions(+), 44 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/src/ssh_dbg.erl b/lib/ssh/src/ssh_dbg.erl
index d5d4ab04c3..3f742ad9b6 100644
--- a/lib/ssh/src/ssh_dbg.erl
+++ b/lib/ssh/src/ssh_dbg.erl
@@ -22,10 +22,8 @@
-module(ssh_dbg).
--export([messages/0, messages/1, messages/2,
- ct_messages/0,
- auth/0, auth/1, auth/2,
- ct_auth/0,
+-export([messages/0, messages/1, messages/2, messages/3,
+ auth/0, auth/1, auth/2, auth/3,
stop/0
]).
@@ -37,50 +35,52 @@
-include("ssh_connect.hrl").
-include("ssh_auth.hrl").
--record(data, {
- writer,
- acc = []}).
%%%================================================================
-messages() ->
- messages(fun(String,_D) -> io:format(String) end).
+messages() -> start(msg).
+messages(F) -> start(msg,F).
+messages(F,X) -> start(msg,F,X).
+messages(F,M,I) -> start(msg,F,M,I).
-ct_messages() ->
- messages(fun(String,_D) -> ct:log(String,[]) end).
+auth() -> start(auth).
+auth(F) -> start(auth,F).
+auth(F,X) -> start(auth,F,X).
+auth(F,M,I) -> start(auth,F,M,I).
-messages(Write) when is_function(Write,2) ->
- messages(Write, fun(X) -> X end).
-
-messages(Write, MangleArg) when is_function(Write,2),
- is_function(MangleArg,1) ->
- cond_start(msg, Write, MangleArg),
- dbg_ssh_messages(),
- dbg_ssh_auth().
+stop() -> dbg:stop().
+%%%----------------------------------------------------------------
+start(Type) -> start(Type, fun io:format/2).
-auth() ->
- auth(fun(String,_D) -> io:format(String) end).
+start(Type, F) when is_function(F,2) -> start(Type, fmt_fun(F));
+start(Type, F) when is_function(F,3) -> start(Type, F, id_fun()).
-ct_auth() ->
- auth(fun(String,_D) -> ct:log(String,[]) end).
+start(Type, WriteFun, MangleArgFun) when is_function(WriteFun, 3),
+ is_function(MangleArgFun, 1) ->
+ start(Type, WriteFun, MangleArgFun, []);
+start(Type, WriteFun, InitValue) ->
+ start(Type, WriteFun, id_fun(), InitValue).
-auth(Write) when is_function(Write,2) ->
- auth(Write, fun(X) -> X end).
+start(Type, WriteFun, MangleArgFun, InitValue) when is_function(WriteFun, 3),
+ is_function(MangleArgFun, 1) ->
+ cond_start(Type, WriteFun, MangleArgFun, InitValue),
+ dbg_ssh(Type).
-auth(Write, MangleArg) when is_function(Write,2),
- is_function(MangleArg,1) ->
- cond_start(auth, Write, MangleArg),
- dbg_ssh_auth().
+%%%----------------------------------------------------------------
+fmt_fun(F) -> fun(Fmt,Args,Data) -> F(Fmt,Args), Data end.
+id_fun() -> fun(X) -> X end.
-dbg_ssh_messages() ->
+%%%----------------------------------------------------------------
+dbg_ssh(msg) ->
+ dbg_ssh(auth),
dbg:tp(ssh_message,encode,1, x),
dbg:tp(ssh_message,decode,1, x),
dbg:tpl(ssh_transport,select_algorithm,4, x),
dbg:tp(ssh_transport,hello_version_msg,1, x),
dbg:tp(ssh_transport,handle_hello_version,1, x),
- dbg:tpl(ssh_connection_handler,ext_info,2, x).
+ dbg:tpl(ssh_connection_handler,ext_info,2, x);
-dbg_ssh_auth() ->
+dbg_ssh(auth) ->
dbg:tp(ssh_transport,hello_version_msg,1, x),
dbg:tp(ssh_transport,handle_hello_version,1, x),
dbg:tp(ssh_message,encode,1, x),
@@ -89,15 +89,11 @@ dbg_ssh_auth() ->
lists:foreach(fun(F) -> dbg:tp(ssh_auth, F, x) end,
[publickey_msg, password_msg, keyboard_interactive_msg]).
-%%%----------------------------------------------------------------
-stop() ->
- dbg:stop().
-
%%%================================================================
-cond_start(Type, Write, MangleArg) ->
+cond_start(Type, WriteFun, MangleArgFun, Init) ->
try
dbg:start(),
- setup_tracer(Type, Write, MangleArg),
+ setup_tracer(Type, WriteFun, MangleArgFun, Init),
dbg:p(new,[c,timestamp])
catch
_:_ -> ok
@@ -207,21 +203,25 @@ msg_formater(msg, {trace_ts,Pid,'receive',ErlangMsg,TS}, D) ->
msg_formater(_, _, D) ->
D.
+%%%----------------------------------------------------------------
+-record(data, {writer,
+ acc}).
-fmt(Fmt, Args, D=#data{writer=Write,acc=Acc}) ->
- D#data{acc = Write(io_lib:format(Fmt, Args), Acc)}.
+fmt(Fmt, Args, D=#data{writer=Write, acc=Acc}) ->
+ D#data{acc = Write(Fmt,Args,Acc)}.
ts({_,_,Usec}=Now) ->
{_Date,{HH,MM,SS}} = calendar:now_to_local_time(Now),
io_lib:format("~.2.0w:~.2.0w:~.2.0w.~.6.0w",[HH,MM,SS,Usec]);
ts(_) ->
"-".
-%%%----------------------------------------------------------------
-setup_tracer(Type, Write, MangleArg) ->
+
+setup_tracer(Type, WriteFun, MangleArgFun, Init) ->
Handler = fun(Arg, D) ->
- msg_formater(Type, MangleArg(Arg), D)
+ msg_formater(Type, MangleArgFun(Arg), D)
end,
- InitialData = #data{writer = Write},
+ InitialData = #data{writer = WriteFun,
+ acc = Init},
{ok,_} = dbg:tracer(process, {Handler, InitialData}),
ok.
--
cgit v1.2.3
From 5bcd6af12b34db9d1976099d86fe3414b810aa3e Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 7 Jun 2017 17:22:44 +0200
Subject: ssh: fix sporadic error in ssh_protocol_SUITE
---
lib/ssh/test/ssh_protocol_SUITE.erl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_protocol_SUITE.erl b/lib/ssh/test/ssh_protocol_SUITE.erl
index 0385e30ad1..0837fe7eaf 100644
--- a/lib/ssh/test/ssh_protocol_SUITE.erl
+++ b/lib/ssh/test/ssh_protocol_SUITE.erl
@@ -466,7 +466,7 @@ bad_long_service_name(Config) ->
bad_very_long_service_name(Config) ->
bad_service_name(Config,
- lists:duplicate(4*?SSH_MAX_PACKET_SIZE, $a)).
+ lists:duplicate(?SSH_MAX_PACKET_SIZE+5, $a)).
empty_service_name(Config) ->
bad_service_name(Config, "").
--
cgit v1.2.3
From e46e9d5bec5089d16d0cae7b435c4c82f57f0316 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 7 Jun 2017 17:30:05 +0200
Subject: ssh: fix sporadic error in ssh_options_SUITE
---
lib/ssh/test/ssh_options_SUITE.erl | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/test/ssh_options_SUITE.erl b/lib/ssh/test/ssh_options_SUITE.erl
index b710ca8fb7..8b454ffe5d 100644
--- a/lib/ssh/test/ssh_options_SUITE.erl
+++ b/lib/ssh/test/ssh_options_SUITE.erl
@@ -555,14 +555,14 @@ connectfun_disconnectfun_server(Config) ->
{disconnect,Ref,R} ->
ct:log("Disconnect result: ~p",[R]),
ssh:stop_daemon(Pid)
- after 5000 ->
+ after 10000 ->
receive
X -> ct:log("received ~p",[X])
after 0 -> ok
end,
{fail, "No disconnectfun action"}
end
- after 5000 ->
+ after 10000 ->
receive
X -> ct:log("received ~p",[X])
after 0 -> ok
--
cgit v1.2.3
From 0145539b3cb6a72f62d39a6d401d409eb1de0474 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 1 Jun 2017 10:51:05 +0200
Subject: ssh: Doc for SSH application updated
---
lib/ssh/doc/src/ssh_app.xml | 44 +++++++++++++++++++++++++++++++++++++-------
1 file changed, 37 insertions(+), 7 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/ssh_app.xml b/lib/ssh/doc/src/ssh_app.xml
index 74c4111338..33ec7aaee0 100644
--- a/lib/ssh/doc/src/ssh_app.xml
+++ b/lib/ssh/doc/src/ssh_app.xml
@@ -161,6 +161,8 @@
- ecdsa-sha2-nistp521
- ssh-rsa
- ssh-dss
+ - rsa-sha2-256
+ - rsa-sha2-512
@@ -176,21 +178,23 @@
Encryption algorithms (ciphers)
-
- - aes128-gcm@openssh.com (AEAD_AES_128_GCM)
- - aes256-gcm@openssh.com (AEAD_AES_256_GCM)
+ - aes128-gcm@openssh.com
+ - aes256-gcm@openssh.com
- aes128-ctr
- aes192-ctr
- aes256-ctr
- aes128-cbc
- 3des-cbc
+ - (AEAD_AES_128_GCM, not enabled per default)
+ - (AEAD_AES_256_GCM, not enabled per default)
+ See the text at the description of the rfc 5647 further down
+ for more information regarding AEAD_AES_*_GCM.
+
Following the internet de-facto standard, the cipher and mac algorithm AEAD_AES_128_GCM is selected when the
cipher aes128-gcm@openssh.com is negotiated. The cipher and mac algorithm AEAD_AES_256_GCM is selected when the
cipher aes256-gcm@openssh.com is negotiated.
- See the text at the description of the rfc 5647 further down
- for more information.
-
Compression algorithms
@@ -235,7 +239,11 @@
- RFC 4253, The Secure Shell (SSH) Transport Layer Protocol.
-
+
Except
+
+ - 8.1. diffie-hellman-group1-sha1. Disabled by default, can be enabled with the preferred_algorithms option.
+
+
- RFC 4254, The Secure Shell (SSH) Connection Protocol.
@@ -310,7 +318,29 @@
- - Work in progress: https://tools.ietf.org/html/draft-ietf-curdle-ssh-kex-sha2-05, Key Exchange (KEX) Method Updates and Recommendations for Secure Shell (SSH)
+ - Draft-ietf-curdle-ssh-kex-sha2 (work in progress), Key Exchange (KEX) Method Updates and Recommendations for Secure Shell (SSH).
+
Deviations:
+
+ - The diffie-hellman-group1-sha1 is not enabled by default, but is still supported and can be enabled
+ with the option preferred-algorithms
+ - The questionable sha1-based algorithms diffie-hellman-group-exchange-sha1 and
+ diffie-hellman-group14-sha1 are still enabled by default for compatibility with ancient clients and servers.
+ They can be disabled with the option preferred-algorithms
+
+
+
+
+ - Draft-ietf-curdle-rsa-sha2 (work in progress), Use of RSA Keys with SHA-2 256 and 512 in Secure Shell (SSH).
+
+
+ - Draft-ietf-curdle-ssh-ext-info (work in progress), Extension Negotiation in Secure Shell (SSH).
+
Implemented are:
+
+ - The Extension Negotiation Mechanism
+ - The extension server-sig-algs
+
+
+
--
cgit v1.2.3
From 6dae98d627d16ce67b5ac75f7fc69cfa1caa6dc9 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 1 Jun 2017 13:19:12 +0200
Subject: ssh: Document send_ext_info and recv_ext_info options
---
lib/ssh/doc/src/ssh.xml | 44 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index 5c9ce3d5fb..ea7e975ef5 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -320,6 +320,29 @@
attempted.
+
+
+
+ -
+
Tell the server that the client accepts extension negotiation. See
+ Draft-ietf-curdle-ssh-ext-info (work in progress) for details.
+
+ Currently implemented extension is server-sig-algs which is the list of the server's preferred
+ user's public key algorithms.
+
+ Default value is true.
+
+
+
-
Module implementing the behaviour
+
+ -
+
Send a list of extensions to the client if the client has asked for it. See
+ Draft-ietf-curdle-ssh-ext-info (work in progress) for details.
+
+ Currently implemented extension is sending server-sig-algs which is the list of the server's preferred
+ user's public key algorithms.
+
+ Default value is true.
+
+
+
+
+
-
Module implementing the behaviour
Date: Thu, 1 Jun 2017 19:23:57 +0200
Subject: ssh: re-formulate timeouts in ssh_sftp:start_channel
---
lib/ssh/doc/src/ssh_sftp.xml | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/ssh_sftp.xml b/lib/ssh/doc/src/ssh_sftp.xml
index eb6f43d417..2822bf808f 100644
--- a/lib/ssh/doc/src/ssh_sftp.xml
+++ b/lib/ssh/doc/src/ssh_sftp.xml
@@ -558,8 +558,14 @@
-
-
The time-out is passed to the ssh_channel start function,
- and defaults to infinity.
+ There are two ways to set a timeout for the underlying ssh connection:
+
+ - If the connection timeout option connect_timeout is set, that value
+ is used also for the negotiation timeout and this option (timeout) is ignored.
+ - Otherwise, this option (timeout) is used as the negotiation timeout
+ only and there is no connection timeout set
+
+ The value defaults to infinity.
--
cgit v1.2.3
From 43718d3b81d7f3d08e25047e22d579801bbe5044 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Wed, 14 Jun 2017 15:36:21 +0200
Subject: Update copyright year
---
lib/ssh/doc/src/ssh_sftp.xml | 2 +-
lib/ssh/test/ssh_property_test_SUITE.erl | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/ssh_sftp.xml b/lib/ssh/doc/src/ssh_sftp.xml
index 2822bf808f..ed7fbf9cf3 100644
--- a/lib/ssh/doc/src/ssh_sftp.xml
+++ b/lib/ssh/doc/src/ssh_sftp.xml
@@ -4,7 +4,7 @@
- 20052016
+ 20052017
Ericsson AB. All Rights Reserved.
diff --git a/lib/ssh/test/ssh_property_test_SUITE.erl b/lib/ssh/test/ssh_property_test_SUITE.erl
index 5ea60d8a8f..3318b86d39 100644
--- a/lib/ssh/test/ssh_property_test_SUITE.erl
+++ b/lib/ssh/test/ssh_property_test_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
--
cgit v1.2.3
From c18b13d4c8aa31b145703bbbf228fb07d6b2a0a5 Mon Sep 17 00:00:00 2001
From: Erlang/OTP
Date: Wed, 21 Jun 2017 10:53:19 +0200
Subject: Prepare release
---
lib/ssh/doc/src/notes.xml | 170 ++++++++++++++++++++++++++++++++++++++++++++++
lib/ssh/vsn.mk | 2 +-
2 files changed, 171 insertions(+), 1 deletion(-)
(limited to 'lib/ssh')
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index bddae00dd2..f93753f1d2 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -30,6 +30,176 @@
notes.xml
+Ssh 4.5
+
+ Improvements and New Features
+
+ -
+
+ The internal handling of SSH options is re-written.
+
+ Previously there were no checks if a client option was
+ given to a daemon or vice versa. This is corrected now.
+ If your code has e.g. a client-only option in a call to
+ start a daemon, the call will fail.
+
+ *** POTENTIAL INCOMPATIBILITY ***
+
+ Own Id: OTP-12872
+
+ -
+
+ Modernization of key exchange algorithms. See
+ draft-ietf-curdle-ssh-kex-sha2 for a discussion.
+
+ Removed an outdated weak algorithm and added stronger
+ replacements to keep interoperability with other modern
+ ssh clients and servers. The default ordering of the
+ algorithms is also adjusted.
+
+ Retired: The nowadays unsecure key-exchange
+ diffie-hellman-group1-sha1 is not enabled by
+ default, but can be enabled with the option
+ preferred-algorithms.
+
+ Added: The new stronger key-exchange
+ diffie-hellman-group16-sha512,
+ diffie-hellman-group18-sha512 and
+ diffie-hellman-group14-sha256 are added and
+ enabled by default.
+
+ The questionable [RFC 6194] sha1-based algorithms
+ diffie-hellman-group-exchange-sha1 and
+ diffie-hellman-group14-sha1 are however still kept
+ enabled by default for compatibility with ancient clients
+ and servers that lack modern key-exchange alternatives.
+ When the draft-ietf-curdle-ssh-kex-sha2 becomes an rfc,
+ those sha1-based algorithms and
+ diffie-hellman-group1-sha1 will be deprecated by
+ IETF. They might then be removed from the default list in
+ Erlang/OTP.
+
+ *** POTENTIAL INCOMPATIBILITY ***
+
+ Own Id: OTP-14110
+
+ -
+
+ Modernized internal representation of sftp by use of
+ maps.
+
+ Own Id: OTP-14117
+
+ -
+
+ The Extension Negotiation Mechanism and the extension
+ server-sig-algs in
+ draft-ietf-curdle-ssh-ext-info-05 are implemented.
+
+ The related draft-ietf-curdle-rsa-sha2-05 is implemented
+ and introduces the signature algorithms
+ rsa-sha2-256 and rsa-sha2-512.
+
+ Own Id: OTP-14193
+
+ -
+
+ The 'timeout' and 'connect_timeout' handling in
+ ssh_sftp:start_channel documentation is clarified.
+
+ Own Id: OTP-14216
+
+ -
+
+ The functions ssh:connect, ssh:shell and
+ ssh:start_channel now accept an IP-tuple as Host
+ destination argument.
+
+ Own Id: OTP-14243
+
+ -
+
+ The function ssh:daemon_info/1 now returns Host
+ and Profile as well as the Port info in the property
+ list.
+
+ Own Id: OTP-14259
+
+ -
+
+ Removed the option public_key_alg which was
+ deprecated in 18.2. Use pref_public_key_algs
+ instead.
+
+ *** POTENTIAL INCOMPATIBILITY ***
+
+ Own Id: OTP-14263
+
+ -
+
+ The SSH application is refactored regarding daemon
+ starting. The resolution of contradicting Host
+ argument and ip option were not described. There
+ were also strange corner cases when the 'any'
+ value was used in Host argument or ip
+ option. This is (hopefully) resolved now, but it may
+ cause incompatibilities for code using both Host
+ and the ip option. The value 'loopback' has been
+ added for a correct way of naming those addresses.
+
+ *** POTENTIAL INCOMPATIBILITY ***
+
+ Own Id: OTP-14264
+
+ -
+
+ The supervisor code is refactored. The naming of
+ listening IP-Port-Profile triples are slightly changed to
+ improve consistency in strange corner cases as resolved
+ by OTP-14264
+
+ Own Id: OTP-14267 Aux Id: OTP-14266
+
+ -
+
+ The idle_time option can now be used in daemons.
+
+ Own Id: OTP-14312
+
+ -
+
+ Added test cases for IETF-CURDLE Extension Negotiation
+ (ext-info)
+
+ Own Id: OTP-14361
+
+ -
+
+ Testcases for IETF-CURDLE extension
+ server-sig-algs including rsa-sha2-*
+
+ Own Id: OTP-14362 Aux Id: OTP-14361
+
+ -
+
+ The option auth_methods can now also be used in
+ clients to select which authentication options that are
+ used and in which order.
+
+ Own Id: OTP-14399
+
+ -
+
+ Checks that a ECDSA public key (ecdsa-sha2-nistp*)
+ stored in a file has the correct size.
+
+ Own Id: OTP-14410
+
+
+
+
+
+
Ssh 4.4.2
Fixed Bugs and Malfunctions
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index 48332d2e5a..7208baca6e 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,5 +1,5 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 4.4.2
+SSH_VSN = 4.5
APP_VSN = "ssh-$(SSH_VSN)"
--
cgit v1.2.3