Skip to content

Commit

Permalink
Merge branch 'hans/ssh/scanning/OTP-12247' into maint-17
Browse files Browse the repository at this point in the history
* hans/ssh/scanning/OTP-12247:
  ssh: fix ssh.appup.src.
  ssh: Corrected appup
  ssh: fix .app and .appup errors
  ssh: remove supervisors for crashed connection worker
  ssh: Print supervisor tree (on demand).
  ssh: prepare for release
  ssh: avoid terminated but not deleted children to be counted.
  ssh: simple info function (ssh_info:print/0).
  ssh: Gracefully handle bad handshake messages
  ssh: reduce amount of printouts
  ssh: Fix port scanner problems
  • Loading branch information
Erlang/OTP committed Oct 23, 2014
2 parents 5d49d05 + b7f2472 commit c530f3d
Show file tree
Hide file tree
Showing 11 changed files with 353 additions and 26 deletions.
1 change: 1 addition & 0 deletions lib/ssh/src/Makefile
Expand Up @@ -65,6 +65,7 @@ MODULES= \
ssh_cli \
ssh_file \
ssh_io \
ssh_info \
ssh_math \
ssh_message \
ssh_no_io \
Expand Down
1 change: 1 addition & 0 deletions lib/ssh/src/ssh.app.src
Expand Up @@ -23,6 +23,7 @@
sshd_sup,
ssh_file,
ssh_io,
ssh_info,
ssh_math,
ssh_no_io,
ssh_server_key_api,
Expand Down
34 changes: 32 additions & 2 deletions lib/ssh/src/ssh.appup.src
Expand Up @@ -19,15 +19,45 @@

