diff options
-rw-r--r-- | lib/diameter/doc/src/diameter.xml | 32 | ||||
-rw-r--r-- | lib/diameter/src/base/diameter_service.erl | 13 | ||||
-rw-r--r-- | lib/diameter/test/diameter_traffic_SUITE.erl | 21 | ||||
-rw-r--r-- | lib/ssh/doc/src/ssh.xml | 5 | ||||
-rw-r--r-- | lib/ssh/src/ssh.erl | 22 | ||||
-rw-r--r-- | lib/ssh/src/ssh_auth.erl | 49 | ||||
-rw-r--r-- | lib/ssh/src/ssh_connection_handler.erl | 28 |
7 files changed, 136 insertions, 34 deletions
diff --git a/lib/diameter/doc/src/diameter.xml b/lib/diameter/doc/src/diameter.xml index b7936dbacc..80863f8eff 100644 --- a/lib/diameter/doc/src/diameter.xml +++ b/lib/diameter/doc/src/diameter.xml @@ -1212,6 +1212,12 @@ DPA or timeout.</p> <desc> <p> Return information about a started service. +Requesting info for an unknown service causes <c>undefined</c> to be +returned. +Requesting a list of items causes a tagged list to be +returned.</p> + +<p> <c>Item</c> can be one of the following.</p> <taglist> @@ -1482,13 +1488,27 @@ The Diameter-level statistics returned by <c>transport</c> and <c>connections</c> info are based upon these entries.</p> </item> -</taglist> - +<tag><c><seealso marker="diameter_app#peer_ref">diameter_app:peer_ref()</seealso></c></tag> +<item> <p> -Requesting info for an unknown service causes <c>undefined</c> to be -returned. -Requesting a list of items causes a tagged list to be -returned.</p> +Return transport configuration associated with a single peer, as +passed to <seealso marker="#add_transport">add_transport/2</seealso>. +The returned list is empty if the peer is unknown. +Otherwise it contains the <c>ref</c>, <c>type</c> and <c>options</c> +tuples as in <c>transport</c> and <c>connections</c> info above. +For example:</p> + +<code> +[{ref,#Ref<0.0.0.61>}, + {type,accept}, + {options,[{transport_module,diameter_tcp}, + {transport_config,[{reuseaddr,true}, + {ip,{127,0,0,1}}, + {port,3868}]}]}] +</code> +</item> + +</taglist> <marker id="services"/> </desc> diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl index b4e54cc9f9..cffba4fc94 100644 --- a/lib/diameter/src/base/diameter_service.erl +++ b/lib/diameter/src/base/diameter_service.erl @@ -3051,6 +3051,19 @@ tagged_info(Item, S) undefined end; +tagged_info(TPid, #state{peerT = PT, connT = CT}) + when is_pid(TPid) -> + try + [#conn{peer = Pid}] = ets:lookup(CT, TPid), + [#peer{ref = Ref, type = Type, options = Opts}] = ets:lookup(PT, Pid), + [{ref, Ref}, + {type, Type}, + {options, Opts}] + catch + error:_ -> + [] + end; + tagged_info(Items, S) when is_list(Items) -> [T || I <- Items, T <- [tagged_info(I,S)], T /= undefined, T /= []]; diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl index c391ba0317..5744ff0307 100644 --- a/lib/diameter/test/diameter_traffic_SUITE.erl +++ b/lib/diameter/test/diameter_traffic_SUITE.erl @@ -626,22 +626,13 @@ pick_peer(Peers, _, ?CLIENT, _State, send_detach, Id, {_,_}) -> find(Id, Peers). find(Id, Peers) -> - [P] = lists:flatmap(fun(C) -> peer(Id, C) end, - diameter:service_info(?CLIENT, transport)), - case lists:keyfind(P, 1, Peers) of %% OTP-10470 will provide a better way. - {_,_} = TC -> - {ok, TC}; - false = No -> - No - end. + [P] = [P || P <- Peers, id(Id, P)], + {ok, P}. -peer(Id, [{ref, _}, - {type, connect}, - {options, Opts}, - {watchdog, _}, - {peer, {PeerRef, _}} - | _]) -> - [PeerRef || lists:member({id, Id}, Opts)]. +id(Id, {Pid, _Caps}) -> + [{ref, _}, {type, _}, {options, Opts} | _] + = diameter:service_info(?CLIENT, Pid), + lists:member({id, Id}, Opts). %% prepare_request/5-6 diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml index b84b3a3dcb..4ab25a8f9b 100644 --- a/lib/ssh/doc/src/ssh.xml +++ b/lib/ssh/doc/src/ssh.xml @@ -142,6 +142,11 @@ some reason, the other algorithm is tried. The default is to try <c><![CDATA[ssh_rsa]]></c> first.</p> </item> + <tag><c><![CDATA[{pref_public_key_algs, list()}]]></c></tag> + <item> + <p>List of public key algorithms to try to use, ssh_rsa and ssh_dsa available. + Will override <c><![CDATA[{public_key_alg, ssh_rsa | ssh_dsa}]]></c></p> + </item> <tag><c><![CDATA[{connect_timeout, timeout()}]]></c></tag> <item> <p>Sets a timeout on the transport layer connection. Defaults to infinity.</p> diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl index 3395f73884..66d1d024ed 100644 --- a/lib/ssh/src/ssh.erl +++ b/lib/ssh/src/ssh.erl @@ -342,6 +342,8 @@ 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([{pref_public_key_algs, _} = 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). @@ -357,6 +359,13 @@ handle_ssh_option({user_interaction, Value} = Opt) when Value == true; Value == Opt; handle_ssh_option({public_key_alg, Value} = Opt) when Value == ssh_rsa; Value == ssh_dsa -> Opt; +handle_ssh_option({pref_public_key_algs, Value} = Opt) when is_list(Value), length(Value) >= 1 -> + case check_pref_algs(Value) of + true -> + Opt; + _ -> + throw({error, {eoptions, Opt}}) + end; handle_ssh_option({connect_timeout, Value} = Opt) when is_integer(Value); Value == infinity -> Opt; handle_ssh_option({user, Value} = Opt) when is_list(Value) -> @@ -424,7 +433,18 @@ handle_inet_option({reuseaddr, _} = Opt) -> %% Option verified by inet handle_inet_option(Opt) -> Opt. - +%% Check preferred algs +check_pref_algs([]) -> + true; +check_pref_algs([H|T]) -> + case H of + ssh_dsa -> + check_pref_algs(T); + ssh_rsa -> + check_pref_algs(T); + _ -> + false + end. %% Has IPv6 been disabled? inetopt(true) -> inet; diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl index aa452a8e09..27e44df554 100644 --- a/lib/ssh/src/ssh_auth.erl +++ b/lib/ssh/src/ssh_auth.erl @@ -118,15 +118,37 @@ init_userauth_request_msg(#ssh{opts = Opts} = Ssh) -> service = "ssh-connection", method = "none", data = <<>>}, - FirstAlg = algorithm(proplists:get_value(public_key_alg, Opts, - ?PREFERRED_PK_ALG)), - SecondAlg = other_alg(FirstAlg), - AllowUserInt = proplists:get_value(user_interaction, Opts, true), - Prefs = method_preference(FirstAlg, SecondAlg, AllowUserInt), - ssh_transport:ssh_packet(Msg, Ssh#ssh{user = User, - userauth_preference = Prefs, - userauth_methods = none, - service = "ssh-connection"}); + case proplists:get_value(pref_public_key_algs, Opts, false) of + false -> + FirstAlg = algorithm(proplists:get_value(public_key_alg, Opts, + ?PREFERRED_PK_ALG)), + SecondAlg = other_alg(FirstAlg), + AllowUserInt = proplists:get_value(user_interaction, Opts, true), + Prefs = method_preference(FirstAlg, SecondAlg, AllowUserInt), + ssh_transport:ssh_packet(Msg, Ssh#ssh{user = User, + userauth_preference = Prefs, + userauth_methods = none, + service = "ssh-connection"}); + Algs -> + FirstAlg = algorithm(lists:nth(1, Algs)), + case length(Algs) =:= 2 of + true -> + SecondAlg = other_alg(FirstAlg), + AllowUserInt = proplists:get_value(user_interaction, Opts, true), + Prefs = method_preference(FirstAlg, SecondAlg, AllowUserInt), + ssh_transport:ssh_packet(Msg, Ssh#ssh{user = User, + userauth_preference = Prefs, + userauth_methods = none, + service = "ssh-connection"}); + _ -> + AllowUserInt = proplists:get_value(user_interaction, Opts, true), + Prefs = method_preference(FirstAlg, AllowUserInt), + ssh_transport:ssh_packet(Msg, Ssh#ssh{user = User, + userauth_preference = Prefs, + userauth_methods = none, + service = "ssh-connection"}) + end + end; {error, no_user} -> ErrStr = "Could not determine the users name", throw(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_ILLEGAL_USER_NAME, @@ -287,6 +309,15 @@ method_preference(Alg1, Alg2, false) -> {"publickey", ?MODULE, publickey_msg,[Alg2]}, {"password", ?MODULE, password_msg, []} ]. +method_preference(Alg1, true) -> + [{"publickey", ?MODULE, publickey_msg, [Alg1]}, + {"password", ?MODULE, password_msg, []}, + {"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []} + ]; +method_preference(Alg1, false) -> + [{"publickey", ?MODULE, publickey_msg, [Alg1]}, + {"password", ?MODULE, password_msg, []} + ]. user_name(Opts) -> Env = case os:type() of diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl index 5b3d1b8a1b..d8950a7b67 100644 --- a/lib/ssh/src/ssh_connection_handler.erl +++ b/lib/ssh/src/ssh_connection_handler.erl @@ -718,8 +718,18 @@ init_ssh(server = Role, Vsn, Version, Options, Socket) -> available_host_keys = supported_host_keys(Role, KeyCb, Options) }. -supported_host_keys(client, _, _) -> - ["ssh-rsa", "ssh-dss"]; +supported_host_keys(client, _, Options) -> + try + case extract_algs(proplists:get_value(pref_public_key_algs, Options, false), []) of + false -> + ["ssh-rsa", "ssh-dss"]; + Algs -> + Algs + end + catch + exit:Reason -> + {stop, {shutdown, Reason}} + end; supported_host_keys(server, KeyCb, Options) -> lists:foldl(fun(Type, Acc) -> case available_host_key(KeyCb, Type, Options) of @@ -731,7 +741,19 @@ supported_host_keys(server, KeyCb, Options) -> end, [], %% Prefered alg last so no need to reverse ["ssh-dss", "ssh-rsa"]). - +extract_algs(false, _) -> + false; +extract_algs([],[]) -> + false; +extract_algs([], NewList) -> + lists:reverse(NewList); +extract_algs([H|T], NewList) -> + case H of + ssh_dsa -> + extract_algs(T, ["ssh-dss"|NewList]); + ssh_rsa -> + extract_algs(T, ["ssh-rsa"|NewList]) + end. available_host_key(KeyCb, "ssh-dss"= Alg, Opts) -> case KeyCb:host_key('ssh-dss', Opts) of {ok, _} -> |