PowerShell / Win32-OpenSSH

Win32 port of OpenSSH
7.38k stars 759 forks source link

Not returning errorlevel correctly when -t flag passed to ssh #1737

Closed skissane closed 3 years ago

skissane commented 3 years ago

"OpenSSH for Windows" version ((Get-Item (Get-Command sshd).Source).VersionInfo.FileVersion)

7.7.2.3 (still reproduces after upgrading to 8.1.0.0)

(Note above command doesn't actually work for me. I am running C:\Windows\System32\OpenSSH\sshd.exe, as demonstrated by sc qc sshd output. But, I actually have MSYS2 sshd first in my path (even though I don't use it), so above command tries to get the version of MSYS2 sshd instead (which doesn't have embedded version info, so it returns blank). Instead I have to do this in PowerShell: (Get-Item C:\Windows\System32\OpenSSH\sshd.exe).VersionInfo.FileVersion)

Server OperatingSystem ((Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows nt\CurrentVersion\" -Name ProductName).ProductName)

"Windows 10 Pro"

Client OperatingSystem

macOS 10.14.6

What is failing When I pass the -t option to ssh, Windows does not return command status code (ERRORLEVEL). By contrast, when I connect to a Linux host, the command status code is always returned correctly, whether I pass -t or not. I am calling an interactive program from a script (so terminal option -t is required) but the script needs to know if the program succeeded or failed.

Running all these commands from my Mac:

ssh mywindowsbox exit 0; echo $? # Prints 0 as expected
ssh mywindowsbox exit 1; echo $? # Prints 1 as expected
ssh mylinuxbox exit 0; echo $? # Prints 0 as expected
ssh mylinuxbox exit 1; echo $? # Prints 1 as expected
ssh -t mylinuxbox exit 0; echo $? # Prints 0 as expected
ssh -t mylinuxbox exit 1; echo $? # Prints 1 as expected
ssh -t mywindowsbox exit 0; echo $? # Prints 0 as expected
ssh -t mywindowsbox exit 1; echo $? # PROBLEM: doesn't print 1, prints 0 instead

(Originally I was reproducing above with true and false, using true.exe/false.exe from MSYS2. I replaced true with exit 0 and false with exit 1 so the reproduce steps no longer depend on MSYS2, and will reproduce with out-of-the-box Windows. Luckily the exit command works the same between bash on Linux and cmd.exe on Windows, so the example still works.)

Windows sshd should return correct ERRORLEVEL from an interactive (-t) process. This would both be consistent with how sshd works on Linux, and also useful in that a script running an interactive console-mode Windows program over ssh could get correct indication of whether the execution of the program was successful or not.

bagajjal commented 3 years ago

@skissane - Can you please test with OpenSSH v8.1. Installation instructions are here

skissane commented 3 years ago

@bagajjal Okay, just upgraded to 8.1.0.0 per your instructions, and I still get the exact same behaviour

skissane commented 3 years ago

@bagajjal Also I edited my reproduction steps above. Don't need to use true.exe/false.exe from MSYS2 to reproduce this. The EXIT command in cmd.exe is enough

DHowett commented 3 years ago

This is possibly because of the old ConPTY invocation style (conhost.exe -- PATH_TO_COMMAND). It does not return the exit code for the COMMAND it runs.

The solution is to use the modern ConPTY API -- CreatePseudoConsole + CreateProcess(... COMMAND ...), followed by tracking the status of the spawned subprocess.

bagajjal commented 3 years ago

@skissane - This will be part of the next win32-OpenSSH release. Meanwhile, you can test with the attached private sshd binary sshd_latest.zip

Terasoft-git commented 11 months ago

The latest sshd has the same behavior