{"%VSN%",
[
{"3.0.7", [{load_module, ssh_auth, soft_purge, soft_purge, [ssh_connection_handler]},
{load_module, ssh_acceptor, soft_purge, soft_purge, [ssh_connection_handler]},
{load_module, ssh_channel, soft_purge, soft_purge, [ssh_connection_handler]},
{load_module, ssh_connection, soft_purge, soft_purge, [ssh_connection_handler]},
{load_module, ssh_connection_handler, soft_purge, soft_purge, []},
{load_module, ssh_info, soft_purge, soft_purge, []},
{load_module, ssh_message, soft_purge, soft_purge, [ssh_connection_handler]},
{load_module, ssh_io, soft_purge, soft_purge, [ssh_connection_handler]},
{load_module, ssh_sftp, soft_purge, soft_purge, [ssh_connection_handler]},
{load_module, ssh_xfer, soft_purge, soft_purge, [ssh_connection_handler]}]},
{"3.0.6", [{load_module, ssh_auth, soft_purge, soft_purge, [ssh_connection_handler]},
{load_module, ssh_acceptor, soft_purge, soft_purge, [ssh_connection_handler]},
{load_module, ssh_channel, soft_purge, soft_purge, [ssh_connection_handler]},
{load_module, ssh_connection, soft_purge, soft_purge, [ssh_connection_handler]},
{load_module, ssh_connection_handler, soft_purge, soft_purge, []},
{load_module, ssh_info, soft_purge, soft_purge, []},
{load_module, ssh_message, soft_purge, soft_purge, [ssh_connection_handler]},
{load_module, ssh_io, soft_purge, soft_purge, [ssh_connection_handler]},
{load_module, ssh_sftp, soft_purge, soft_purge, [ssh_connection_handler]}]},
{load_module, ssh_xfer, soft_purge, soft_purge, [ssh_connection_handler]},
{load_module, ssh_sftp, soft_purge, soft_purge, [ssh_connection_handler]},
{load_module, ssh_xfer, soft_purge, soft_purge, [ssh_connection_handler]}]},
{<<".*">>, [{restart_application, ssh}]}
],
[
{"3.0.7", [{load_module, ssh_auth, soft_purge, soft_purge, [ssh_connection_handler]},
{load_module, ssh_acceptor, soft_purge, soft_purge, [ssh_connection_handler]},
{load_module, ssh_channel, soft_purge, soft_purge, [ssh_connection_handler]},
{load_module, ssh_connection, soft_purge, soft_purge, [ssh_connection_handler]},
{load_module, ssh_connection_handler, soft_purge, soft_purge, []},
{load_module, ssh_info, soft_purge, soft_purge, []},
{load_module, ssh_message, soft_purge, soft_purge, [ssh_connection_handler]},
{load_module, ssh_io, soft_purge, soft_purge, [ssh_connection_handler]},
{load_module, ssh_sftp, soft_purge, soft_purge, [ssh_connection_handler]},
{load_module, ssh_xfer, soft_purge, soft_purge, [ssh_connection_handler]}]},
{"3.0.6", [{load_module, ssh_auth, soft_purge, soft_purge, [ssh_connection_handler]},
{load_module, ssh_acceptor, soft_purge, soft_purge, [ssh_connection_handler]},
{load_module, ssh_channel, soft_purge, soft_purge, [ssh_connection_handler]},
{load_module, ssh_connection, soft_purge, soft_purge, [ssh_connection_handler]},
{load_module, ssh_connection_handler, soft_purge, soft_purge, []},
{load_module, ssh_info, soft_purge, soft_purge, []},
{load_module, ssh_message, soft_purge, soft_purge, [ssh_connection_handler]},
{load_module, ssh_io, soft_purge, soft_purge, [ssh_connection_handler]},
{load_module, ssh_sftp, soft_purge, soft_purge, [ssh_connection_handler]},
Expand Down
4 changes: 3 additions & 1 deletion lib/ssh/src/ssh_acceptor.erl
Expand Up @@ -22,7 +22,8 @@
-module(ssh_acceptor).

%% Internal application API
-export([start_link/5]).
-export([start_link/5,
number_of_connections/1]).

%% spawn export
-export([acceptor_init/6, acceptor_loop/6]).
Expand Down Expand Up @@ -140,5 +141,6 @@ handle_error(Reason) ->
number_of_connections(SystemSup) ->
length([X ||
{R,X,supervisor,[ssh_subsystem_sup]} <- supervisor:which_children(SystemSup),
is_pid(X),
is_reference(R)
]).
24 changes: 22 additions & 2 deletions lib/ssh/src/ssh_auth.erl
Expand Up @@ -184,9 +184,8 @@ handle_userauth_request(#ssh_msg_service_request{name =
handle_userauth_request(#ssh_msg_userauth_request{user = User,
service = "ssh-connection",
method = "password",
data = Data}, _,
data = <<?FALSE, ?UINT32(Sz), BinPwd:Sz/binary>>}, _,
#ssh{opts = Opts} = Ssh) ->
<<_:8, ?UINT32(Sz), BinPwd:Sz/binary>> = Data,
Password = unicode:characters_to_list(BinPwd),
case check_password(User, Password, Opts) of
true ->
Expand All @@ -199,6 +198,27 @@ handle_userauth_request(#ssh_msg_userauth_request{user = User,
partial_success = false}, Ssh)}
end;

handle_userauth_request(#ssh_msg_userauth_request{user = User,
service = "ssh-connection",
method = "password",
data = <<?TRUE,
_/binary
%% ?UINT32(Sz1), OldBinPwd:Sz1/binary,
%% ?UINT32(Sz2), NewBinPwd:Sz2/binary
>>
}, _,
Ssh) ->
%% Password change without us having sent SSH_MSG_USERAUTH_PASSWD_CHANGEREQ (because we never do)
%% RFC 4252 says:
%% SSH_MSG_USERAUTH_FAILURE without partial success - The password
%% has not been changed. Either password changing was not supported,
%% or the old password was bad.

{not_authorized, {User, {error,"Password change not supported"}},
ssh_transport:ssh_packet(#ssh_msg_userauth_failure{
authentications = "",
partial_success = false}, Ssh)};

handle_userauth_request(#ssh_msg_userauth_request{user = User,
service = "ssh-connection",
method = "none"}, _,
Expand Down
14 changes: 13 additions & 1 deletion lib/ssh/src/ssh_channel.erl
Expand Up @@ -67,7 +67,8 @@
%% Internal application API
-export([cache_create/0, cache_lookup/2, cache_update/2,
cache_delete/1, cache_delete/2, cache_foldl/3,
cache_find/2]).
cache_find/2,
get_print_info/1]).

-record(state, {
cm,
Expand Down Expand Up @@ -190,6 +191,14 @@ init([Options]) ->
%% {stop, Reason, State}
%% Description: Handling call messages
%%--------------------------------------------------------------------
handle_call(get_print_info, _From, State) ->
Reply =
{{State#state.cm,
State#state.channel_id},
io_lib:format('CB=~p',[State#state.channel_cb])
},
{reply, Reply, State};

handle_call(Request, From, #state{channel_cb = Module,
channel_state = ChannelState} = State) ->
try Module:handle_call(Request, From, ChannelState) of
Expand Down Expand Up @@ -333,6 +342,9 @@ cache_find(ChannelPid, Cache) ->
Channel
end.

get_print_info(Pid) ->
call(Pid, get_print_info, 1000).

%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion lib/ssh/src/ssh_connection.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
%% Copyright Ericsson AB 2008-2014. 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
Expand Down
99 changes: 81 additions & 18 deletions lib/ssh/src/ssh_connection_handler.erl
Expand Up @@ -41,11 +41,13 @@
global_request/4, send/5, send_eof/2, info/1, info/2,
connection_info/2, channel_info/3,
adjust_window/3, close/2, stop/1, renegotiate/1, renegotiate_data/1,
start_connection/4]).
start_connection/4,
get_print_info/1]).

