[erlang-patches] Problems with erlang SSH server

Stefan Zegenhagen <>
Fri Jul 20 11:41:48 CEST 2012


Dear all,

The patch below fixes a few problems with the erlang SSH server that
prevents numerous SSH clients from connecting/operating correctly with
an erlang-SSH server.

Kind regards,


--- snip ---

>From acb7a76a5cd46d03f20e74db8d7b0a7723284814 Mon Sep 17 00:00:00 2001
From: Stefan Zegenhagen <>
Date: Fri, 20 Jul 2012 11:38:57 +0200
Subject: [PATCH] Improve interoperability with SSH clients

This patch fixes a few problems of the SSH shell server that affect the
interoperability with SSH clients in widespread use.

First problem is that, whenever a channel_request message is
received with want_reply=true, the reply ends up being sent to the
servers channel id, not the clients channel id. This causes the client
to terminate the connection. The easiest solution to the problem appears
to be a new function in ssh_connection_manager.erl that translates the
servers channel id before sending the reply (in the same manner as
other functions do it).

Second problem is in ssh_cli.erl. When an SSH client sends a
window_change request between PTY allocation and starting the shell
(which appears to happen with some clients), ssh_cli.erl crashes
because #state.buf is yet 'undefined'. Allocating an empty buffer at PTY
allocation time solves the problem.

Affected SSH clients:
 - all clients based on SSH-2.0-TrileadSSH2Java_213 (problem #1)
 - SSH Term Pro (problem #2)
---
 lib/ssh/src/ssh_cli.erl                |    3 ++-
 lib/ssh/src/ssh_connection.erl         |    2 +-
 lib/ssh/src/ssh_connection_manager.erl |   15 ++++++++++++++-
 3 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/lib/ssh/src/ssh_cli.erl b/lib/ssh/src/ssh_cli.erl
index 781e01b..c8c610f 100644
--- a/lib/ssh/src/ssh_cli.erl
+++ b/lib/ssh/src/ssh_cli.erl
@@ -81,7 +81,8 @@ handle_ssh_msg({ssh_cm, ConnectionManager,
 				  height = not_zero(Height, 24),
 				  pixel_width = PixWidth,
 				  pixel_height = PixHeight,
-				  modes = Modes}},
+                  modes = Modes},
+             buf = empty_buf()},
     set_echo(State),
     ssh_connection:reply_request(ConnectionManager, WantReply, 
 				 success, ChannelId),
diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl
index c46f799..913f505 100644
--- a/lib/ssh/src/ssh_connection.erl
+++ b/lib/ssh/src/ssh_connection.erl
@@ -177,7 +177,7 @@ close(ConnectionManager, ChannelId) ->
 %% Description: Send status replies to requests that want such replies.
 %%--------------------------------------------------------------------
 reply_request(ConnectionManager, true, Status, ChannelId) ->
-    ConnectionManager ! {ssh_cm, self(), {Status, ChannelId}},
+    ssh_connection_manager:reply_request(ConnectionManager, Status, ChannelId),
     ok;
 reply_request(_,false, _, _) ->
     ok.
diff --git a/lib/ssh/src/ssh_connection_manager.erl b/lib/ssh/src/ssh_connection_manager.erl
index e53cd4f..e350f96 100644
--- a/lib/ssh/src/ssh_connection_manager.erl
+++ b/lib/ssh/src/ssh_connection_manager.erl
@@ -40,7 +40,7 @@
 	 close/2, stop/1, send/5,
 	 send_eof/2]).
 
--export([open_channel/6, request/6, request/7, global_request/4, event/2,
+-export([open_channel/6, reply_request/3, request/6, request/7, global_request/4, event/2,
 	 cast/2]).
 
 %% Internal application API and spawn
@@ -95,6 +95,9 @@ request(ConnectionManager, ChannelId, Type, true, Data, Timeout) ->
 request(ConnectionManager, ChannelId, Type, false, Data, _) ->
     cast(ConnectionManager, {request, ChannelId, Type, Data}).
 
+reply_request(ConnectionManager, Status, ChannelId) ->
+    cast(ConnectionManager, {reply_request, Status, ChannelId}).
+
 global_request(ConnectionManager, Type, true = Reply, Data) ->
     case call(ConnectionManager, 
 	      {global_request, self(), Type, Reply, Data}) of
@@ -431,6 +434,16 @@ handle_cast({request, ChannelId, Type, Data}, State0) ->
     lists:foreach(fun send_msg/1, Replies),
     {noreply, State};
 
+handle_cast({reply_request, Status, ChannelId}, #state{connection_state =
+        #connection{channel_cache = Cache}} = State0) ->
+    State = case ssh_channel:cache_lookup(Cache, ChannelId) of
+        #channel{remote_id = RemoteId} ->
+            cm_message({Status, RemoteId}, State0);
+        undefined ->
+            State0
+    end,
+    {noreply, State};
+
 handle_cast({global_request, _, _, _, _} = Request, State0) ->
     State = handle_global_request(Request, State0),
     {noreply, State};
-- 
1.7.9.5



-- 
Dr. Stefan Zegenhagen

arcutronix GmbH
Garbsener Landstr. 10
30419 Hannover
Germany

Tel:   +49 511 277-2734
Fax:   +49 511 277-2709
Email: 
Web:   www.arcutronix.com

*Synchronize the Ethernet*

General Managers: Dipl. Ing. Juergen Schroeder, Dr. Josef Gfrerer -
Legal Form: GmbH, Registered office: Hannover, HRB 202442, Amtsgericht
Hannover; Ust-Id: DE257551767.

Please consider the environment before printing this message.



More information about the erlang-patches mailing list