Link to home
Start Free TrialLog in
Avatar of BroadbandAntennaTrackingSystems
BroadbandAntennaTrackingSystems

asked on

Mask Input via OpenSSH

Hello experts.

I have a Command Line application developed in .NET 2.0

I have the following code for masking specific user input that I do not want displayed in clear text.

protected string MaskPasswordInput()
            {
                  IntPtr hStdIn = new IntPtr(CONIN);
                  int mode = 0;
                  char inputChar;
                  string password = "";

                  //Set console mode to read a character
                  //at a time and not echo input.
                  GetConsoleMode(hStdIn, ref mode);
                  mode = (mode & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT));
                  SetConsoleMode(hStdIn, mode);

                  //Read the password a character at a time.
                  do
                  {
                        inputChar = (char)Console.Read();
                        if (inputChar >= 32)
                        {
                              //Echo character with password mask.
                              password += inputChar;
                              Console.Write("*");
                        }
                  } while (inputChar != '\r');//Enter pressed end of password.

                  //Set console back to line input
                  //mode if that's what you want.
                  mode = (mode | (ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT));
                  SetConsoleMode(hStdIn, mode);

                  return password;
            }

This subroutine works fabulously via a telnet session. However when using Putty and OpenSSH the subroutine does not properly mask the input. Instead I see the clear text followed by the masked input characters. My best guess is this has to do with the echo or delay via SSH?

Any help or ideas would be greatly appreciated.

Cheers
Avatar of gelonida
gelonida
Flag of France image

Do telnet / putty / openssh use the same terminal configuration?


Do you use putty / openssh interactively or is this an automated openssh call?

Could you specify your host on which you start telnet? (is it windows or cygwin telnet / is it started from a cmd window or from an xterm?)

Could you specify your host on which you started  putty/ssh?




You might try the '-t' option for openssh, but with the little information I have I'm not sure, that this is your problem

     -t      Force pseudo-tty allocation.  This can be used to execute arbi-
             trary screen-based programs on a remote machine, which can be
             very useful, e.g. when implementing menu services.  Multiple -t
             options force tty allocation, even if ssh has no local tty.

Avatar of BroadbandAntennaTrackingSystems
BroadbandAntennaTrackingSystems

ASKER

Gelonida,

Thanks for the feedback. I am using KTS KPYM Telnet Service on a Windows x86 environment. openSSH is being run under Cygwin on the same machine.

The ForceStart command of openSSH launches my .NET based Command Line Console.

I have openSSH registered as a start up service. So perhaps adding the -t command to the start up.

I have attempted to execute stty -echo prior to the password input and stty echo after the password input but this does not seem to quite work.

 public void ToggleEcho(bool on)
        {
            try
            {
                int exitCode = -9999;
               
               
                exitCode = CommandLineHelper.ExecuteCommand(@"c:\cygwin\bin\stty.exe",
                                                 (on ? "echo" : "-echo"), 120000);

               
               Log.Info(("Exit Code " + exitCode));
               
            }
            catch (Exception ex)
            {
               Log.Error(ex);
            }
        }


I have also seen examples using the following command  c:\cygwin\bin\sh.exe -c /bin/stty -echo
but still no success.

I'll let you know how the -t on the service start up works. Alternatively is there a variable I could set in the sshd_config file?
ASKER CERTIFIED SOLUTION
Avatar of gelonida
gelonida
Flag of France image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks for the input. I'll give it a try.
Gelonida,

Thanks for your suggestions. Sometimes it really helps to take a step back and get another perspective.
So I think the issue may reside in that the stty -echo command may only apply to the current cygwin instance.

Here was my base test case.

1) Open a cygwin shell test stty -echo and stty echo
Everything works great

2) open two cygwin shells
run stty -echo
see if these settings take effect on both shells.
Result. They do not.
So I would not expect that running stty -echo from another process as above would produce the desired result.

I am somewhat new to the cygwin environment so please forgive me if this is a newbie question. Is there a flag for stty -echo that I could use to control all open cygwin shells?

Thanks again for all your input
Hi,

I'm not aware of a global flag. normally stty controls only the current terminal.

perhaps you clould again explain your exact use case:
I'm afraid I don't understand it.

Yoou have two Computers let's call them A and B


on A you installed an openssh server and a .NET command line application let's call it dotnet.exe
on B you have a cygwin=window


If you start dotnet.exe on A from a cmd window, then your password entry is hidden / masked, right?

if you start a cygwi wndow on B and ssh to A and try to strt dotnet.exe, then your password is not hidden/masked,
right?


What happens:

if you open a cygwin window on A and start dotnet.exe from there?
(without any stty -echo and so on ?? )


Thank you again for your help.

Ok. So your synopsis is pretty much accurate.

