From e9d46adb58b940a92874b2c4bcc833dfcf7375a3 Mon Sep 17 00:00:00 2001
From: Fredrik Gustafsson <fredrik@erlang.org>
Date: Thu, 15 Nov 2012 14:32:52 +0100
Subject: Fixed user interaction ssh

---
 lib/ssh/src/ssh.erl           | 51 +++++++++++++++++++++++----------------
 lib/ssh/src/ssh_auth.erl      | 18 +++++++-------
 lib/ssh/src/ssh_io.erl        | 56 +++++++++++++++++++++++++------------------
 lib/ssh/src/ssh_transport.erl |  2 +-
 4 files changed, 73 insertions(+), 54 deletions(-)

(limited to 'lib')

diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index d09f6cf34b..7d68b1d7bd 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -79,7 +79,7 @@ connect(Host, Port, Options, Timeout) ->
 	    DisableIpv6 =  proplists:get_value(ip_v6_disabled, SshOptions, false),
 	    Inet = inetopt(DisableIpv6),
 	    do_connect(Host, Port, [Inet | SocketOptions], 
-		       [{host, Host} | SshOptions], Timeout, DisableIpv6)
+		       [{user_pid, self()}, {host, Host} | SshOptions], Timeout, DisableIpv6)
     end.
 
 do_connect(Host, Port, SocketOptions, SshOptions, Timeout, DisableIpv6) ->
@@ -91,30 +91,39 @@ do_connect(Host, Port, SocketOptions, SshOptions, Timeout, DisableIpv6) ->
  	{ok, ConnectionSup} ->
 	    {ok, Manager} = 
 		ssh_connection_sup:connection_manager(ConnectionSup),
-	    receive 
-		{Manager, is_connected} ->
-		    {ok, Manager};
-		%% When the connection fails 
-		%% ssh_connection_sup:connection_manager
-		%% might return undefined as the connection manager
-		%% could allready have terminated, so we will not
-		%% match the Manager in this case
-		{_, not_connected, {error, econnrefused}} when DisableIpv6 == false ->
-		    do_connect(Host, Port, proplists:delete(inet6, SocketOptions), 
-			    SshOptions, Timeout, true);
-		{_, not_connected, {error, Reason}} ->
-		    {error, Reason};
-		{_, not_connected, Other} ->
-		    {error, Other}
-	    after Timeout  ->
-		    ssh_connection_manager:stop(Manager),
-		    {error, timeout}
-	    end
+	    msg_loop(Manager, DisableIpv6, Host, Port, SocketOptions, SshOptions, Timeout)
     catch 
 	exit:{noproc, _} ->
  	    {error, ssh_not_started}
     end.