%% gen_fsm callbacks
-export([hello/2, kexinit/2, key_exchange/2, new_keys/2,
userauth/2, connected/2]).
userauth/2, connected/2,
error/2]).

-export([init/1, handle_event/3,
handle_sync_event/4, handle_info/3, terminate/3, format_status/2, code_change/4]).
Expand Down Expand Up @@ -171,9 +173,23 @@ init([Role, Socket, SshOpts]) ->
State#state{ssh_params = Ssh})
catch
_:Error ->
gen_fsm:enter_loop(?MODULE, [], error, {Error, State0})
gen_fsm:enter_loop(?MODULE, [], error, {Error, State})
end.

%% Temporary fix for the Nessus error. SYN-> <-SYNACK ACK-> RST-> ?
error(_Event, {Error,State=#state{}}) ->
case Error of
{badmatch,{error,enotconn}} ->
%% {error,enotconn} probably from inet:peername in
%% init_ssh(server,..)/5 called from init/1
{stop, {shutdown,"TCP connenction to server was prematurely closed by the client"}, State};
_ ->
{stop, {shutdown,{init,Error}}, State}
end;
error(Event, State) ->
%% State deliberately not checked beeing #state. This is a panic-clause...
{stop, {shutdown,{init,{spurious_error,Event}}}, State}.

%%--------------------------------------------------------------------
-spec open_channel(pid(), string(), iodata(), integer(), integer(),
timeout()) -> {open, channel_id()} | {error, term()}.
Expand Down Expand Up @@ -240,6 +256,9 @@ send_eof(ConnectionHandler, ChannelId) ->
%%--------------------------------------------------------------------
-spec connection_info(pid(), [atom()]) -> proplists:proplist().
%%--------------------------------------------------------------------
get_print_info(ConnectionHandler) ->
sync_send_all_state_event(ConnectionHandler, get_print_info, 1000).

connection_info(ConnectionHandler, Options) ->
sync_send_all_state_event(ConnectionHandler, {connection_info, Options}).

Expand Down Expand Up @@ -550,7 +569,7 @@ connected({#ssh_msg_kexinit{}, _Payload} = Event, State) ->

%%--------------------------------------------------------------------
handle_event(#ssh_msg_disconnect{description = Desc} = DisconnectMsg, _StateName, #state{} = State) ->
handle_disconnect(DisconnectMsg, State),
handle_disconnect(peer, DisconnectMsg, State),
{stop, {shutdown, Desc}, State};

handle_event(#ssh_msg_ignore{}, StateName, State) ->
Expand Down Expand Up @@ -758,6 +777,20 @@ handle_sync_event({recv_window, ChannelId}, _From, StateName,
end,
{reply, Reply, StateName, next_packet(State)};

handle_sync_event(get_print_info, _From, StateName, State) ->
Reply =
try
{inet:sockname(State#state.socket),
inet:peername(State#state.socket)
}
of
{{ok,Local}, {ok,Remote}} -> {{Local,Remote},io_lib:format("statename=~p",[StateName])};
_ -> {{"-",0},"-"}
catch
_:_ -> {{"?",0},"?"}
end,
{reply, Reply, StateName, State};

handle_sync_event({connection_info, Options}, _From, StateName, State) ->
Info = ssh_info(Options, State, []),
{reply, Info, StateName, State};
Expand Down Expand Up @@ -936,6 +969,10 @@ terminate(normal, _, #state{transport_cb = Transport,
(catch Transport:close(Socket)),
ok;

terminate({shutdown,{init,Reason}}, StateName, State) ->
error_logger:info_report(io_lib:format("Erlang ssh in connection handler init: ~p~n",[Reason])),
terminate(normal, StateName, State);

%% Terminated by supervisor
terminate(shutdown, StateName, #state{ssh_params = Ssh0} = State) ->
DisconnectMsg =
Expand All @@ -951,8 +988,10 @@ terminate({shutdown, #ssh_msg_disconnect{} = Msg}, StateName,
{SshPacket, Ssh} = ssh_transport:ssh_packet(Msg, Ssh0),
send_msg(SshPacket, State),
terminate(normal, StateName, State#state{ssh_params = Ssh});

terminate({shutdown, _}, StateName, State) ->
terminate(normal, StateName, State);

terminate(Reason, StateName, #state{ssh_params = Ssh0, starter = _Pid,
connection_state = Connection} = State) ->
terminate_subsytem(Connection),
Expand All @@ -965,6 +1004,7 @@ terminate(Reason, StateName, #state{ssh_params = Ssh0, starter = _Pid,
send_msg(SshPacket, State),
terminate(normal, StateName, State#state{ssh_params = Ssh}).


terminate_subsytem(#connection{system_supervisor = SysSup,
sub_system_supervisor = SubSysSup}) when is_pid(SubSysSup) ->
ssh_system_sup:stop_subsystem(SysSup, SubSysSup);
Expand Down Expand Up @@ -1161,7 +1201,10 @@ send_all_state_event(FsmPid, Event) ->
gen_fsm:send_all_state_event(FsmPid, Event).

sync_send_all_state_event(FsmPid, Event) ->
try gen_fsm:sync_send_all_state_event(FsmPid, Event, infinity)
sync_send_all_state_event(FsmPid, Event, infinity).

sync_send_all_state_event(FsmPid, Event, Timeout) ->
try gen_fsm:sync_send_all_state_event(FsmPid, Event, Timeout)
catch
exit:{noproc, _} ->
{error, closed};
Expand Down Expand Up @@ -1258,13 +1301,23 @@ generate_event(<<?BYTE(Byte), _/binary>> = Msg, StateName,
generate_event(Msg, StateName, State0, EncData) ->
Event = ssh_message:decode(Msg),
State = generate_event_new_state(State0, EncData),
case Event of
#ssh_msg_kexinit{} ->
%% We need payload for verification later.
event({Event, Msg}, StateName, State);
_ ->
event(Event, StateName, State)
end.
try
case Event of
#ssh_msg_kexinit{} ->
%% We need payload for verification later.
event({Event, Msg}, StateName, State);
_ ->
event(Event, StateName, State)
end
catch
_:_ ->
DisconnectMsg =
#ssh_msg_disconnect{code = ?SSH_DISCONNECT_PROTOCOL_ERROR,
description = "Encountered unexpected input",
language = "en"},
handle_disconnect(DisconnectMsg, State)
end.



handle_request(ChannelPid, ChannelId, Type, Data, WantReply, From,
Expand Down Expand Up @@ -1442,17 +1495,27 @@ handle_ssh_packet(Length, StateName, #state{decoded_data_buffer = DecData0,
handle_disconnect(DisconnectMsg, State0)
end.

handle_disconnect(#ssh_msg_disconnect{description = Desc} = Msg, #state{connection_state = Connection0,
role = Role} = State0) ->
handle_disconnect(DisconnectMsg, State) ->
handle_disconnect(own, DisconnectMsg, State).

handle_disconnect(#ssh_msg_disconnect{} = DisconnectMsg, State, Error) ->
handle_disconnect(own, DisconnectMsg, State, Error);
handle_disconnect(Type, #ssh_msg_disconnect{description = Desc} = Msg, #state{connection_state = Connection0, role = Role} = State0) ->
{disconnect, _, {{replies, Replies}, Connection}} = ssh_connection:handle_msg(Msg, Connection0, Role),
State = send_replies(Replies, State0),
State = send_replies(disconnect_replies(Type, Msg, Replies), State0),
{stop, {shutdown, Desc}, State#state{connection_state = Connection}}.
handle_disconnect(#ssh_msg_disconnect{description = Desc} = Msg, #state{connection_state = Connection0,
role = Role} = State0, ErrorMsg) ->

handle_disconnect(Type, #ssh_msg_disconnect{description = Desc} = Msg, #state{connection_state = Connection0,
role = Role} = State0, ErrorMsg) ->
{disconnect, _, {{replies, Replies}, Connection}} = ssh_connection:handle_msg(Msg, Connection0, Role),
State = send_replies(Replies, State0),
State = send_replies(disconnect_replies(Type, Msg, Replies), State0),
{stop, {shutdown, {Desc, ErrorMsg}}, State#state{connection_state = Connection}}.

disconnect_replies(own, Msg, Replies) ->
[{connection_reply, Msg} | Replies];
disconnect_replies(peer, _, Replies) ->
Replies.

counterpart_versions(NumVsn, StrVsn, #ssh{role = server} = Ssh) ->
Ssh#ssh{c_vsn = NumVsn , c_version = StrVsn};
counterpart_versions(NumVsn, StrVsn, #ssh{role = client} = Ssh) ->
Expand Down

0 comments on commit c530f3d

Please sign in to comment.