When running cygwin shell on A and start dotnet.exe (TestConsole.exe) the echo is off. It currently does not turn back on but I think that has to do with looking for the eol character at the end of the password mask function.

I have seen an example were someone was writing out to /dev/tty each time. This may be worth evaluating if I can find the reference again. What are your thoughts? Is there anything there?
Two more tests (I just try to narow down)


Test 1: ssh from A to A and run your program:
---------------------------------------------------------
open a cygwin shell on A:
ssh localhost  # use ssh and connect to yourself
#Now run
TestConsole.exe
# and just to have some more info
echo $TERM


Test 2: same as test 1, but ssh from B:
----------------------------------------------------
open a cygwin shell on B:
ssh hostnameof_A   # use ssh and connect to A
#Now run
TestConsole.exe
# and just to have some more info (it should be same as in Test1)
echo $TERM

FYI, Here is the code example.

Will post results form above momentarily.

#CODE

class Program
{
      static void Main(string[] args)
      {
             TTY_Test.Execute();
      }
}

public class TTY_Test
{
        public static void Execute()
        {
            int exitCode1;
            int exitCode2;
            Console.WriteLine("User: ");
            string user = Console.ReadLine();
            Console.WriteLine("Password: ");
            exitCode1 = ToggleEcho(false);
            string password = Console.ReadLine();
            exitCode2 = ToggleEcho(true);
            Console.WriteLine("Toggle off Exit Code:" + exitCode1");
            Console.WriteLine("Toggle on Exit Code:" + exitCode2");
            Console.WriteLine("Done;");
            Console.ReadLine();
        }

        protected static int ToggleEcho(bool on)
        {
            int exitCode = -9999;

            try
            {
                //TODO: Add CommandLineHelper-e

                exitCode = CommandLineHelper.ExecuteCommand(@"c:\cygwin\bin\stty.exe",
                                                 (on ? "echo" : "-echo"), 120000);


                Console.WriteLine("Exit Code " + exitCode);

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }

            return exitCode;
        }
}

#END CODE

Run Cygwin on A
echo $TERM
result cygwin
Run TestConsole.exe
User: user
Password: pass (echoes)
Toggle Off Exit Code: 0
Toggle On Exit Code: 0
echo $TERM
result cygwin

SSH from A to A
echo $TERM
result xterm
Run TestConsole.exe
User: user
Passwor: pass (echoes)
Toggle Off Exit Code: 0
Toggle On Exit Code: 0
echo $TERM
result xterm

protected static int ToggleEcho(bool on)
        {
            int ExitCode = -9999;

            try
            {
                //TODO: Add CommandLineHelper-e

                ProcessStartInfo ProcessInfo;
                System.Diagnostics.Process Process;

               
                    try
                    {
                        StringBuilder output = new StringBuilder();
                        ProcessInfo = new ProcessStartInfo(@"c:\cygwin\bin\stty.exe", (on ? "echo" : "-echo"));
                        ProcessInfo.CreateNoWindow = true;
                        ProcessInfo.UseShellExecute = false;
                        Process = System.Diagnostics.Process.Start(ProcessInfo);
                        Process.WaitForExit(120000);
                        ExitCode = Process.ExitCode;
                        Process.Close();
                    }
                    catch (Exception ex)
                    {
                       Console.WriteLine("Error");
                    }
                    return ExitCode;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }

            return ExitCode;
        }
SSH from B to A
echo $TERM
result xterm
Run TestConsole.exe
User: user
Passwor: pass (echoes)
Toggle Off Exit Code: 0
Toggle On Exit Code: 0
echo $TERM
result xterm
when $TERM result is CYGWIN then setting the properties on the Console such as ECHO* and Console.ForegroundColor take effect, but not for XTERM

*ECHO in this case is achieved by

            [System.Runtime.InteropServices.DllImport("kernel32")]
            private static extern int SetConsoleMode(IntPtr hConsoleHandle,
            int dwMode);

            [System.Runtime.InteropServices.DllImport("kernel32")]
            private static extern int GetConsoleMode(IntPtr hConsoleHandle,
            ref int dwMode);

//Set console mode to read a character
                  //at a time and not echo input.
                  GetConsoleMode(hStdIn, ref mode);
                  mode = (mode & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT));
                  SetConsoleMode(hStdIn, mode);
no idea, why the wrong terminal is detected and set.
but you can force the TERM variable in ~/.bashrc


by adding following line to it
export TERM=cygwin

Thanks for the info. Do I need to set it /home/user/.bashrc or is there a way to default it for all users?
/etc/bash.bashrc  should be for all users
 
If this doesn't work change /etc/profile




Thanks so much for all of your help... this has really be haunting me. I'll let you know how it goes!