From e85070d50e3dd07f524273c9f9ab9d1596fc3448 Mon Sep 17 00:00:00 2001 From: Manoj Ampalam Date: Sun, 15 Jan 2017 16:46:39 -0800 Subject: [PATCH] Source snapshot from Powershell/openssh-portable:latestw_cwb --- INSTALL | 3 +- appveyor.yml | 14 +- auth2-pubkey.c | 8 +- contrib/win32/openssh/appveyor.psm1 | 188 ++++++----- contrib/win32/openssh/build.psm1 | 76 ++--- contrib/win32/openssh/version.rc | Bin 4046 -> 4046 bytes contrib/win32/win32compat/fileio.c | 21 +- contrib/win32/win32compat/inc/dirent.h | 3 +- contrib/win32/win32compat/inc/w32posix.h | 2 + contrib/win32/win32compat/lsa/Ssh-lsa.c | 9 +- contrib/win32/win32compat/misc.c | 298 ++++++++++++++---- contrib/win32/win32compat/misc_internal.h | 3 +- contrib/win32/win32compat/pwd.c | 9 +- contrib/win32/win32compat/shell-host.c | 27 +- contrib/win32/win32compat/signal.c | 2 +- contrib/win32/win32compat/signal_internal.h | 7 +- contrib/win32/win32compat/signal_sigchld.c | 42 ++- contrib/win32/win32compat/ssh-agent/agent.c | 7 +- .../win32/win32compat/ssh-agent/agentconfig.c | 10 +- .../win32compat/ssh-agent/authagent-request.c | 2 +- contrib/win32/win32compat/w32log.c | 90 ++++-- contrib/win32/win32compat/win32_dirent.c | 20 +- contrib/win32/win32compat/wmain_sshd.c | 6 +- .../pesterTests/PlatformAbstractLayer.psm1 | 42 ++- regress/pesterTests/SCP.Tests.ps1 | 73 +++-- regress/pesterTests/SSH.Tests.ps1 | 25 +- scp.c | 11 +- sftp-client.c | 4 +- sftp.c | 16 +- ssh-agent.c | 4 +- ssh-keygen.c | 4 + 31 files changed, 693 insertions(+), 333 deletions(-) diff --git a/INSTALL b/INSTALL index 6bc80b68..92106bf0 100644 --- a/INSTALL +++ b/INSTALL @@ -1,3 +1,4 @@ +1. Prerequisites ---------------- A C compiler. Any C89 or better compiler should work. Where supported, @@ -231,7 +232,7 @@ manually using the following commands: ssh-keygen -t [type] -f /etc/ssh/ssh_host_key -N "" -for each of the types you wish to generate (rsa, dsa or ecdsaa) or +for each of the types you wish to generate (rsa, dsa or ecdsa) or ssh-keygen -A diff --git a/appveyor.yml b/appveyor.yml index 0d2d4541..b3303b4a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -11,12 +11,12 @@ init: build_script: - ps: | - Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppVeyor.psm1 + Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppVeyor.psm1 -WarningAction SilentlyContinue Invoke-AppVeyorBuild after_build: - ps: | - Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppVeyor.psm1 + Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppVeyor.psm1 -WarningAction SilentlyContinue Install-OpenSSH - ps: Write-Verbose "Restart computer ..." - ps: Restart-Computer -ComputerName localhost -Force @@ -25,19 +25,19 @@ after_build: before_test: - ps: | - Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppVeyor.psm1 - Install-TestDependencies + Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppVeyor.psm1 -WarningAction SilentlyContinue + Install-TestDependencies test_script: - cmd: | - "%ProgramFiles%\PowerShell\6.0.0.12\powershell.exe" -Command "Import-Module \"%APPVEYOR_BUILD_FOLDER%\contrib\win32\openssh\AppVeyor.psm1\";Run-OpenSSHTests" + "%ProgramFiles%\PowerShell\6.0.0.14\powershell.exe" -Command "Import-Module \"%APPVEYOR_BUILD_FOLDER%\contrib\win32\openssh\AppVeyor.psm1\" -WarningAction SilentlyContinue;Run-OpenSSHTests" after_test: - ps: | - Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppVeyor.psm1 + Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppVeyor.psm1 -WarningAction SilentlyContinue Upload-OpenSSHTestResults on_finish: - ps: | - Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppVeyor.psm1 + Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppVeyor.psm1 -WarningAction SilentlyContinue Publish-Artifact diff --git a/auth2-pubkey.c b/auth2-pubkey.c index 949a864a..a5a5c273 100644 --- a/auth2-pubkey.c +++ b/auth2-pubkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-pubkey.c,v 1.60 2016/11/30 02:57:40 djm Exp $ */ +/* $OpenBSD: auth2-pubkey.c,v 1.61 2016/12/30 22:08:02 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -783,6 +783,9 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key) ok = process_principals(f, NULL, pw, cert); + fclose(f); + f = NULL; + if (exited_cleanly(pid, "AuthorizedPrincipalsCommand", command) != 0) goto out; @@ -1106,6 +1109,9 @@ user_key_command_allowed2(struct passwd *user_pw, Key *key) ok = check_authkeys_file(f, options.authorized_keys_command, key, pw); + fclose(f); + f = NULL; + if (exited_cleanly(pid, "AuthorizedKeysCommand", command) != 0) goto out; diff --git a/contrib/win32/openssh/appveyor.psm1 b/contrib/win32/openssh/appveyor.psm1 index a678feca..828228d5 100644 --- a/contrib/win32/openssh/appveyor.psm1 +++ b/contrib/win32/openssh/appveyor.psm1 @@ -1,6 +1,26 @@ $ErrorActionPreference = 'Stop' Import-Module $PSScriptRoot\build.psm1 $repoRoot = Get-RepositoryRoot +$script:logFile = join-path $repoRoot.FullName "appveyorlog.log" + + +<# + Called by Write-BuildMsg to write to the build log, if it exists. +#> +function Write-Log +{ + param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] $Message + ) + # write it to the log file, if present. + if (-not ([string]::IsNullOrEmpty($script:logFile))) + { + Add-Content -Path $script:logFile -Value $Message + } +} # Sets a build variable Function Set-BuildVariable @@ -53,7 +73,7 @@ function Invoke-AppVeyorFull Install-TestDependencies & "$env:ProgramFiles\PowerShell\6.0.0.12\powershell.exe" -Command {Import-Module $($repoRoot.FullName)\contrib\win32\openssh\AppVeyor.psm1;Run-OpenSSHTests -uploadResults} Run-OpenSSHTests - Publish-Artifact + Publish-Artifact } finally { if($APPVEYOR_SCHEDULED_BUILD -and $env:APPVEYOR_SCHEDULED_BUILD) @@ -66,10 +86,8 @@ function Invoke-AppVeyorFull # Implements the AppVeyor 'build_script' step function Invoke-AppVeyorBuild { - Start-SSHBuild -Configuration Release -NativeHostArch x64 -Verbose - Start-SSHBuild -Configuration Debug -NativeHostArch x64 -Verbose - Start-SSHBuild -Configuration Release -NativeHostArch x86 -Verbose - Start-SSHBuild -Configuration Debug -NativeHostArch x86 -Verbose + Start-SSHBuild -Configuration Release -NativeHostArch x64 + Start-SSHBuild -Configuration Debug -NativeHostArch x86 } <# @@ -83,8 +101,8 @@ function Invoke-MSIEXEC [Parameter(Mandatory=$true)] [string] $InstallFile ) - - Write-Verbose "Installing $InstallFile..." + + Write-Log -Message "Installing $InstallFile..." $arguments = @( "/i" "`"$InstallFile`"" @@ -93,10 +111,10 @@ function Invoke-MSIEXEC ) $process = Start-Process -FilePath msiexec.exe -ArgumentList $arguments -Wait -PassThru if ($process.ExitCode -eq 0){ - Write-Output "$InstallFile has been successfully installed" + Write-Log -Message "$InstallFile has been successfully installed." } else { - Write-Output "installer exit code $($process.ExitCode) for file $($InstallFile)" + Write-Log -Message "installer exit code $($process.ExitCode) for file $($InstallFile)" } return $process.ExitCode @@ -108,13 +126,13 @@ function Invoke-MSIEXEC #> function Install-PSCoreFromGithub { - $downloadLocation = Download-PSCoreMSI - - Write-Output "Installing PSCore ..." + $downloadLocation = Download-PSCoreMSI + + Write-Log -Message "Installing PSCore ..." if(-not [string]::IsNullOrEmpty($downloadLocation)) { $processExitCode = Invoke-MSIEXEC -InstallFile $downloadLocation - Write-Output "Process exitcode: $processExitCode" + Write-Log -Message "Process exitcode: $processExitCode" } } @@ -125,27 +143,27 @@ function Install-PSCoreFromGithub function Get-PSCoreMSIDownloadURL { $osversion = [String][Environment]::OSVersion.Version - Write-Host "osversion:$osversion" + if($osversion.StartsWith("6")) { if ($($env:PROCESSOR_ARCHITECTURE).Contains('64')) { - return 'https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-alpha.12/PowerShell_6.0.0.12-alpha.12-win81-x64.msi' + return 'https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-alpha.14/PowerShell_6.0.0.14-alpha.14-win81-x64.msi' } else { - return '' + return 'https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-alpha.14/PowerShell_6.0.0.14-alpha.14-win7-x86.msi' } } elseif ($osversion.Contains("10.0")) { if ($($env:PROCESSOR_ARCHITECTURE).Contains('64')) { - return 'https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-alpha.12/PowerShell_6.0.0.12-alpha.12-win10-x64.msi' + return 'https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-alpha.14/PowerShell_6.0.0.14-alpha.14-win10-x64.msi' } else { - return '' + return 'https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-alpha.14/PowerShell_6.0.0.14-alpha.14-win7-x86.msi' } } } @@ -158,14 +176,14 @@ function Download-PSCoreMSI { $url = Get-PSCoreMSIDownloadURL if([string]::IsNullOrEmpty($url)) - { - Write-Output "url is empty" + { + Write-Log -Message "url is empty" return '' } $parsed = $url.Substring($url.LastIndexOf("/") + 1) if(-not (Test-path "$env:SystemDrive\PScore" -PathType Container)) { - New-Item -ItemType Directory -Force -Path "$env:SystemDrive\PScore" | out-null + $null = New-Item -ItemType Directory -Force -Path "$env:SystemDrive\PScore" | out-null } $downloadLocation = "$env:SystemDrive\PScore\$parsed" if(-not (Test-path $downloadLocation -PathType Leaf)) @@ -196,16 +214,15 @@ function Install-TestDependencies $isModuleAvailable = Get-Module 'Pester' -ListAvailable if (-not ($isModuleAvailable)) - { - Write-Output 'Installing Pester...' - choco install Pester -y --force + { + Write-Log -Message "Installing Pester..." + choco install Pester -y --force --limitoutput } - if ( -not (Test-Path "$env:ProgramData\chocolatey\lib\sysinternals\tools" ) ) { - Write-Output "sysinternals not present. Installing sysinternals." - choco install sysinternals -y - } - Write-Output "Installing pscore..." + if ( -not (Test-Path "$env:ProgramData\chocolatey\lib\sysinternals\tools" ) ) { + Write-Log -Message "sysinternals not present. Installing sysinternals." + choco install sysinternals -y --force --limitoutput + } Install-PSCoreFromGithub } <# @@ -219,8 +236,8 @@ function Install-OpenSSH ( [string] $OpenSSHDir = "$env:SystemDrive\OpenSSH", - [ValidateSet('Debug', 'Release')] - [string]$Configuration = "Debug", + [ValidateSet('Debug', 'Release', '')] + [string]$Configuration = "", [ValidateSet('x86', 'x64', '')] [string]$NativeHostArch = "" @@ -272,8 +289,8 @@ function Build-Win32OpenSSHPackage ( [string] $OpenSSHDir = "$env:SystemDrive\OpenSSH", - [ValidateSet('Debug', 'Release')] - [string]$Configuration = "Debug", + [ValidateSet('Debug', 'Release', '')] + [string]$Configuration = "", [ValidateSet('x86', 'x64', '')] [string]$NativeHostArch = "" @@ -281,32 +298,49 @@ function Build-Win32OpenSSHPackage if (-not (Test-Path -Path $OpenSSHDir -PathType Container)) { - New-Item -Path $OpenSSHDir -ItemType Directory -Force -ErrorAction Stop + $null = New-Item -Path $OpenSSHDir -ItemType Directory -Force -ErrorAction Stop } - [string] $platform = $env:PROCESSOR_ARCHITECTURE + [string] $platform = $env:PROCESSOR_ARCHITECTURE if(-not [String]::IsNullOrEmpty($NativeHostArch)) { $folderName = $NativeHostArch - if($NativeHostArch -eq 'x86') + if($NativeHostArch -ieq 'x86') { - $folderName = "Win32" + $folderName = "Win32" } } else { if($platform -ieq "AMD64") { - $folderName = "x64" + $folderName = "x64" } else { - $folderName = "Win32" + $folderName = "Win32" + } + } + + if([String]::IsNullOrEmpty($Configuration)) + { + if( $folderName -ieq "Win32" ) + { + $RealConfiguration = "Debug" + } + else + { + $RealConfiguration = "Release" } } + else + { + $RealConfiguration = $Configuration + } + [System.IO.DirectoryInfo] $repositoryRoot = Get-RepositoryRoot - $sourceDir = Join-Path $repositoryRoot.FullName -ChildPath "bin\$folderName\$Configuration" + $sourceDir = Join-Path $repositoryRoot.FullName -ChildPath "bin\$folderName\$RealConfiguration" Copy-Item -Path "$sourceDir\*" -Destination $OpenSSHDir -Include *.exe,*.dll -Exclude *unittest*.* -Force -ErrorAction Stop $sourceDir = Join-Path $repositoryRoot.FullName -ChildPath "contrib\win32\openssh" Copy-Item -Path "$sourceDir\*" -Destination $OpenSSHDir -Include *.ps1,sshd_config -Exclude AnalyzeCodeDiff.ps1 -Force -ErrorAction Stop @@ -314,8 +348,8 @@ function Build-Win32OpenSSHPackage $packageName = "rktools.2003" $rktoolsPath = "${env:ProgramFiles(x86)}\Windows Resource Kits\Tools\ntrights.exe" if (-not (Test-Path -Path $rktoolsPath)) - { - Write-Information -MessageData "$packageName not present. Installing $packageName." + { + Write-Log -Message "$packageName not present. Installing $packageName." choco install $packageName -y --force } @@ -327,7 +361,7 @@ function Build-Win32OpenSSHPackage $packageFolder = $env:APPVEYOR_BUILD_FOLDER } - $package = "$packageFolder\Win32OpenSSH$Configuration$folderName.zip" + $package = "$packageFolder\Win32OpenSSH$RealConfiguration$folderName.zip" $allPackage = "$packageFolder\Win32OpenSSH*.zip" if (Test-Path $allPackage) { @@ -349,8 +383,8 @@ function Deploy-OpenSSHTests ( [string] $OpenSSHTestDir = "$env:SystemDrive\OpenSSH", - [ValidateSet('Debug', 'Release')] - [string]$Configuration = "Debug", + [ValidateSet('Debug', 'Release', '')] + [string]$Configuration = "", [ValidateSet('x86', 'x64', '')] [string]$NativeHostArch = "" @@ -358,7 +392,7 @@ function Deploy-OpenSSHTests if (-not (Test-Path -Path $OpenSSHTestDir -PathType Container)) { - New-Item -Path $OpenSSHTestDir -ItemType Directory -Force -ErrorAction Stop + $null = New-Item -Path $OpenSSHTestDir -ItemType Directory -Force -ErrorAction Stop } [string] $platform = $env:PROCESSOR_ARCHITECTURE @@ -381,6 +415,22 @@ function Deploy-OpenSSHTests $folderName = "Win32" } } + + if([String]::IsNullOrEmpty($Configuration)) + { + if( $folderName -ieq "Win32" ) + { + $RealConfiguration = "Debug" + } + else + { + $RealConfiguration = "Release" + } + } + else + { + $RealConfiguration = $Configuration + } [System.IO.DirectoryInfo] $repositoryRoot = Get-RepositoryRoot @@ -388,9 +438,8 @@ function Deploy-OpenSSHTests $sourceDir = Join-Path $repositoryRoot.FullName -ChildPath "regress\pesterTests" Copy-Item -Path "$sourceDir\*" -Destination $OpenSSHTestDir -Include *.ps1,*.psm1 -Force -ErrorAction Stop - $sourceDir = Join-Path $repositoryRoot.FullName -ChildPath "bin\$folderName\$Configuration" - Copy-Item -Path "$sourceDir\*" -Destination $OpenSSHTestDir -Exclude ssh-agent.exe, sshd.exe -Force -ErrorAction Stop - + $sourceDir = Join-Path $repositoryRoot.FullName -ChildPath "bin\$folderName\$RealConfiguration" + Copy-Item -Path "$sourceDir\*" -Destination $OpenSSHTestDir -Exclude ssh-agent.exe, sshd.exe -Force -ErrorAction Stop } @@ -419,10 +468,8 @@ function Add-BuildLog ) if (Test-Path -Path $buildLog) - { - Write-Output "Adding $buildLog to local artifacts" + { $null = $artifacts.Add($buildLog) - Write-Output "Adding $buildLog to local artifacts- completed" } else { @@ -449,14 +496,10 @@ function Add-Artifact $files = Get-ChildItem -Path $FileToAdd -ErrorAction Ignore if ($files -ne $null) - { - + { $files | % { - Write-Output "Adding $($_.FullName) to local artifacts" - $null = $artifacts.Add($_.FullName) - Write-Output "Adding $($_.FullName) to local artifacts- completed" - } - + $null = $artifacts.Add($_.FullName) + } } else { @@ -480,13 +523,11 @@ function Publish-Artifact } Add-Artifact -artifacts $artifacts -FileToAdd "$packageFolder\Win32OpenSSH*.zip" - Add-Artifact -artifacts $artifacts -FileToAdd "$packageFolder\OpenSSH\UnitTestResults.txt" + Add-Artifact -artifacts $artifacts -FileToAdd "$env:SystemDrive\OpenSSH\UnitTestResults.txt" + Add-Artifact -artifacts $artifacts -FileToAdd "$script:logFile" - # Get the build.log file for each build configuration - #Add-BuildLog -artifacts $artifacts -buildLog (Get-BuildLogFile -root $repoRoot.FullName -Configuration Release -NativeHostArch x86) - #Add-BuildLog -artifacts $artifacts -buildLog (Get-BuildLogFile -root $repoRoot.FullName -Configuration Debug -NativeHostArch x86) - #Add-BuildLog -artifacts $artifacts -buildLog (Get-BuildLogFile -root $repoRoot.FullName -Configuration Release -NativeHostArch x64) - Add-BuildLog -artifacts $artifacts -buildLog (Get-BuildLogFile -root $repoRoot.FullName -Configuration Debug -NativeHostArch x64) + # Get the build.log file for each build configuration + Add-BuildLog -artifacts $artifacts -buildLog (Get-BuildLogFile -root $repoRoot.FullName) foreach ($artifact in $artifacts) { @@ -505,11 +546,11 @@ function Run-OpenSSHPesterTest param($testRoot, $outputXml) # Discover all CI tests and run them. - Push-Location $testRoot - Write-Output "Running OpenSSH Pester tests..." + Push-Location $testRoot + Write-Log -Message "Running OpenSSH Pester tests..." $testFolders = Get-ChildItem *.tests.ps1 -Recurse | ForEach-Object{ Split-Path $_.FullName} | Sort-Object -Unique - Invoke-Pester $testFolders -OutputFormat NUnitXml -OutputFile $outputXml -Tag 'CI' + Invoke-Pester $testFolders -OutputFormat NUnitXml -OutputFile $outputXml -Tag 'CI' Pop-Location } @@ -522,8 +563,8 @@ function Run-OpenSSHUnitTest param($testRoot, $unitTestOutputFile) # Discover all CI tests and run them. - Push-Location $testRoot - Write-Output "Running OpenSSH unit tests..." + Push-Location $testRoot + Write-Log -Message "Running OpenSSH unit tests..." if (Test-Path $unitTestOutputFile) { Remove-Item -Path $unitTestOutputFile -Force -ErrorAction SilentlyContinue @@ -534,13 +575,13 @@ function Run-OpenSSHUnitTest if ($unitTestFiles -ne $null) { $unitTestFiles | % { - Write-Output "Running OpenSSH unit $($_.FullName)..." + Write-Log -Message "Running OpenSSH unit $($_.FullName)..." & $_.FullName >> $unitTestOutputFile $errorCode = $LASTEXITCODE if ($errorCode -ne 0) { $testFailed = $true - Write-Output "$($_.FullName) test failed for OpenSSH.`nExitCode: $error" + Write-Log -Message "$($_.FullName) test failed for OpenSSH.`nExitCode: $error" } } @@ -614,6 +655,5 @@ function Upload-OpenSSHTestResults if ($env:APPVEYOR_JOB_ID) { (New-Object 'System.Net.WebClient').UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path $testResultsFile)) - } - + } } diff --git a/contrib/win32/openssh/build.psm1 b/contrib/win32/openssh/build.psm1 index ed5ec5ab..722a32b2 100644 --- a/contrib/win32/openssh/build.psm1 +++ b/contrib/win32/openssh/build.psm1 @@ -133,15 +133,14 @@ function Write-BuildMsg Verifies all tools and dependencies required for building Open SSH are installed on the machine. #> function Start-SSHBootstrap -{ +{ + [bool] $silent = -not $script:Verbose + Set-StrictMode -Version Latest - Write-BuildMsg -AsInfo -Message "Checking tools and dependencies" + Write-BuildMsg -AsInfo -Message "Checking tools and dependencies" -Silent:$silent $machinePath = [Environment]::GetEnvironmentVariable('Path', 'MACHINE') - $newMachineEnvironmentPath = $machinePath - - # NOTE: Unless -Verbose is specified, most informational output will only go to the log file. - [bool] $silent = -not $script:Verbose + $newMachineEnvironmentPath = $machinePath # Install chocolatey $chocolateyPath = "$env:AllUsersProfile\chocolatey\bin" @@ -151,18 +150,18 @@ function Start-SSHBootstrap } else { - Write-BuildMsg -AsInfo -Message "Chocolatey not present. Installing chocolatey." + Write-BuildMsg -AsInfo -Message "Chocolatey not present. Installing chocolatey." -Silent:$silent Invoke-Expression ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1')) if (-not ($machinePath.ToLower().Contains($chocolateyPath.ToLower()))) { - Write-BuildMsg -AsVerbose -Message "Adding $chocolateyPath to Path environment variable" + Write-BuildMsg -AsVerbose -Message "Adding $chocolateyPath to Path environment variable" -Silent:$silent $newMachineEnvironmentPath += ";$chocolateyPath" $env:Path += ";$chocolateyPath" } else { - Write-BuildMsg -AsVerbose -Message "$chocolateyPath already present in Path environment variable" + Write-BuildMsg -AsVerbose -Message "$chocolateyPath already present in Path environment variable" -Silent:$silent } } @@ -170,7 +169,7 @@ function Start-SSHBootstrap $gitCmdPath = "$env:ProgramFiles\git\cmd" if (-not ($machinePath.ToLower().Contains($gitCmdPath.ToLower()))) { - Write-BuildMsg -AsVerbose -Message "Adding $gitCmdPath to Path environment variable" + Write-BuildMsg -AsVerbose -Message "Adding $gitCmdPath to Path environment variable" -Silent:$silent $newMachineEnvironmentPath = "$gitCmdPath;$newMachineEnvironmentPath" } else @@ -186,7 +185,7 @@ function Start-SSHBootstrap if (-not ($machinePath.ToLower().Contains($nativeMSBuildPath.ToLower()))) { - Write-BuildMsg -AsVerbose -Message "Adding $nativeMSBuildPath to Path environment variable" + Write-BuildMsg -AsVerbose -Message "Adding $nativeMSBuildPath to Path environment variable" -Silent:$silent $newMachineEnvironmentPath += ";$nativeMSBuildPath" $env:Path += ";$nativeMSBuildPath" } @@ -207,8 +206,8 @@ function Start-SSHBootstrap if (-not (Test-Path -Path $nasmPath -PathType Container)) { - Write-BuildMsg -AsInfo -Message "$packageName not present. Installing $packageName." - choco install $packageName -y --force --execution-timeout 10000 + Write-BuildMsg -AsInfo -Message "$packageName not present. Installing $packageName." -Silent:$silent + choco install $packageName -y --force --limitoutput --execution-timeout 10000 } else { @@ -221,9 +220,9 @@ function Start-SSHBootstrap if ($null -eq $VSPackageInstalled) { - Write-BuildMsg -AsInfo -Message "$packageName not present. Installing $packageName." + Write-BuildMsg -AsInfo -Message "$packageName not present. Installing $packageName." -Silent:$silent $adminFilePath = "$script:OpenSSHRoot\contrib\win32\openssh\VSWithBuildTools.xml" - choco install $packageName -packageParameters "--AdminFile $adminFilePath" -y --force --execution-timeout 10000 + choco install $packageName -packageParameters "--AdminFile $adminFilePath" -y --force --limitoutput --execution-timeout 10000 } else { @@ -236,8 +235,8 @@ function Start-SSHBootstrap if (-not (Test-Path -Path $sdkPath)) { - Write-BuildMsg -AsInfo -Message "Windows 8.1 SDK not present. Installing $packageName." - choco install $packageName -y --force + Write-BuildMsg -AsInfo -Message "Windows 8.1 SDK not present. Installing $packageName." -Silent:$silent + choco install $packageName -y --limitoutput --force } else { @@ -262,7 +261,7 @@ function Start-SSHBootstrap $item = Get-Item(Join-Path -Path $env:VS140COMNTOOLS -ChildPath '../../vc') $script:vcPath = $item.FullName - Write-BuildMsg -AsVerbose -Message "vcPath: $script:vcPath" + Write-BuildMsg -AsVerbose -Message "vcPath: $script:vcPath" -Silent:$silent if ((Test-Path -Path "$script:vcPath\vcvarsall.bat") -eq $false) { Write-BuildMsg -AsError -ErrorAction Stop -Message "Could not find Visual Studio vcvarsall.bat at" + $script:vcPath @@ -270,16 +269,18 @@ function Start-SSHBootstrap } function Clone-Win32OpenSSH -{ +{ + [bool] $silent = -not $script:Verbose + $win32OpenSSHPath = join-path $script:gitRoot "Win32-OpenSSH" if (-not (Test-Path -Path $win32OpenSSHPath -PathType Container)) { - Write-BuildMsg -AsInfo -Message "clone repo Win32-OpenSSH" + Write-BuildMsg -AsInfo -Message "clone repo Win32-OpenSSH" -Silent:$silent Push-Location $gitRoot git clone -q --recursive https://github.com/PowerShell/Win32-OpenSSH.git $win32OpenSSHPath Pop-Location } - Write-BuildMsg -AsInfo -Message "pull latest from repo Win32-OpenSSH" + Write-BuildMsg -AsInfo -Message "pull latest from repo Win32-OpenSSH" -Silent:$silent Push-Location $win32OpenSSHPath git fetch -q origin git checkout -qf L1-Prod @@ -287,9 +288,11 @@ function Clone-Win32OpenSSH } function Copy-OpenSSLSDK -{ +{ + [bool] $silent = -not $script:Verbose + $sourcePath = Join-Path $script:gitRoot "Win32-OpenSSH\contrib\win32\openssh\OpenSSLSDK" - Write-BuildMsg -AsInfo -Message "copying $sourcePath" + Write-BuildMsg -AsInfo -Message "copying $sourcePath" -Silent:$silent Copy-Item -Container -Path $sourcePath -Destination $PSScriptRoot -Recurse -Force -ErrorAction SilentlyContinue -ErrorVariable e if($e -ne $null) { @@ -306,7 +309,7 @@ function Start-SSHBuild [string]$NativeHostArch = "x64", [ValidateSet('Debug', 'Release', '')] - [string]$Configuration = "Debug" + [string]$Configuration = "Release" ) Set-StrictMode -Version Latest $script:BuildLogFile = $null @@ -321,16 +324,16 @@ function Start-SSHBuild if($PSBoundParameters.ContainsKey("Verbose")) { $script:Verbose = ($PSBoundParameters['Verbose']).IsPresent - } + } + [bool] $silent = -not $script:Verbose $script:BuildLogFile = Get-BuildLogFile -root $repositoryRoot.FullName -Configuration $Configuration -NativeHostArch $NativeHostArch if (Test-Path -Path $script:BuildLogFile) { Remove-Item -Path $script:BuildLogFile } - - Write-BuildMsg -AsInfo -Message "Starting Open SSH build." - Write-BuildMsg -AsInfo -Message "Build Log: $($script:BuildLogFile)" + + Write-BuildMsg -AsInfo -Message "Starting Open SSH build; Build Log: $($script:BuildLogFile)" Start-SSHBootstrap @@ -338,20 +341,19 @@ function Start-SSHBuild Copy-OpenSSLSDK $msbuildCmd = "msbuild.exe" $solutionFile = Get-SolutionFile -root $repositoryRoot.FullName - $cmdMsg = @("${solutionFile}", "/p:Platform=${NativeHostArch}", "/p:Configuration=${Configuration}", "/fl", "/flp:LogFile=${script:BuildLogFile}`;Append`;Verbosity=diagnostic") + $cmdMsg = @("${solutionFile}", "/p:Platform=${NativeHostArch}", "/p:Configuration=${Configuration}", "/noconlog", "/nologo", "/fl", "/flp:LogFile=${script:BuildLogFile}`;Append`;Verbosity=diagnostic") + #$cmdMsg = @("${solutionFile}", "/p:Platform=${NativeHostArch}", "/p:Configuration=${Configuration}", "/nologo", "/fl", "/flp:LogFile=${script:BuildLogFile}`;Append`;Verbosity=diagnostic") - Write-Information -MessageData $msbuildCmd - Write-Information -MessageData $cmdMsg & $msbuildCmd $cmdMsg $errorCode = $LASTEXITCODE if ($errorCode -ne 0) { - Write-BuildMsg -AsError -ErrorAction Stop -Message "Build failed for OpenSSH.`nExitCode: $error" - } + Write-BuildMsg -AsError -ErrorAction Stop -Message "Build failed for OpenSSH.`nExitCode: $error." + } - Write-BuildMsg -AsVerbose -Message "Finished Open SSH build." + Write-BuildMsg -AsInfo -Message "SSH build passed." } function Get-BuildLogFile @@ -366,10 +368,10 @@ function Get-BuildLogFile [string]$NativeHostArch = "x64", [ValidateSet('Debug', 'Release', '')] - [string]$Configuration = "Debug" + [string]$Configuration = "Release" ) - return Join-Path -Path $root -ChildPath "contrib\win32\openssh\OpenSSH$($Configuration)$($NativeHostArch).log" + return Join-Path -Path $root -ChildPath "contrib\win32\openssh\OpenSSH$($Configuration)$($NativeHostArch).log" } function Get-SolutionFile @@ -414,4 +416,4 @@ function Get-RepositoryRoot throw new-object System.IO.DirectoryNotFoundException("Could not find the root of the GIT repository") } -Export-ModuleMember -Function Start-SSHBuild, Get-RepositoryRoot, Get-BuildLogFile, Clone-Win32OpenSSH, Copy-OpenSSLSDK \ No newline at end of file +Export-ModuleMember -Function Start-SSHBuild, Get-RepositoryRoot, Get-BuildLogFile, Clone-Win32OpenSSH, Copy-OpenSSLSDK, Write-BuildMsg \ No newline at end of file diff --git a/contrib/win32/openssh/version.rc b/contrib/win32/openssh/version.rc index 88c54b0faf5f2d19c0a0bf4d685eff0d1eb6ebed..f02930daf13317be87c93a20dfa5f770a25b5d5f 100644 GIT binary patch delta 45 zcmX>ne@=eGBo0RN$&)z@8O=8z<&b0oau#w+PhP;qG1-8JZ?XXQ1fax1Ze11tPJ#_d delta 45 zcmX>ne@=eGBo0Qi$&)z@8O=5y<&b0oau#w+PhP;qG1-8JZ?XXQ1fax1Ze11tP9P0M diff --git a/contrib/win32/win32compat/fileio.c b/contrib/win32/win32compat/fileio.c index 8d7ed26d..542c6072 100644 --- a/contrib/win32/win32compat/fileio.c +++ b/contrib/win32/win32compat/fileio.c @@ -37,6 +37,7 @@ #include #include #include "inc\utf.h" +#include "misc_internal.h" /* internal read buffer size */ #define READ_BUFFER_SIZE 100*1024 @@ -76,7 +77,7 @@ int fileio_pipe(struct w32_io* pio[2]) { HANDLE read_handle = INVALID_HANDLE_VALUE, write_handle = INVALID_HANDLE_VALUE; struct w32_io *pio_read = NULL, *pio_write = NULL; - char pipe_name[MAX_PATH]; + char pipe_name[PATH_MAX]; SECURITY_ATTRIBUTES sec_attributes; if (pio == NULL) { @@ -86,7 +87,7 @@ fileio_pipe(struct w32_io* pio[2]) { } /* create name for named pipe */ - if (-1 == sprintf_s(pipe_name, MAX_PATH, "\\\\.\\Pipe\\W32PosixPipe.%08x.%08x", + if (-1 == sprintf_s(pipe_name, PATH_MAX, "\\\\.\\Pipe\\W32PosixPipe.%08x.%08x", GetCurrentProcessId(), pipe_counter++)) { errno = EOTHER; debug("pipe - ERROR sprintf_s %d", errno); @@ -564,15 +565,15 @@ fileio_fstat(struct w32_io* pio, struct _stat64 *buf) { int fileio_stat(const char *path, struct _stat64 *buf) { - wchar_t wpath[MAX_PATH]; - wchar_t* wtmp = NULL; + wchar_t wpath[PATH_MAX]; + wchar_t* wtmp = NULL; - if ((wtmp = utf8_to_utf16(path)) == NULL) - fatal("failed to covert input arguments"); - wcscpy(&wpath[0], wtmp); - free(wtmp); + if ((wtmp = utf8_to_utf16(path)) == NULL) + fatal("failed to covert input arguments"); + wcscpy(&wpath[0], wtmp); + free(wtmp); - return _wstat64(wpath, buf); + return _wstat64(wpath, buf); } long @@ -597,8 +598,6 @@ fileio_fdopen(struct w32_io* pio, const char *mode) { debug2("fdopen - io:%p", pio); /* logic below doesn't work with overlapped file HANDLES */ - errno = ENOTSUP; - return NULL; if (mode[1] == '\0') { switch (*mode) { diff --git a/contrib/win32/win32compat/inc/dirent.h b/contrib/win32/win32compat/inc/dirent.h index a7408151..8ac3a598 100644 --- a/contrib/win32/win32compat/inc/dirent.h +++ b/contrib/win32/win32compat/inc/dirent.h @@ -10,10 +10,11 @@ #include #include #include +#include "..\misc_internal.h" struct dirent { int d_ino; /* Inode number */ - char d_name[256]; /* Null-terminated filename */ + char d_name[PATH_MAX]; /* Null-terminated filename */ }; typedef struct DIR_ DIR; diff --git a/contrib/win32/win32compat/inc/w32posix.h b/contrib/win32/win32compat/inc/w32posix.h index 7e7beeda..c265ae39 100644 --- a/contrib/win32/win32compat/inc/w32posix.h +++ b/contrib/win32/win32compat/inc/w32posix.h @@ -154,6 +154,8 @@ explicit_bzero(void *b, size_t len); /* string.h overrides */ #define strcasecmp _stricmp #define strncasecmp _strnicmp +char *w32_strerror(int); +#define strerror w32_strerror /* stdio.h overrides */ #define fopen w32_fopen_utf8 diff --git a/contrib/win32/win32compat/lsa/Ssh-lsa.c b/contrib/win32/win32compat/lsa/Ssh-lsa.c index 26a69c6f..103fdc25 100644 --- a/contrib/win32/win32compat/lsa/Ssh-lsa.c +++ b/contrib/win32/win32compat/lsa/Ssh-lsa.c @@ -38,6 +38,7 @@ #include #include #include +#include "..\misc_internal.h" #define Unsigned unsigned #define Char char @@ -264,7 +265,7 @@ LsaApLogonUser(PLSA_CLIENT_REQUEST request, SECURITY_LOGON_TYPE logonType, UNICODE_STRING *flatName = NULL; UCHAR *userAuth = NULL; ULONG userAuthSize; - wchar_t homeDir[MAX_PATH]; + wchar_t homeDir[PATH_MAX]; TOKEN_SOURCE tokenSource; HANDLE token = NULL; @@ -292,9 +293,9 @@ LsaApLogonUser(PLSA_CLIENT_REQUEST request, SECURITY_LOGON_TYPE logonType, *authority, &token, logonId, *accountName, subStat)); - NTFAIL(LsaApi.AllocateClientBuffer(request, MAX_PATH * sizeof(wchar_t), profile)); - *profileSize = MAX_PATH; - NTFAIL(LsaApi.CopyToClientBuffer(request, MAX_PATH * sizeof(wchar_t), + NTFAIL(LsaApi.AllocateClientBuffer(request, PATH_MAX * sizeof(wchar_t), profile)); + *profileSize = PATH_MAX; + NTFAIL(LsaApi.CopyToClientBuffer(request, PATH_MAX * sizeof(wchar_t), *profile, homeDir)); PLSA_TOKEN_INFORMATION_V1 outTokenInfo; diff --git a/contrib/win32/win32compat/misc.c b/contrib/win32/win32compat/misc.c index 32b2ddc8..80ca223c 100644 --- a/contrib/win32/win32compat/misc.c +++ b/contrib/win32/win32compat/misc.c @@ -37,6 +37,8 @@ #include #include #include "misc_internal.h" +#include "inc\dlfcn.h" +#include "inc\dirent.h" int usleep(unsigned int useconds) { @@ -114,51 +116,6 @@ explicit_bzero(void *b, size_t len) { SecureZeroMemory(b, len); } -int statvfs(const char *path, struct statvfs *buf) { - DWORD sectorsPerCluster; - DWORD bytesPerSector; - DWORD freeClusters; - DWORD totalClusters; - - if (GetDiskFreeSpace(path, §orsPerCluster, &bytesPerSector, - &freeClusters, &totalClusters) == TRUE) - { - debug3("path : [%s]", path); - debug3("sectorsPerCluster : [%lu]", sectorsPerCluster); - debug3("bytesPerSector : [%lu]", bytesPerSector); - debug3("bytesPerCluster : [%lu]", sectorsPerCluster * bytesPerSector); - debug3("freeClusters : [%lu]", freeClusters); - debug3("totalClusters : [%lu]", totalClusters); - - buf->f_bsize = sectorsPerCluster * bytesPerSector; - buf->f_frsize = sectorsPerCluster * bytesPerSector; - buf->f_blocks = totalClusters; - buf->f_bfree = freeClusters; - buf->f_bavail = freeClusters; - buf->f_files = -1; - buf->f_ffree = -1; - buf->f_favail = -1; - buf->f_fsid = 0; - buf->f_flag = 0; - buf->f_namemax = MAX_PATH - 1; - - return 0; - } - else - { - debug3("ERROR: Cannot get free space for [%s]. Error code is : %d.\n", - path, GetLastError()); - - return -1; - } -} - -int fstatvfs(int fd, struct statvfs *buf) { - errno = ENOTSUP; - return -1; -} - -#include "inc\dlfcn.h" HMODULE dlopen(const char *filename, int flags) { return LoadLibraryA(filename); } @@ -178,7 +135,7 @@ FARPROC dlsym(HMODULE handle, const char *symbol) { */ FILE* w32_fopen_utf8(const char *path, const char *mode) { - wchar_t wpath[MAX_PATH], wmode[5]; + wchar_t wpath[PATH_MAX], wmode[5]; FILE* f; char utf8_bom[] = { 0xEF,0xBB,0xBF }; char first3_bytes[3]; @@ -188,7 +145,7 @@ w32_fopen_utf8(const char *path, const char *mode) { return NULL; } - if (MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, MAX_PATH) == 0 || + if (MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, PATH_MAX) == 0 || MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, 5) == 0) { errno = EFAULT; debug("WideCharToMultiByte failed for %c - ERROR:%d", path, GetLastError()); @@ -480,10 +437,16 @@ strmode(mode_t mode, char *p) } int -w32_chmod(const char *pathname, mode_t mode) { - /* TODO - implement this */ - errno = EOPNOTSUPP; - return -1; +w32_chmod(const char *pathname, mode_t mode) { + int ret; + wchar_t *resolvedPathName_utf16 = utf8_to_utf16(sanitized_path(pathname)); + if (resolvedPathName_utf16 == NULL) { + errno = ENOMEM; + return -1; + } + ret = _wchmod(resolvedPathName_utf16, mode); + free(resolvedPathName_utf16); + return ret; } int @@ -493,20 +456,55 @@ w32_chown(const char *pathname, unsigned int owner, unsigned int group) { return -1; } +static void +unix_time_to_file_time(ULONG t, LPFILETIME pft) { + + ULONGLONG ull; + ull = UInt32x32To64(t, 10000000) + 116444736000000000; + + pft->dwLowDateTime = (DWORD)ull; + pft->dwHighDateTime = (DWORD)(ull >> 32); +} + +static int +settimes(wchar_t * path, FILETIME *cretime, FILETIME *acttime, FILETIME *modtime) { + HANDLE handle; + handle = CreateFileW(path, GENERIC_WRITE, FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + + if (handle == INVALID_HANDLE_VALUE) { + /* TODO - convert Win32 error to errno */ + errno = GetLastError(); + debug("w32_settimes - CreateFileW ERROR:%d", errno); + return -1; + } + + if (SetFileTime(handle, cretime, acttime, modtime) == 0) { + errno = GetLastError(); + debug("w32_settimes - SetFileTime ERROR:%d", errno); + CloseHandle(handle); + return -1; + } + + CloseHandle(handle); + return 0; +} + int w32_utimes(const char *filename, struct timeval *tvp) { - struct utimbuf ub; - ub.actime = tvp[0].tv_sec; - ub.modtime = tvp[1].tv_sec; int ret; - + FILETIME acttime, modtime; wchar_t *resolvedPathName_utf16 = utf8_to_utf16(sanitized_path(filename)); if (resolvedPathName_utf16 == NULL) { errno = ENOMEM; return -1; } + memset(&acttime, 0, sizeof(FILETIME)); + memset(&modtime, 0, sizeof(FILETIME)); - ret = _wutime(resolvedPathName_utf16, &ub); + unix_time_to_file_time((ULONG)tvp[0].tv_sec, &acttime); + unix_time_to_file_time((ULONG)tvp[1].tv_sec, &modtime); + ret = settimes(resolvedPathName_utf16, NULL, &acttime, &modtime); free(resolvedPathName_utf16); return ret; } @@ -535,6 +533,28 @@ w32_rename(const char *old_name, const char *new_name) { return -1; } + /* + * To be consistent with linux rename(), + * 1) if the new_name is file, then delete it so that _wrename will succeed. + * 2) if the new_name is directory and it is empty then delete it so that _wrename will succeed. + */ + struct _stat64 st; + if (fileio_stat(sanitized_path(new_name), &st) != -1) { + if(((st.st_mode & _S_IFMT) == _S_IFREG)) { + w32_unlink(new_name); + } else { + DIR *dirp = opendir(new_name); + if (NULL != dirp) { + struct dirent *dp = readdir(dirp); + closedir(dirp); + + if (dp == NULL) { + w32_rmdir(new_name); + } + } + } + } + int returnStatus = _wrename(resolvedOldPathName_utf16, resolvedNewPathName_utf16); free(resolvedOldPathName_utf16); free(resolvedNewPathName_utf16); @@ -587,10 +607,10 @@ w32_chdir(const char *dirname_utf8) { char * w32_getcwd(char *buffer, int maxlen) { - wchar_t wdirname[MAX_PATH]; + wchar_t wdirname[PATH_MAX]; char* putf8 = NULL; - _wgetcwd(&wdirname[0], MAX_PATH); + _wgetcwd(&wdirname[0], PATH_MAX); if ((putf8 = utf16_to_utf8(&wdirname[0])) == NULL) fatal("failed to convert input arguments"); @@ -609,8 +629,17 @@ w32_mkdir(const char *path_utf8, unsigned short mode) { return -1; } int returnStatus = _wmkdir(path_utf16); + if (returnStatus < 0) { + free(path_utf16); + return -1; + } + + mode_t curmask = _umask(0); + _umask(curmask); + + returnStatus = _wchmod(path_utf16, mode & ~curmask & (_S_IREAD | _S_IWRITE)); free(path_utf16); - + return returnStatus; } @@ -648,19 +677,25 @@ convertToForwardslash(char *str) { } /* -* This method will resolves references to /./, /../ and extra '/' characters in the null-terminated string named by -* path to produce a canonicalized absolute pathname. -*/ + * This method will resolves references to /./, /../ and extra '/' characters in the null-terminated string named by + * path to produce a canonicalized absolute pathname. + */ char * -realpath(const char *path, char resolved[MAX_PATH]) { - char tempPath[MAX_PATH]; +realpath(const char *path, char resolved[PATH_MAX]) { + char tempPath[PATH_MAX]; - if (*path == '/' && *(path + 2) == ':') + if ((path[0] == '/') && path[1] && (path[2] == ':')) { strncpy(resolved, path + 1, strlen(path)); // skip the first '/' - else + } else { strncpy(resolved, path, strlen(path) + 1); + } - if (_fullpath(tempPath, resolved, MAX_PATH) == NULL) + if ((resolved[0]) && (resolved[1] == ':') && (resolved[2] == '\0')) { // make "x:" as "x:\\" + resolved[2] = '\\'; + resolved[3] = '\0'; + } + + if (_fullpath(tempPath, resolved, PATH_MAX) == NULL) return NULL; convertToForwardslash(tempPath); @@ -670,6 +705,27 @@ realpath(const char *path, char resolved[MAX_PATH]) { return resolved; } +char* +sanitized_path(const char *path) { + static char newPath[PATH_MAX] = { '\0', }; + + if (path[0] == '/' && path[1]) { + if (path[2] == ':') { + if (path[3] == '\0') { // make "/x:" as "x:\\" + strncpy(newPath, path + 1, strlen(path) - 1); + newPath[2] = '\\'; + newPath[3] = '\0'; + + return newPath; + } else { + return (char *)(path + 1); // skip the first "/" + } + } + } + + return (char *)path; +} + // Maximum reparse buffer info size. The max user defined reparse // data is 16KB, plus there's a header. #define MAX_REPARSE_SIZE 17000 @@ -677,8 +733,7 @@ realpath(const char *path, char resolved[MAX_PATH]) { #define IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L) // winnt ntifs #define IO_REPARSE_TAG_HSM (0xC0000004L) // winnt ntifs #define IO_REPARSE_TAG_SIS (0x80000007L) // winnt ntifs -#define REPARSE_MOUNTPOINT_HEADER_SIZE 8 - +#define REPARSE_MOUNTPOINT_HEADER_SIZE 8 typedef struct _REPARSE_DATA_BUFFER { ULONG ReparseTag; @@ -778,4 +833,107 @@ ResolveLink(wchar_t * tLink, wchar_t *ret, DWORD * plen, DWORD Flags) { CloseHandle(fileHandle); return TRUE; -} \ No newline at end of file +} + +int statvfs(const char *path, struct statvfs *buf) { + DWORD sectorsPerCluster; + DWORD bytesPerSector; + DWORD freeClusters; + DWORD totalClusters; + + wchar_t* path_utf16 = utf8_to_utf16(sanitized_path(path)); + if (GetDiskFreeSpaceW(path_utf16, §orsPerCluster, &bytesPerSector, + &freeClusters, &totalClusters) == TRUE) + { + debug3("path : [%s]", path); + debug3("sectorsPerCluster : [%lu]", sectorsPerCluster); + debug3("bytesPerSector : [%lu]", bytesPerSector); + debug3("bytesPerCluster : [%lu]", sectorsPerCluster * bytesPerSector); + debug3("freeClusters : [%lu]", freeClusters); + debug3("totalClusters : [%lu]", totalClusters); + + buf->f_bsize = sectorsPerCluster * bytesPerSector; + buf->f_frsize = sectorsPerCluster * bytesPerSector; + buf->f_blocks = totalClusters; + buf->f_bfree = freeClusters; + buf->f_bavail = freeClusters; + buf->f_files = -1; + buf->f_ffree = -1; + buf->f_favail = -1; + buf->f_fsid = 0; + buf->f_flag = 0; + buf->f_namemax = PATH_MAX - 1; + + free(path_utf16); + return 0; + } + else + { + debug3("ERROR: Cannot get free space for [%s]. Error code is : %d.\n", + path, GetLastError()); + + free(path_utf16); + return -1; + } +} + +int fstatvfs(int fd, struct statvfs *buf) { + errno = ENOTSUP; + return -1; +} + +/* w32_strerror start */ +/* Windows CRT defines error string messages only till 43 in errno.h*/ +/* This is an extended list that defines messages for EADDRINUSE through EWOULDBLOCK*/ +char* _sys_errlist_ext[] = { + "Address already in use", // EADDRINUSE 100 + "Address not available", // EADDRNOTAVAIL 101 + "Address family not supported", // EAFNOSUPPORT 102 + "Connection already in progress", // EALREADY 103 + "Bad message", // EBADMSG 104 + "Operation canceled", // ECANCELED 105 + "Connection aborted", // ECONNABORTED 106 + "Connection refused", // ECONNREFUSED 107 + "Connection reset", // ECONNRESET 108 + "Destination address required", // EDESTADDRREQ 109 + "Host is unreachable", // EHOSTUNREACH 110 + "Identifier removed", // EIDRM 111 + "Operation in progress", // EINPROGRESS 112 + "Socket is connected", // EISCONN 113 + "Too many levels of symbolic links", // ELOOP 114 + "Message too long", // EMSGSIZE 115 + "Network is down", // ENETDOWN 116 + "Connection aborted by network", // ENETRESET 117 + "Network unreachable", // ENETUNREACH 118 + "No buffer space available", // ENOBUFS 119 + "No message is available on the STREAM head read queue", // ENODATA 120 + "Link has been severed", // ENOLINK 121 + "No message of the desired type", // ENOMSG 122 + "Protocol not available", // ENOPROTOOPT 123 + "No STREAM resources", // ENOSR 124 + "Not a STREAM", // ENOSTR 125 + "The socket is not connected", // ENOTCONN 126 + "enotecoverable", // ENOTRECOVERABLE 127 + "Not a socket", // ENOTSOCK 128 + "Operation not supported", // ENOTSUP 129 + "Operation not supported on socket", // EOPNOTSUPP 130 + "eother", // EOTHER 131 + "Value too large to be stored in data type", // EOVERFLOW 132 + "eownerdead", // EOWNERDEAD 133 + "Protocol error", // EPROTO 134 + "Protocol not supported", // EPROTONOSUPPORT 135 + "Protocol wrong type for socket", // EPROTOTYPE 136 + "Timer expired", // ETIME 137 + "Connection timed out", // ETIMEDOUT 138 + "Text file busy", // ETXTBSY 139 + "Operation would block" // EWOULDBLOCK 140 +}; + +char * +w32_strerror(int errnum) { + if (errnum >= EADDRINUSE && errnum <= EWOULDBLOCK) + return _sys_errlist_ext[errnum - EADDRINUSE]; + return strerror(errnum); +} + +/* w32_strerror end */ \ No newline at end of file diff --git a/contrib/win32/win32compat/misc_internal.h b/contrib/win32/win32compat/misc_internal.h index 0cd23692..f4b6d790 100644 --- a/contrib/win32/win32compat/misc_internal.h +++ b/contrib/win32/win32compat/misc_internal.h @@ -1,3 +1,4 @@ +#define PATH_MAX MAX_PATH /* removes first '/' for Windows paths that are unix styled. Ex: /c:/ab.cd */ -#define sanitized_path(p) (((p)[0] == '/' && (p)[1] != '\0' && (p)[2] == ':')? (p)+1 : (p)) \ No newline at end of file +char * sanitized_path(const char *); \ No newline at end of file diff --git a/contrib/win32/win32compat/pwd.c b/contrib/win32/win32compat/pwd.c index 9d0a4a79..9a80afa0 100644 --- a/contrib/win32/win32compat/pwd.c +++ b/contrib/win32/win32compat/pwd.c @@ -39,6 +39,7 @@ #include "inc\pwd.h" #include "inc\grp.h" #include "inc\utf.h" +#include "misc_internal.h" static struct passwd pw; static char* pw_shellpath = NULL; @@ -87,9 +88,9 @@ get_passwd(const char *user_utf8, LPWSTR user_sid) { char *uname_utf8 = NULL, *pw_home_utf8 = NULL; LPBYTE user_info = NULL; LPWSTR user_sid_local = NULL; - wchar_t reg_path[MAX_PATH], profile_home[MAX_PATH]; + wchar_t reg_path[PATH_MAX], profile_home[PATH_MAX]; HKEY reg_key = 0; - int tmp_len = MAX_PATH; + int tmp_len = PATH_MAX; PDOMAIN_CONTROLLER_INFOW pdc = NULL; errno = 0; @@ -141,10 +142,10 @@ get_passwd(const char *user_utf8, LPWSTR user_sid) { user_sid = user_sid_local; } - if (swprintf(reg_path, MAX_PATH, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\%ls", user_sid) == MAX_PATH || + if (swprintf(reg_path, PATH_MAX, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\%ls", user_sid) == PATH_MAX || RegOpenKeyExW(HKEY_LOCAL_MACHINE, reg_path, 0, STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_WOW64_64KEY, ®_key) != 0 || RegQueryValueExW(reg_key, L"ProfileImagePath", 0, NULL, (LPBYTE)profile_home, &tmp_len) != 0) - GetWindowsDirectoryW(profile_home, MAX_PATH); + GetWindowsDirectoryW(profile_home, PATH_MAX); if ((uname_utf8 = _strdup(user_utf8)) == NULL || (pw_home_utf8 = utf16_to_utf8(profile_home)) == NULL) { diff --git a/contrib/win32/win32compat/shell-host.c b/contrib/win32/win32compat/shell-host.c index dfd05295..06bde1ec 100644 --- a/contrib/win32/win32compat/shell-host.c +++ b/contrib/win32/win32compat/shell-host.c @@ -35,6 +35,7 @@ #include #include #include +#include "misc_internal.h" #define MAX_CONSOLE_COLUMNS 9999 #define MAX_CONSOLE_ROWS 9999 @@ -136,6 +137,7 @@ HANDLE pipe_in = INVALID_HANDLE_VALUE; HANDLE pipe_out = INVALID_HANDLE_VALUE; HANDLE pipe_err = INVALID_HANDLE_VALUE; HANDLE child = INVALID_HANDLE_VALUE; +DWORD child_exit_code = 0; HANDLE hConsoleBuffer = INVALID_HANDLE_VALUE; HANDLE monitor_thread = INVALID_HANDLE_VALUE; @@ -497,6 +499,7 @@ void SizeWindow(HANDLE hInput) { DWORD WINAPI MonitorChild(_In_ LPVOID lpParameter) { WaitForSingleObject(child, INFINITE); + GetExitCodeProcess(child, &child_exit_code); PostThreadMessage(hostThreadId, WM_APPEXIT, 0, 0); return 0; } @@ -1066,15 +1069,15 @@ int start_with_pty(int ac, wchar_t **av) { /*TODO - pick this up from system32*/ cmd[0] = L'\0'; if (ac) - GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_PATH, L"cmd.exe")); + GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, PATH_MAX, L"cmd.exe")); ac--; av++; if (ac) - GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_PATH, L" /c")); + GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, PATH_MAX, L" /c")); while (ac) { - GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_PATH, L" ")); - GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_PATH, *av)); + GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, PATH_MAX, L" ")); + GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, PATH_MAX, *av)); ac--; av++; } @@ -1088,8 +1091,7 @@ int start_with_pty(int ac, wchar_t **av) { Sleep(20); while (!AttachConsole(pi.dwProcessId)) { - DWORD exit_code; - if (GetExitCodeProcess(pi.hProcess, &exit_code) && exit_code != STILL_ACTIVE) + if (GetExitCodeProcess(pi.hProcess, &child_exit_code) && child_exit_code != STILL_ACTIVE) break; Sleep(100); } @@ -1129,7 +1131,7 @@ int start_with_pty(int ac, wchar_t **av) { FreeConsole(); - return 0; + return child_exit_code; } HANDLE child_pipe_read; @@ -1138,6 +1140,7 @@ DWORD WINAPI MonitorChild_nopty( _In_ LPVOID lpParameter ) { WaitForSingleObject(child, INFINITE); + GetExitCodeProcess(child, &child_exit_code); CloseHandle(pipe_in); //printf("XXXX CHILD PROCESS DEAD XXXXX"); return 0; @@ -1180,14 +1183,14 @@ int start_withno_pty(int ac, wchar_t **av) { /*TODO - pick this up from system32*/ cmd[0] = L'\0'; - GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_PATH, L"cmd.exe")); + GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, PATH_MAX, L"cmd.exe")); ac -= 2; av += 2; if (ac) - GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_PATH, L" /c")); + GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, PATH_MAX, L" /c")); while (ac) { - GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_PATH, L" ")); - GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_PATH, *av)); + GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, PATH_MAX, L" ")); + GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, PATH_MAX, *av)); ac--; av++; } @@ -1282,7 +1285,7 @@ int start_withno_pty(int ac, wchar_t **av) { TerminateProcess(child, 0); if (monitor_thread != INVALID_HANDLE_VALUE) WaitForSingleObject(monitor_thread, INFINITE); - return 0; + return child_exit_code; } int wmain(int ac, wchar_t **av) { diff --git a/contrib/win32/win32compat/signal.c b/contrib/win32/win32compat/signal.c index 8a74da9a..d84f5412 100644 --- a/contrib/win32/win32compat/signal.c +++ b/contrib/win32/win32compat/signal.c @@ -258,7 +258,7 @@ wait_for_any_event(HANDLE* events, int num_events, DWORD milli_seconds) if ((ret >= WAIT_OBJECT_0) && (ret <= WAIT_OBJECT_0 + num_all_events - 1)) { //woken up by event signalled /* is this due to a child process going down*/ - if (children.num_children && ((ret - WAIT_OBJECT_0) < children.num_children)) { + if (live_children && ((ret - WAIT_OBJECT_0) < live_children)) { sigaddset(&pending_signals, W32_SIGCHLD); sw_child_to_zombie(ret - WAIT_OBJECT_0); } diff --git a/contrib/win32/win32compat/signal_internal.h b/contrib/win32/win32compat/signal_internal.h index 826ca957..4bd7f209 100644 --- a/contrib/win32/win32compat/signal_internal.h +++ b/contrib/win32/win32compat/signal_internal.h @@ -11,12 +11,17 @@ int sw_kill(int pid, int sig); /* child processes */ #define MAX_CHILDREN 50 struct _children { + /* + * array of handles and process_ids. + * intial (num_children - num_zombies) are alive + * rest are zombies + */ HANDLE handles[MAX_CHILDREN]; DWORD process_id[MAX_CHILDREN]; /* total children */ DWORD num_children; /* #zombies */ - /* (num_chileren - zombies) are live children */ + /* (num_children - zombies) are live children */ DWORD num_zombies; }; diff --git a/contrib/win32/win32compat/signal_sigchld.c b/contrib/win32/win32compat/signal_sigchld.c index afd0242f..53c6c2d7 100644 --- a/contrib/win32/win32compat/signal_sigchld.c +++ b/contrib/win32/win32compat/signal_sigchld.c @@ -101,7 +101,7 @@ sw_remove_child_at_index(DWORD index) { int sw_child_to_zombie(DWORD index) { - DWORD last_non_zombie, last_child, zombie_pid; + DWORD last_non_zombie, zombie_pid; HANDLE zombie_handle; debug("zombie'ing child at index %d, %d zombies of %d", index, @@ -112,17 +112,17 @@ sw_child_to_zombie(DWORD index) { return -1; } - zombie_pid = children.process_id[index]; - zombie_handle = children.handles[index]; last_non_zombie = children.num_children - children.num_zombies - 1; - last_child = children.num_children - 1; - - children.handles[index] = children.handles[last_non_zombie]; - children.process_id[index] = children.process_id[last_non_zombie]; - - children.handles[last_non_zombie] = children.handles[index]; - children.process_id[last_non_zombie] = children.process_id[index]; - + + if (last_non_zombie != index) { + /* swap */ + zombie_pid = children.process_id[index]; + zombie_handle = children.handles[index]; + children.handles[index] = children.handles[last_non_zombie]; + children.process_id[index] = children.process_id[last_non_zombie]; + children.handles[last_non_zombie] = zombie_handle; + children.process_id[last_non_zombie] = zombie_pid; + } children.num_zombies++; return 0; } @@ -185,10 +185,13 @@ int waitpid(int pid, int *status, int options) { return -1; } - process = children.handles[index]; - ret = WaitForSingleObject(process, INFINITE); - if (ret != WAIT_OBJECT_0) - DebugBreak();//fatal + /* wait if process is still alive */ + if (index < children.num_children - children.num_zombies) { + process = children.handles[index]; + ret = WaitForSingleObject(process, INFINITE); + if (ret != WAIT_OBJECT_0) + DebugBreak();//fatal + } ret_id = children.process_id[index]; GetExitCodeProcess(process, &exit_code); @@ -200,6 +203,15 @@ int waitpid(int pid, int *status, int options) { } /* pid = -1*/ + /* are there any existing zombies */ + if (children.num_zombies) { + /* return one of them */ + ret_id = children.process_id[children.num_children - 1]; + sw_remove_child_at_index(children.num_children - 1); + return ret_id; + } + + /* all children are alive. wait for one of them to exit */ timeout = INFINITE; if (options & WNOHANG) timeout = 0; diff --git a/contrib/win32/win32compat/ssh-agent/agent.c b/contrib/win32/win32compat/ssh-agent/agent.c index 62e625d9..b97227a7 100644 --- a/contrib/win32/win32compat/ssh-agent/agent.c +++ b/contrib/win32/win32compat/ssh-agent/agent.c @@ -31,6 +31,7 @@ #include "agent.h" #include #include +#include "..\misc_internal.h" #define BUFSIZE 5 * 1024 static HANDLE ioc_port = NULL; @@ -179,15 +180,15 @@ agent_listen_loop() { } else { /* spawn a child to take care of this*/ - wchar_t path[MAX_PATH], module_path[MAX_PATH]; + wchar_t path[PATH_MAX], module_path[PATH_MAX]; PROCESS_INFORMATION pi; STARTUPINFOW si; si.cb = sizeof(STARTUPINFOW); memset(&si, 0, sizeof(STARTUPINFOW)); - GetModuleFileNameW(NULL, module_path, MAX_PATH); + GetModuleFileNameW(NULL, module_path, PATH_MAX); SetHandleInformation(con, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); - if ((swprintf_s(path, MAX_PATH, L"%s %d", module_path, (int)(intptr_t)con) == -1 ) || + if ((swprintf_s(path, PATH_MAX, L"%s %d", module_path, (int)(intptr_t)con) == -1 ) || (CreateProcessW(NULL, path, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &si, &pi) == FALSE)) { diff --git a/contrib/win32/win32compat/ssh-agent/agentconfig.c b/contrib/win32/win32compat/ssh-agent/agentconfig.c index ec261be7..9761a02c 100644 --- a/contrib/win32/win32compat/ssh-agent/agentconfig.c +++ b/contrib/win32/win32compat/ssh-agent/agentconfig.c @@ -87,15 +87,15 @@ int GetCurrentModulePath(wchar_t *path, int pathSize) } int load_config() { - wchar_t basePath[MAX_PATH] = { 0 }; - wchar_t path[MAX_PATH] = { 0 }; + wchar_t basePath[PATH_MAX] = { 0 }; + wchar_t path[PATH_MAX] = { 0 }; /* TODO - account for UNICODE paths*/ - if (GetCurrentModulePath(basePath, MAX_PATH) == -1) + if (GetCurrentModulePath(basePath, PATH_MAX) == -1) return -1; - wcsncpy(path, basePath, MAX_PATH); - wcsncat(path, L"/sshd_config", MAX_PATH); + wcsncpy(path, basePath, PATH_MAX); + wcsncat(path, L"/sshd_config", PATH_MAX); if ((config_file_name = utf16_to_utf8(path)) == NULL) return -1; diff --git a/contrib/win32/win32compat/ssh-agent/authagent-request.c b/contrib/win32/win32compat/ssh-agent/authagent-request.c index 0cacbe60..a9e24ec7 100644 --- a/contrib/win32/win32compat/ssh-agent/authagent-request.c +++ b/contrib/win32/win32compat/ssh-agent/authagent-request.c @@ -318,7 +318,7 @@ int process_pubkeyauth_request(struct sshbuf* request, struct sshbuf* response, if (SHGetKnownFolderPath(&FOLDERID_Profile, 0, token, &wuser_home) != S_OK || pubkey_allowed(key, wuser, wuser_home) != 1) { - debug("given public key is not mapped to user %ls (profile:%ls)", wuser, wuser_home); + debug("unable to verify public key for user %ls (profile:%ls)", wuser, wuser_home); goto done; } diff --git a/contrib/win32/win32compat/w32log.c b/contrib/win32/win32compat/w32log.c index 06f2f4b4..d23e2ef6 100644 --- a/contrib/win32/win32compat/w32log.c +++ b/contrib/win32/win32compat/w32log.c @@ -1,43 +1,79 @@ +/* +* Copyright (c) 2016 Microsoft Corp. +* All rights reserved +* +* Implementation of sys log for windows: +* openlog(), closelog, syslog +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + #include #include #include #include #include "inc\syslog.h" +#include "misc_internal.h" #define MSGBUFSIZ 1024 static int logfd = -1; -void openlog(char *ident, unsigned int option, int facility) { - if ((logfd == -1) && (ident != NULL)) { - wchar_t path[MAX_PATH], log_file[MAX_PATH + 12]; - if (GetModuleFileNameW(NULL, path, MAX_PATH) == 0) - return; - path[MAX_PATH - 1] = '\0'; - /* split path root and module */ - { - wchar_t* tail = path + wcslen(path), *p; - while (tail > path && *tail != L'\\' && *tail != L'/') - tail--; - - memcpy(log_file, path, (tail - path) * sizeof(wchar_t)); - p = log_file + (tail - path); - memcpy(p, L"\\logs\\", 12); - p += 6; - memcpy(p, tail + 1, (wcslen(tail + 1) - 3) * sizeof(wchar_t)); - p += wcslen(tail + 1) - 3; - memcpy(p, L"log\0", 8); - } - logfd = _wopen(log_file, O_WRONLY | O_CREAT | O_APPEND, - S_IREAD | S_IWRITE); - if (logfd != -1) - SetHandleInformation((HANDLE)_get_osfhandle(logfd), - HANDLE_FLAG_INHERIT, 0); +void +openlog(char *ident, unsigned int option, int facility) { + if (logfd != -1 || ident == NULL) + return; + + wchar_t path[PATH_MAX], log_file[PATH_MAX + 12]; + if (GetModuleFileNameW(NULL, path, PATH_MAX) == 0) + + return; + path[PATH_MAX - 1] = '\0'; + + /* split path root and module */ + { + wchar_t* tail = path + wcslen(path), *p; + while (tail > path && *tail != L'\\' && *tail != L'/') + tail--; + + memcpy(log_file, path, (tail - path) * sizeof(wchar_t)); + p = log_file + (tail - path); + memcpy(p, L"\\logs\\", 12); + p += 6; + memcpy(p, tail + 1, (wcslen(tail + 1) - 3) * sizeof(wchar_t)); + p += wcslen(tail + 1) - 3; + memcpy(p, L"log\0", 8); } + + logfd = _wopen(log_file, O_WRONLY | O_CREAT | O_APPEND, + S_IREAD | S_IWRITE); + if (logfd != -1) + SetHandleInformation((HANDLE)_get_osfhandle(logfd), + HANDLE_FLAG_INHERIT, 0); } -void closelog(void) { - //NOOP +void +closelog(void) { + /*NOOP*/ } void diff --git a/contrib/win32/win32compat/win32_dirent.c b/contrib/win32/win32compat/win32_dirent.c index 2418e13d..dcfe77a2 100644 --- a/contrib/win32/win32compat/win32_dirent.c +++ b/contrib/win32/win32compat/win32_dirent.c @@ -27,7 +27,7 @@ DIR * opendir(const char *name) struct _wfinddata_t c_file; intptr_t hFile; DIR *pdir; - wchar_t searchstr[MAX_PATH]; + wchar_t searchstr[PATH_MAX]; wchar_t* wname = NULL; int needed; @@ -37,7 +37,7 @@ DIR * opendir(const char *name) } // add *.* for Windows _findfirst() search pattern - swprintf_s(searchstr, MAX_PATH, L"%s\\*.*", wname); + swprintf_s(searchstr, PATH_MAX, L"%s\\*.*", wname); free(wname); if ((hFile = _wfindfirst(searchstr, &c_file)) == -1L) @@ -77,7 +77,7 @@ int closedir(DIR *dirp) by a later readdir call on the same DIR stream. */ struct dirent *readdir(void *avp) { - struct dirent *pdirentry; + static struct dirent pdirentry; struct _wfinddata_t c_file; DIR *dirp = (DIR *)avp; char *tmp = NULL; @@ -92,19 +92,18 @@ struct dirent *readdir(void *avp) if (wcscmp(c_file.name, L".") == 0 || wcscmp(c_file.name, L"..") == 0 ) continue; - - if ((pdirentry = malloc(sizeof(struct dirent))) == NULL || - (tmp = utf16_to_utf8(c_file.name)) == NULL) { + + if ((tmp = utf16_to_utf8(c_file.name)) == NULL) { errno = ENOMEM; return NULL; } - strncpy(pdirentry->d_name, tmp, strlen(tmp) + 1); + strncpy(pdirentry.d_name, tmp, strlen(tmp) + 1); free(tmp); - pdirentry->d_ino = 1; // a fictious one like UNIX to say it is nonzero - return pdirentry ; - } + pdirentry.d_ino = 1; // a fictious one like UNIX to say it is nonzero + return &pdirentry ; + } } // return last part of a path. The last path being a filename. @@ -123,4 +122,3 @@ char *basename(char *path) return path; // path does not have a slash } -// end of dirent functions in Windows diff --git a/contrib/win32/win32compat/wmain_sshd.c b/contrib/win32/win32compat/wmain_sshd.c index 7a812f0f..4f2e5d75 100644 --- a/contrib/win32/win32compat/wmain_sshd.c +++ b/contrib/win32/win32compat/wmain_sshd.c @@ -112,8 +112,12 @@ int sshd_main(int argc, wchar_t **wargv) { w32posix_initialize(); if (getenv("SSHD_REMSOC")) is_child = 1; + /* change current directory to sshd.exe root */ - _wchdir(utf8_to_utf16(w32_programdir())); + wchar_t* path_utf16 = utf8_to_utf16(w32_programdir()); + _wchdir(path_utf16); + free(path_utf16); + return main(argc, argv); } diff --git a/regress/pesterTests/PlatformAbstractLayer.psm1 b/regress/pesterTests/PlatformAbstractLayer.psm1 index 8b5d6639..7b0683f7 100644 --- a/regress/pesterTests/PlatformAbstractLayer.psm1 +++ b/regress/pesterTests/PlatformAbstractLayer.psm1 @@ -85,7 +85,7 @@ Class Machine [string] $ClientKeyDirectory [string] $knownHostOfCurrentUser [string] $OpenSSHdir = $PSScriptRoot - [string] $ToolsPath = "$env:ProgramData\chocolatey\lib\sysinternals\tools" + [string] $ToolsPath = "$env:ProgramData\chocolatey\lib\sysinternals\tools" Machine() { $this.Platform = Set-Platform @@ -106,13 +106,13 @@ Class Machine } [void] InitializeClient() { - $this.ClientKeyDirectory = join-path ($env:USERPROFILE) ".ssh" + $this.ClientKeyDirectory = join-path $PSScriptRoot "clientkeys" if(-not (Test-path $this.ClientKeyDirectory -PathType Container)) { New-Item -Path $this.ClientKeyDirectory -ItemType Directory -Force -ErrorAction silentlycontinue } - Remove-Item -Path "$($this.ClientKeyDirectory)\*" -Force -ea silentlycontinue + Remove-Item -Path "$($this.ClientKeyDirectory)\*" -Force -ea silentlycontinue $this.knownHostOfCurrentUser = join-path ($env:USERPROFILE) ".ssh/known_hosts" @@ -131,8 +131,7 @@ Class Machine $this.clientPrivateKeyPaths += $keyPath $this.clientPublicKeyPaths += "$keyPath.pub" $str = ".\ssh-keygen -t $key -P """" -f $keyPath" - $this.RunCmd($str) - + $this.RunCmd($str) } } @@ -211,16 +210,27 @@ Class Machine } } - [void] CleanupServer() { - Remove-Item -Path $this.localAdminAuthorizedKeyPath -Force -ea silentlycontinue + [void] CleanupServer() { + $sshPath = split-path $this.localAdminAuthorizedKeyPath -Parent + if(Test-Path $sshPath -PathType Container ) + { + Remove-item -path $sshPath -force -Recurse + } + if ( $this.Platform -eq [PlatformType]::Windows ) { $this.CleanupLocalAccountTokenFilterPolicy() } } - [void] CleanupClient() { - Remove-Item -Path "$this.clientKeyPath\*" -Force -ea silentlycontinue + [void] CleanupClient() { + Remove-item -path $($this.ClientKeyDirectory) -force -Recurse -ea silentlycontinue + $sshPath = split-path $this.knownHostOfCurrentUser -Parent + if(Test-Path $sshPath -PathType Container ) + { + Remove-item -path $sshPath -force -Recurse + } + $this.CleanupPasswordSetting() } [void] RunCmd($Str) { @@ -248,6 +258,19 @@ Class Machine } } + [void] AddPasswordSetting([string] $pass) { + if ($this.Platform -eq [PlatformType]::Windows) { + $env:SSH_ASKPASS="$($env:ComSpec) /c echo $pass" + } + } + + [void] CleanupPasswordSetting() { + if ($this.Platform -eq [PlatformType]::Windows -and (Test-Path env:SSH_ASKPASS)) + { + remove-item "env:SSH_ASKPASS" -ErrorAction SilentlyContinue + } + } + #Set LocalAccountTokenFilterPolicy [void] SetLocalAccountTokenFilterPolicy($setting) { $path = "HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\system" @@ -308,6 +331,7 @@ Class Machine $shell_app = $null } + #this does not work when "using module"; works fine when import the module [void] DownloadPStools() { $machinePath = [Environment]::GetEnvironmentVariable('Path', 'MACHINE') diff --git a/regress/pesterTests/SCP.Tests.ps1 b/regress/pesterTests/SCP.Tests.ps1 index 7e9a4d64..9e64e2b7 100644 --- a/regress/pesterTests/SCP.Tests.ps1 +++ b/regress/pesterTests/SCP.Tests.ps1 @@ -98,31 +98,30 @@ Describe "Tests for scp command" -Tags "CI" { It 'SCP usage' { #TODO: usage output does not redirect to file } - }#> - - #this context only run on windows + }#> + Context "Key is Secured in ssh-agent on server" { BeforeAll { $Server.SecureHostKeys($server.PrivateHostKeyPaths) - $identifyFile = $client.clientPrivateKeyPaths[0] + $privateKeyFile = $client.clientPrivateKeyPaths[0] } AfterAll { $Server.CleanupHostKeys() } - It 'File Copy with -i option: ' -TestCases:$testData { + It 'File copy with -i option and private key: <Title> ' -TestCases:$testData { param([string]$Title, $Source, $Destination) - .\scp -i $identifyFile $Source $Destination + .\scp -i $privateKeyFile $Source $Destination #validate file content. DestPath is the path to the file. $equal = @(Compare-Object (Get-ChildItem -path $SourceFilePath) (Get-ChildItem -path $DestinationFilePath) -Property Name, Length).Length -eq 0 $equal | Should Be $true - } + } - It 'Directory recursive Copy with -i option: <Title> ' -TestCases:$testData1 { + It 'Directory recursive copy with -i option and private key: <Title> ' -TestCases:$testData1 { param([string]$Title, $Source, $Destination) - .\scp -r -i $identifyFile $Source $Destination + .\scp -r -i $privateKeyFile $Source $Destination $equal = @(Compare-Object (Get-Item -path $SourceDir ) (Get-Item -path (join-path $DestinationDir $SourceDirName) ) -Property Name, Length).Length -eq 0 $equal | Should Be $true @@ -130,10 +129,9 @@ Describe "Tests for scp command" -Tags "CI" { $equal = @(Compare-Object (Get-ChildItem -Recurse -path $SourceDir) (Get-ChildItem -Recurse -path (join-path $DestinationDir $SourceDirName) ) -Property Name, Length).Length -eq 0 $equal | Should Be $true - } + } } - - #this context only run on windows + Context "Single signon with keys -p -v -c option Secured in ssh-agent" { BeforeAll { $Server.SecureHostKeys($server.PrivateHostKeyPaths) @@ -149,27 +147,27 @@ Describe "Tests for scp command" -Tags "CI" { .\ssh-add.exe -D } - It 'File Copy with -S option (positive)' { + It 'File copy with -S option (positive)' { .\scp -S .\ssh.exe $SourceFilePath "$($server.localAdminUserName)@$($server.MachineName):$DestinationFilePath" #validate file content. DestPath is the path to the file. $equal = @(Compare-Object (Get-ChildItem -path $SourceFilePath) (Get-ChildItem -path $DestinationFilePath) -Property Name, Length).Length -eq 0 $equal | Should Be $true } - It 'File Copy with -p -c -v option: <Title> ' -TestCases:$testData { + It 'File copy with -p -c -v option: <Title> ' -TestCases:$testData { param([string]$Title, $Source, $Destination) - .\scp -p -c aes128-ctr -v -C $Source $Destination + .\scp -p -c aes128-ctr -v -C $Source $Destination #validate file content. DestPath is the path to the file. $equal = @(Compare-Object (Get-ChildItem -path $SourceFilePath) (Get-ChildItem -path $DestinationFilePath) -Property Name, Length, LastWriteTime.DateTime).Length -eq 0 $equal | Should Be $true } - It 'Directory recursive Copy with -r -p -v option: <Title> ' -TestCases:$testData1 { + It 'Directory recursive copy with -r -p -v option: <Title> ' -TestCases:$testData1 { param([string]$Title, $Source, $Destination) .\scp -r -p -c aes128-ctr -v $Source $Destination - $equal = @(Compare-Object (Get-Item -path $SourceDir ) (Get-Item -path (join-path $DestinationDir $SourceDirName) ) -Property Name, Length).Length -eq 0 + $equal = @(Compare-Object (Get-Item -path $SourceDir ) (Get-Item -path (join-path $DestinationDir $SourceDirName) ) -Property Name, Length, LastWriteTime.DateTime).Length -eq 0 $equal | Should Be $true $equal = @(Compare-Object (Get-ChildItem -Recurse -path $SourceDir) (Get-ChildItem -Recurse -path (join-path $DestinationDir $SourceDirName) ) -Property Name, Length, LastWriteTime.DateTime).Length -eq 0 @@ -177,12 +175,12 @@ Describe "Tests for scp command" -Tags "CI" { } } - Context "Key based authentication with -i -C -q options. host keys are not secured on server" { + Context "Private key authentication with -i -C -q options. host keys are not secured on server" { BeforeAll { $identifyFile = $client.clientPrivateKeyPaths[0] } - It 'File Copy with -i -C -q options: <Title> ' -TestCases:$testData{ + It 'File copy with -i -C -q options: <Title> ' -TestCases:$testData{ param([string]$Title, $Source, $Destination) .\scp -i $identifyFile -C -q $Source $Destination @@ -191,16 +189,45 @@ Describe "Tests for scp command" -Tags "CI" { $equal | Should Be $true } - - It 'Directory recursive Copy with -i and -q options: <Title> ' -TestCases:$testData1 { + It 'Directory recursive copy with -i -C -r and -q options: <Title> ' -TestCases:$testData1 { param([string]$Title, $Source, $Destination) - .\scp -i $identifyFile -r -q $Source $Destination + .\scp -i $identifyFile -C -r -q $Source $Destination $equal = @(Compare-Object (Get-Item -path $SourceDir ) (Get-Item -path (join-path $DestinationDir $SourceDirName) ) -Property Name, Length).Length -eq 0 $equal | Should Be $true $equal = @(Compare-Object (Get-ChildItem -Recurse -path $SourceDir) (Get-ChildItem -Recurse -path (join-path $DestinationDir $SourceDirName) ) -Property Name, Length).Length -eq 0 $equal | Should Be $true } - } + } + + Context "Password authentication" { + BeforeAll { + $client.AddPasswordSetting($server.localAdminPassword) + } + + AfterAll { + $client.CleanupPasswordSetting() + } + + It 'File copy with -p options: <Title> ' -TestCases:$testData { + param([string]$Title, $Source, $Destination) + + .\scp -p $Source $Destination + #validate file content. DestPath is the path to the file. + $equal = @(Compare-Object (Get-ChildItem -path $SourceFilePath) (Get-ChildItem -path $DestinationFilePath) -Property Name, Length, LastWriteTime.DateTime).Length -eq 0 + $equal | Should Be $true + } + + It 'Directory recursive copy with -p and -v options: <Title> ' -TestCases:$testData1 { + param([string]$Title, $Source, $Destination) + + .\scp -r -p $Source $Destination + $equal = @(Compare-Object (Get-Item -path $SourceDir ) (Get-Item -path (join-path $DestinationDir $SourceDirName) ) -Property Name, Length, LastWriteTime.DateTime).Length -eq 0 + $equal | Should Be $true + + $equal = @(Compare-Object (Get-ChildItem -Recurse -path $SourceDir) (Get-ChildItem -Recurse -path (join-path $DestinationDir $SourceDirName) ) -Property Name, Length, LastWriteTime.DateTime).Length -eq 0 + $equal | Should Be $true + } + } } diff --git a/regress/pesterTests/SSH.Tests.ps1 b/regress/pesterTests/SSH.Tests.ps1 index 0b399906..01790d18 100644 --- a/regress/pesterTests/SSH.Tests.ps1 +++ b/regress/pesterTests/SSH.Tests.ps1 @@ -135,5 +135,28 @@ Describe "Tests for ssh command" -Tags "CI" { #validate file content. Get-Content $filePath | Should be $server.MachineName } - } + } + Context "password authentication" { + BeforeAll { + $client.AddPasswordSetting($server.localAdminPassword) + Remove-Item -Path $filePath -Force -ea silentlycontinue + } + + AfterAll { + $client.CleanupPasswordSetting() + } + + AfterEach { + Remove-Item -Path $filePath -Force -ea silentlycontinue + } + + It '<Title>' -TestCases:$testData { + param([string]$Title, $LogonStr, $Options) + + $str = ".\ssh $($Options) $($LogonStr) hostname > $filePath" + $client.RunCmd($str) + #validate file content. + Get-Content $filePath | Should be $server.MachineName + } + } } diff --git a/scp.c b/scp.c index e65b4663..f0cff40b 100644 --- a/scp.c +++ b/scp.c @@ -595,12 +595,17 @@ main(int argc, char **argv) #ifdef WINDOWS /* * To support both Windows and Unix style paths - * convert '\\' to '/' in rest of arguments + * convert '\\' to '/' in path portion of rest arguments */ { int i; - for (i = 0; i < argc; i++) - convertToForwardslash(argv[i]); + char *p; + for (i = 0; i < argc; i++) { + if(p = colon(argv[i])) + convertToForwardslash(p); + else + convertToForwardslash(argv[i]); + } } #endif /* WINDOWS */ diff --git a/sftp-client.c b/sftp-client.c index e65c15c8..d47be0ea 100644 --- a/sftp-client.c +++ b/sftp-client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp-client.c,v 1.125 2016/09/12 01:22:38 deraadt Exp $ */ +/* $OpenBSD: sftp-client.c,v 1.126 2017/01/03 05:46:51 djm Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> * @@ -587,6 +587,8 @@ do_lsreaddir(struct sftp_conn *conn, const char *path, int print_flag, if ((r = sshbuf_get_u32(msg, &count)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); + if (count > SSHBUF_SIZE_MAX) + fatal("%s: nonsensical number of entries", __func__); if (count == 0) break; debug3("Received %d SSH2_FXP_NAME responses", count); diff --git a/sftp.c b/sftp.c index 9910fda3..d1f3ffa4 100644 --- a/sftp.c +++ b/sftp.c @@ -320,12 +320,16 @@ static void local_do_shell(const char *args) { #ifdef WINDOWS - /* execute via system call in Windows*/ - if (!*args) { - /* TODO - support unicode ComSpec */ + /* execute via system call in Windows*/ + if (!*args) { args = (char *) getenv("ComSpec"); // get name of Windows cmd shell + } else { + convertToBackslash((char *) args); } - system(args); // execute the shell or cmd given + + wchar_t* path_utf16 = utf8_to_utf16(args); + _wsystem(path_utf16); // execute the shell or cmd given + free(path_utf16); #else /* !WINDOWS */ int status; char *shell; @@ -1513,7 +1517,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, * convert '\\' to '/' in Windows styled paths. * else they get treated as escape sequence in makeargv */ - convertToForwardslash(cmd); + convertToForwardslash((char *)cmd); #endif cmdnum = parse_args(&cmd, &ignore_errors, &aflag, &fflag, &hflag, &iflag, &lflag, &pflag, &rflag, &sflag, &n_arg, &path1, &path2); @@ -2334,7 +2338,7 @@ connect_to_server(char *path, char **args, int *in, int *out) /* disable inheritance on local pipe ends*/ fcntl(pout[1], F_SETFD, FD_CLOEXEC); fcntl(pin[0], F_SETFD, FD_CLOEXEC); - + sshpid = spawn_child(full_cmd, c_in, c_out, STDERR_FILENO, 0); free(full_cmd); } diff --git a/ssh-agent.c b/ssh-agent.c index 39521355..1320cdaa 100644 --- a/ssh-agent.c +++ b/ssh-agent.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-agent.c,v 1.215 2016/11/30 03:07:37 djm Exp $ */ +/* $OpenBSD: ssh-agent.c,v 1.216 2017/01/04 02:21:43 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -89,7 +89,7 @@ #endif #ifndef DEFAULT_PKCS11_WHITELIST -# define DEFAULT_PKCS11_WHITELIST "/usr/lib/*,/usr/local/lib/*" +# define DEFAULT_PKCS11_WHITELIST "/usr/lib*/*,/usr/local/lib*/*" #endif typedef enum { diff --git a/ssh-keygen.c b/ssh-keygen.c index 0dcfb562..07344687 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c @@ -221,7 +221,11 @@ type_bits_valid(int type, const char *name, u_int32_t *bitsp) fatal("Key must at least be 1024 bits"); else if (type == KEY_ECDSA && sshkey_ecdsa_bits_to_nid(*bitsp) == -1) fatal("Invalid ECDSA key length - valid lengths are " +#ifdef OPENSSL_HAS_NISTP521 "256, 384 or 521 bits"); +#else + "256 or 384 bits"); +#endif #endif }