diff --git a/contrib/win32/openssh/OpenSSHBuildHelper.psm1 b/contrib/win32/openssh/OpenSSHBuildHelper.psm1 index 8f358c97f..a66aa2f33 100644 --- a/contrib/win32/openssh/OpenSSHBuildHelper.psm1 +++ b/contrib/win32/openssh/OpenSSHBuildHelper.psm1 @@ -301,7 +301,8 @@ function Package-OpenSSH $buildDir = Join-Path $repositoryRoot ("bin\" + $folderName + "\" + $Configuration) $payload = "sshd.exe", "ssh.exe", "ssh-agent.exe", "ssh-add.exe", "sftp.exe" $payload += "sftp-server.exe", "scp.exe", "ssh-shellhost.exe", "ssh-keygen.exe", "ssh-keyscan.exe" - $payload += "sshd_config", "install-sshd.ps1", "uninstall-sshd.ps1", "FixHostFilePermissions.ps1", "FixUserFilePermissions.ps1", "OpenSSHUtils.psm1" + $payload += "sshd_config", "install-sshd.ps1", "uninstall-sshd.ps1" + $payload +="FixHostFilePermissions.ps1", "FixUserFilePermissions.ps1", "OpenSSHUtils.psm1", "ssh-add-hostkey.ps1" $packageName = "OpenSSH-Win64" if ($NativeHostArch -eq 'x86') { diff --git a/contrib/win32/openssh/OpenSSHTestHelper.psm1 b/contrib/win32/openssh/OpenSSHTestHelper.psm1 index 3c4f16467..40012037a 100644 --- a/contrib/win32/openssh/OpenSSHTestHelper.psm1 +++ b/contrib/win32/openssh/OpenSSHTestHelper.psm1 @@ -158,6 +158,8 @@ WARNING: Following changes will be made to OpenSSH configuration # copy new sshd_config Copy-Item (Join-Path $Script:E2ETestDirectory sshd_config) (Join-Path $script:OpenSSHBinPath sshd_config) -Force + Start-Service ssh-agent + #copy sshtest keys Copy-Item "$($Script:E2ETestDirectory)\sshtest*hostkey*" $script:OpenSSHBinPath -Force Get-ChildItem "$($script:OpenSSHBinPath)\sshtest*hostkey*"| % { @@ -165,17 +167,11 @@ WARNING: Following changes will be made to OpenSSH configuration (Get-Content $_.FullName -Raw).Replace("`r`n","`n") | Set-Content $_.FullName -Force Adjust-HostKeyFileACL -FilePath $_.FullName if (-not ($_.Name.EndsWith(".pub"))) { - Add-PermissionToFileACL -FilePath $_.FullName -User "NT Service\sshd" -Perm "Read" + #register private key with agent + ssh-add-hostkey.ps1 $_.FullName } } - #register host keys with agent - <#Get-ChildItem "$($script:OpenSSHBinPath)\sshtest*hostkey*"| % { - if (-not ($_.Name.EndsWith(".pub"))) { - & "$env:ProgramData\chocolatey\lib\sysinternals\tools\psexec" -accepteula -nobanner -i -s -w $($script:OpenSSHBinPath) cmd.exe /c "ssh-add $_" - Add-PermissionToFileACL -FilePath $_.FullName -User "NT Service\sshd" -Perm "Read" - } - }#> Restart-Service sshd -Force #Backup existing known_hosts and replace with test version @@ -255,7 +251,6 @@ function Get-LocalUserProfile .SYNOPSIS This function installs the tools required by our tests 1) Pester for running the tests - 2) sysinternals required by the tests on windows. #> function Install-OpenSSHTestDependencies { @@ -275,11 +270,6 @@ function Install-OpenSSHTestDependencies Write-Log -Message "Installing Pester..." choco install Pester -y --force --limitoutput 2>&1 >> $Script:TestSetupLogFile } - - if ( -not (Test-Path "$env:ProgramData\chocolatey\lib\sysinternals\tools" ) ) { - Write-Log -Message "sysinternals not present. Installing sysinternals." - choco install sysinternals -y --force --limitoutput 2>&1 >> $Script:TestSetupLogFile - } } <# .Synopsis @@ -309,26 +299,30 @@ function Get-UserSID Cleanup-OpenSSHTestEnvironment #> function Cleanup-OpenSSHTestEnvironment -{ +{ + if($Global:OpenSSHTestInfo -eq $null) { + throw "OpenSSHTestInfo is not set. Did you run Setup-OpenSShTestEnvironment?" + } + + $sshBinPath = $Global:OpenSSHTestInfo["OpenSSHBinPath"] + # .exe - Windows specific. TODO - PAL - if (-not (Test-Path (Join-Path $script:OpenSSHBinPath ssh.exe) -PathType Leaf)) + if (-not (Test-Path (Join-Path $sshBinPath ssh.exe) -PathType Leaf)) { Throw "Cannot find OpenSSH binaries under $script:OpenSSHBinPath. " } - + #unregister test host keys from agent - Get-ChildItem "$($script:OpenSSHBinPath)\sshtest*hostkey*.pub"| % { - $cmd = "cmd /c `"$env:ProgramData\chocolatey\lib\sysinternals\tools\psexec -accepteula -nobanner -s -w $($script:OpenSSHBinPath) ssh-add -d $_ 2> tmp.txt`"" - iex $cmd + Get-ChildItem "$sshBinPath\sshtest*hostkey*.pub"| % { + ssh-add-hostkey.ps1 -Delete_key $_.FullName } - + Remove-Item $sshBinPath\sshtest*hostkey* -Force -ErrorAction SilentlyContinue #Restore sshd_config - $backupConfigPath = Join-Path $Script:OpenSSHBinPath sshd_config.ori + $backupConfigPath = Join-Path $sshBinPath sshd_config.ori if (Test-Path $backupConfigPath -PathType Leaf) { - Copy-Item $backupConfigPath (Join-Path $Script:OpenSSHBinPath sshd_config) -Force -ErrorAction SilentlyContinue - Remove-Item (Join-Path $Script:OpenSSHBinPath sshd_config.ori) -Force -ErrorAction SilentlyContinue - Remove-Item $Script:OpenSSHBinPath\sshtest*hostkey* -Force -ErrorAction SilentlyContinue + Copy-Item $backupConfigPath (Join-Path $sshBinPath sshd_config) -Force -ErrorAction SilentlyContinue + Remove-Item (Join-Path $sshBinPath sshd_config.ori) -Force -ErrorAction SilentlyContinue Restart-Service sshd } diff --git a/contrib/win32/openssh/config.vcxproj b/contrib/win32/openssh/config.vcxproj index 8b8245620..3087d5585 100644 --- a/contrib/win32/openssh/config.vcxproj +++ b/contrib/win32/openssh/config.vcxproj @@ -122,8 +122,9 @@ copy /Y $(SolutionDir)uninstall-ssh*ps1 $(OutDir) copy /Y $(SolutionDir)OpenSSHUtils.psm1 $(OutDir) copy /Y $(SolutionDir)Fix*FilePermissions.ps1 $(OutDir) +copy /Y $(SolutionDir)ssh-add-hostkey.ps1 $(OutDir) If NOT exist $(OutDir)\sshd_config (copy $(SolutionDir)sshd_config $(OutDir)) - Copy install-sshd.ps1, uninstall-sshd.ps1, OpenSSHUtils.psm1, FixHostFilePermissions.ps1, FixUserFilePermissions.ps1, and sshd_config (if not already present) to build directory + Copy install-sshd.ps1, uninstall-sshd.ps1, OpenSSHUtils.psm1, FixHostFilePermissions.ps1, FixUserFilePermissions.ps1, ssh-add-hostkey.ps1, and sshd_config (if not already present) to build directory @@ -154,8 +155,9 @@ If NOT exist $(OutDir)\sshd_config (copy $(SolutionDir)sshd_config $(OutDir)) - Copy install-sshd.ps1, uninstall-sshd.ps1, OpenSSHUtils.psm1, FixHostFilePermissions.ps1, FixUserFilePermissions.ps1, and sshd_config (if not already present) to build directory + Copy install-sshd.ps1, uninstall-sshd.ps1, OpenSSHUtils.psm1, FixHostFilePermissions.ps1, FixUserFilePermissions.ps1, ssh-add-hostkey.ps1, and sshd_config (if not already present) to build directory @@ -190,8 +192,9 @@ If NOT exist $(OutDir)\sshd_config (copy $(SolutionDir)sshd_config $(OutDir)) - Copy install-sshd.ps1, uninstall-sshd.ps1, OpenSSHUtils.psm1, FixHostFilePermissions.ps1, FixUserFilePermissions.ps1, and sshd_config (if not already present) to build directory + Copy install-sshd.ps1, uninstall-sshd.ps1, OpenSSHUtils.psm1, FixHostFilePermissions.ps1, FixUserFilePermissions.ps1, ssh-add-hostkey.ps1, and sshd_config (if not already present) to build directory @@ -226,8 +229,9 @@ If NOT exist $(OutDir)\sshd_config (copy $(SolutionDir)sshd_config $(OutDir)) - Copy install-sshd.ps1, uninstall-sshd.ps1, OpenSSHUtils.psm1, FixHostFilePermissions.ps1, FixUserFilePermissions.ps1, and sshd_config (if not already present) to build directory + Copy install-sshd.ps1, uninstall-sshd.ps1, OpenSSHUtils.psm1, FixHostFilePermissions.ps1, FixUserFilePermissions.ps1, ssh-add-hostkey.ps1, and sshd_config (if not already present) to build directory diff --git a/contrib/win32/openssh/ssh-add-hostkey.ps1 b/contrib/win32/openssh/ssh-add-hostkey.ps1 new file mode 100644 index 000000000..ab03f2744 --- /dev/null +++ b/contrib/win32/openssh/ssh-add-hostkey.ps1 @@ -0,0 +1,96 @@ +<# + Author: manoj.ampalam@microsoft.com + + Description: ssh-add.exe like Powershell utility to do host key management. + Input parameter mimic ssh-add.exe cmdline arguments. + + Host keys on Windows need to be registered as SYSTEM (i.e ssh-add.exe would + need to run as SYSTEM while talking to ssh-agent). This typically requires + an external utility like psexec. + + This script tries to use the Task scheduler option: + - registers a task scheduler task to run ssh-add.exe operation as SYSTEM + - actual output of ssh-add.exe is written to file (both stdout and stderr) + - Dumps the file contents to console + +#> + +# see https://linux.die.net/man/1/ssh-add for what the arguments mean +[CmdletBinding(DefaultParameterSetName='Add_key')] +Param( + [Parameter(ParameterSetName="List_fingerprints")] + [switch]$List_fingerprints, #ssh-add -l + [Parameter(ParameterSetName="List_pubkeys")] + [switch]$List_pubkeys, #ssh-add -L + [Parameter(ParameterSetName="Delete_key")] + [switch]$Delete_key, #ssh-add -d + [Parameter(ParameterSetName="Delete_all")] + [switch]$Delete_all, #ssh-add -D + [Parameter(Mandatory, Position=0, ParameterSetName="Delete_key")] + [Parameter(Mandatory, Position=0, ParameterSetName="Add_key")] + [ValidateNotNullOrEmpty()] + [string]$key +) + +$ssh_add_cmd = get-command ssh-add.exe -ErrorAction Ignore +if($ssh_add_cmd -eq $null) +{ + Throw "Cannot find ssh-add.exe." +} + +#create ssh-add cmdlinet +$ssh_add_cmd_str = $ssh_add_cmd.Path +if ($List_fingerprints) { $ssh_add_cmd_str += " -l" } +elseif ($List_pubkeys) { $ssh_add_cmd_str += " -L" } +elseif ($Delete_key) { $ssh_add_cmd_str += " -d $key" } +elseif ($Delete_all) { $ssh_add_cmd_str += " -D" } +else +{ + if ( ($key.Length -gt 0) -and (-not($key.Contains("host"))) ) { + Do { + $input = Read-Host -Prompt "Are you sure the provided key is a host key? [Yes] Y; [No] N (default is `"Y`")" + if([string]::IsNullOrEmpty($input)) + { + $input = 'Y' + } + } until ($input -match "^(y(es)?|N(o)?)$") + $result = $Matches[0] + if (-not($result.ToLower().Startswith('y'))) { exit } + } + $ssh_add_cmd_str += " $key" +} + +#globals +$taskfolder = "\OpenSSHUtils\hostkey_tasks\" +$taskname = "hostkey_task" +$ssh_add_output = Join-Path (pwd).Path "ssh-add-hostkey-tmp.txt" +$task_argument = "/c `"$ssh_add_cmd_str > $ssh_add_output 2>&1 `"" + +#create TaskScheduler task +$ac = New-ScheduledTaskAction -Execute "cmd.exe" -Argument $task_argument -WorkingDirectory (pwd).path +$task = Register-ScheduledTask -TaskName $taskname -User System -Action $ac -TaskPath $taskfolder -Force + +#run the task +if (Test-Path $ssh_add_output) {Remove-Item $ssh_add_output -Force} +Start-ScheduledTask -TaskPath $taskfolder -TaskName $taskname + +#if still running, wait a little while for task to complete +$num = 0 +while ((Get-ScheduledTask -TaskName $taskname -TaskPath $taskfolder).State -eq "Running") +{ + sleep 1 + $num++ + if($num -gt 20) { break } +} +if (-not(Test-Path $ssh_add_output)) {throw "cannot find task output file. Something went WRONG!!! "} + +#dump output to console +Get-Content $ssh_add_output + +#cleanup task and output file +Remove-Item $ssh_add_output -Force +Unregister-ScheduledTask -TaskPath $taskfolder -TaskName $taskname -Confirm:$false + + + +