-
+msg_loop(Manager, DisableIpv6, Host, Port, SocketOptions, SshOptions, Timeout) ->
+    receive 
+	{Manager, is_connected} ->
+	    {ok, Manager};
+	%% When the connection fails 
+	%% ssh_connection_sup:connection_manager
+	%% might return undefined as the connection manager
+	%% could allready have terminated, so we will not
+	%% match the Manager in this case
+	{_, not_connected, {error, econnrefused}} when DisableIpv6 == false ->
+	    do_connect(Host, Port, proplists:delete(inet6, SocketOptions), 
+		       SshOptions, Timeout, true);
+	{_, not_connected, {error, Reason}} ->
+	    {error, Reason};
+	{_, not_connected, Other} ->
+	    {error, Other};
+	{From, user_password} ->
+	    Pass = io:get_password(),
+	    From ! Pass,
+	    msg_loop(Manager, DisableIpv6, Host, Port, SocketOptions, SshOptions, Timeout);
+	{From, question} ->
+	    Answer = io:get_line(""),
+	    From ! Answer,
+	    msg_loop(Manager, DisableIpv6, Host, Port, SocketOptions, SshOptions, Timeout)
+    after Timeout  ->
+	    ssh_connection_manager:stop(Manager),
+	    {error, timeout}
+    end.
 %%--------------------------------------------------------------------
 %% Function: close(ConnectionRef) -> ok
 %%
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl
index 27e44df554..c436793dc4 100644
--- a/lib/ssh/src/ssh_auth.erl
+++ b/lib/ssh/src/ssh_auth.erl
@@ -71,7 +71,7 @@ password_msg([#ssh{opts = Opts, io_cb = IoCb,
     ssh_bits:install_messages(userauth_passwd_messages()),
     Password = case proplists:get_value(password, Opts) of
 		   undefined -> 
-		       user_interaction(IoCb);
+		       user_interaction(IoCb, Ssh);
 		   PW -> 
 		       PW
 	       end,
@@ -89,10 +89,10 @@ password_msg([#ssh{opts = Opts, io_cb = IoCb,
 	      Ssh)
     end.
 
-user_interaction(ssh_no_io) ->
+user_interaction(ssh_no_io, _) ->
     not_ok;
-user_interaction(IoCb) ->
-    IoCb:read_password("ssh password: ").
+user_interaction(IoCb, Ssh) ->
+    IoCb:read_password("ssh password: ", Ssh).
 
 
 %% See RFC 4256 for info on keyboard-interactive
@@ -401,11 +401,11 @@ keyboard_interact_get_responses(IoCb, Opts, Name, Instr, PromptInfos) ->
 	    %% Special case/fallback for just one prompt
 	    %% (assumed to be the password prompt)
 	    case proplists:get_value(password, Opts) of
-		undefined -> keyboard_interact(IoCb, Name, Instr, PromptInfos);
+		undefined -> keyboard_interact(IoCb, Name, Instr, PromptInfos, Opts);
 		PW        -> [PW]
 	    end;
 	undefined ->
-	    keyboard_interact(IoCb, Name, Instr, PromptInfos);
+	    keyboard_interact(IoCb, Name, Instr, PromptInfos, Opts);
 	KbdInteractFun ->
 	    Prompts = lists:map(fun({Prompt, _Echo}) -> Prompt end,
 				PromptInfos),
@@ -419,15 +419,15 @@ keyboard_interact_get_responses(IoCb, Opts, Name, Instr, PromptInfos) ->
 	    end
     end.
 
-keyboard_interact(IoCb, Name, Instr, Prompts) ->
+keyboard_interact(IoCb, Name, Instr, Prompts, Opts) ->
     if Name /= "" -> IoCb:format("~s", [Name]);
        true       -> ok
     end,
     if Instr /= "" -> IoCb:format("~s", [Instr]);
        true        -> ok
     end,
-    lists:map(fun({Prompt, true})  -> IoCb:read_line(Prompt);
-		 ({Prompt, false}) -> IoCb:read_password(Prompt)
+    lists:map(fun({Prompt, true})  -> IoCb:read_line(Prompt, Opts);
+		 ({Prompt, false}) -> IoCb:read_password(Prompt, Opts)
 	      end,
 	      Prompts).
 
diff --git a/lib/ssh/src/ssh_io.erl b/lib/ssh/src/ssh_io.erl
index 1dbd097423..fc7a572f7c 100644
--- a/lib/ssh/src/ssh_io.erl
+++ b/lib/ssh/src/ssh_io.erl
@@ -23,37 +23,47 @@
 
 -module(ssh_io).
 
--export([yes_no/1, read_password/1, read_line/1, format/2]).
+-export([yes_no/2, read_password/2, read_line/2, format/2]).
 -import(lists, [reverse/1]).
+-include("ssh.hrl").
 
+read_line(Prompt, Ssh) ->
+    format("~s", [listify(Prompt)]),
+    proplists:get_value(user_pid, Ssh) ! {self(), question},
+    receive
+	Answer ->
+	    Answer
+    end.
 
-read_line(Prompt) when is_list(Prompt) ->
-    io:get_line(list_to_atom(Prompt));
-read_line(Prompt) when is_atom(Prompt) ->
-    io:get_line(Prompt).
-
-read_ln(Prompt) ->
-    trim(read_line(Prompt)).
-
-yes_no(Prompt) ->
+yes_no(Prompt, Ssh) ->
     io:format("~s [y/n]?", [Prompt]),
-    case read_ln('') of
-	"y" -> yes;
-	"n" -> no;
-	"Y" -> yes;
-	"N" -> no;
-	_ ->
-	    io:format("please answer y or n\n"),
-	    yes_no(Prompt)
+    proplists:get_value(user_pid, Ssh#ssh.opts) ! {self(), question},
+    receive
+	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"),
+		    yes_no(Prompt, Ssh)
+	    end
     end.
 
 
-read_password(Prompt) ->
+read_password(Prompt, Ssh) ->
     format("~s", [listify(Prompt)]),
-    case io:get_password() of
-	"" ->
-	    read_password(Prompt);
-	Pass -> Pass
+    proplists:get_value(user_pid, Ssh#ssh.opts) ! {self(), user_password},
+    receive
+	Answer ->
+	    case Answer of
+		"" ->
+		    read_password(Prompt, Ssh);
+		Pass -> Pass
+	    end
     end.
 
 listify(A) when is_atom(A) ->
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 1f912c9bdf..7f6e7d9946 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -133,7 +133,7 @@ kex_dh_gex_messages() ->
     ].
 
 yes_no(Ssh, Prompt)  ->
-    (Ssh#ssh.io_cb):yes_no(Prompt).
+    (Ssh#ssh.io_cb):yes_no(Prompt, Ssh).
 
 connect(ConnectionSup, Address, Port, SocketOpts, Opts) ->    
     Timeout = proplists:get_value(connect_timeout, Opts, infinity),
-- 
cgit v1.2.3


From fe607363e2a67f9d565c1b618a3a4fd4bd0baa4e Mon Sep 17 00:00:00 2001
From: Fredrik Gustafsson <fredrik@erlang.org>
Date: Fri, 16 Nov 2012 10:39:22 +0100
Subject: Fixed if it is not the record to read from in read_password

---
 lib/ssh/src/ssh_io.erl | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

(limited to 'lib')

diff --git a/lib/ssh/src/ssh_io.erl b/lib/ssh/src/ssh_io.erl
index fc7a572f7c..17a7cebb4a 100644
--- a/lib/ssh/src/ssh_io.erl
+++ b/lib/ssh/src/ssh_io.erl
@@ -56,7 +56,12 @@ yes_no(Prompt, Ssh) ->
 
 read_password(Prompt, Ssh) ->
     format("~s", [listify(Prompt)]),
-    proplists:get_value(user_pid, Ssh#ssh.opts) ! {self(), user_password},
+    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,
     receive
 	Answer ->
 	    case Answer of
-- 
cgit v1.2.3