diff --git a/Makefile.in b/Makefile.in index e10f374..5870e9e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -236,6 +236,8 @@ clean: regressclean rm -f regress/unittests/sshkey/test_sshkey rm -f regress/unittests/bitmap/*.o rm -f regress/unittests/bitmap/test_bitmap + rm -f regress/unittests/conversion/*.o + rm -f regress/unittests/conversion/test_conversion rm -f regress/unittests/hostkeys/*.o rm -f regress/unittests/hostkeys/test_hostkeys rm -f regress/unittests/kex/*.o @@ -262,6 +264,8 @@ distclean: regressclean rm -f regress/unittests/sshkey/test_sshkey rm -f regress/unittests/bitmap/*.o rm -f regress/unittests/bitmap/test_bitmap + rm -f regress/unittests/conversion/*.o + rm -f regress/unittests/conversion/test_conversion rm -f regress/unittests/hostkeys/*.o rm -f regress/unittests/hostkeys/test_hostkeys rm -f regress/unittests/kex/*.o @@ -426,6 +430,8 @@ regress-prep: mkdir -p `pwd`/regress/unittests/sshkey [ -d `pwd`/regress/unittests/bitmap ] || \ mkdir -p `pwd`/regress/unittests/bitmap + [ -d `pwd`/regress/unittests/conversion ] || \ + mkdir -p `pwd`/regress/unittests/conversion [ -d `pwd`/regress/unittests/hostkeys ] || \ mkdir -p `pwd`/regress/unittests/hostkeys [ -d `pwd`/regress/unittests/kex ] || \ @@ -503,6 +509,16 @@ regress/unittests/bitmap/test_bitmap$(EXEEXT): ${UNITTESTS_TEST_BITMAP_OBJS} \ regress/unittests/test_helper/libtest_helper.a \ -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) +UNITTESTS_TEST_CONVERSION_OBJS=\ + regress/unittests/conversion/tests.o + +regress/unittests/conversion/test_conversion$(EXEEXT): \ + ${UNITTESTS_TEST_CONVERSION_OBJS} \ + regress/unittests/test_helper/libtest_helper.a libssh.a + $(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_CONVERSION_OBJS) \ + regress/unittests/test_helper/libtest_helper.a \ + -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) + UNITTESTS_TEST_KEX_OBJS=\ regress/unittests/kex/tests.o \ regress/unittests/kex/test_kex.o @@ -558,13 +574,14 @@ regress-binaries: regress/modpipe$(EXEEXT) \ regress/unittests/sshbuf/test_sshbuf$(EXEEXT) \ regress/unittests/sshkey/test_sshkey$(EXEEXT) \ regress/unittests/bitmap/test_bitmap$(EXEEXT) \ + regress/unittests/conversion/test_conversion$(EXEEXT) \ regress/unittests/hostkeys/test_hostkeys$(EXEEXT) \ regress/unittests/kex/test_kex$(EXEEXT) \ regress/unittests/match/test_match$(EXEEXT) \ regress/unittests/utf8/test_utf8$(EXEEXT) \ regress/misc/kexfuzz/kexfuzz$(EXEEXT) -tests interop-tests t-exec: regress-prep regress-binaries $(TARGETS) +tests interop-tests t-exec unit: regress-prep regress-binaries $(TARGETS) BUILDDIR=`pwd`; \ TEST_SSH_SCP="$${BUILDDIR}/scp"; \ TEST_SSH_SSH="$${BUILDDIR}/ssh"; \ diff --git a/README b/README index 60594ee..bda8525 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -See https://www.openssh.com/releasenotes.html#7.4p1 for the release notes. +See https://www.openssh.com/releasenotes.html#7.5p1 for the release notes. Please read https://www.openssh.com/report.html for bug reporting instructions and note that we do not use Github for bug reporting or diff --git a/appveyor.yml b/appveyor.yml index 1650a6f..a9a77d0 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 0.0.8.0.{build} +version: 0.0.10.0.{build} image: Visual Studio 2015 branches: @@ -11,12 +11,12 @@ init: build_script: - ps: | - Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppVeyor.psm1 -DisableNameChecking + Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppveyorHelper.psm1 -DisableNameChecking Invoke-AppVeyorBuild after_build: - ps: | - Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppVeyor.psm1 -DisableNameChecking + Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppveyorHelper.psm1 -DisableNameChecking Install-OpenSSH - ps: Write-Verbose "Restart computer ..." - ps: Restart-Computer -Force @@ -25,23 +25,20 @@ after_build: before_test: - ps: | - Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppVeyor.psm1 -DisableNameChecking - Install-TestDependencies - Deploy-OpenSSHTests + Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppveyorHelper.psm1 -DisableNameChecking + Setup-OpenSSHTestEnvironment -Quiet test_script: - - cmd: | - "%ProgramFiles%\PowerShell\6.0.0.14\powershell.exe" -Command "Import-Module \"%APPVEYOR_BUILD_FOLDER%\contrib\win32\openssh\AppVeyor.psm1\" -DisableNameChecking;Run-OpenSSHPesterTest" - ps: | - Check-PesterTestResult - Run-OpenSSHUnitTest + Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppveyorHelper.psm1 -DisableNameChecking + Run-OpenSSHTests after_test: - ps: | - Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppVeyor.psm1 -DisableNameChecking + Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppveyorHelper.psm1 -DisableNameChecking Upload-OpenSSHTestResults on_finish: - ps: | - Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppVeyor.psm1 -DisableNameChecking + Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppveyorHelper.psm1 -DisableNameChecking Publish-Artifact diff --git a/auth-passwd.c b/auth-passwd.c index f64730f..37cb236 100644 --- a/auth-passwd.c +++ b/auth-passwd.c @@ -227,15 +227,16 @@ sys_auth_passwd(Authctxt *authctxt, const char *password) #elif defined(WINDOWS) /* * Authenticate on Windows - Pass credentials to ssh-agent and retrieve token -* upon succesful authentication +* upon successful authentication +* TODO - password is sent in plain text over IPC. Consider implications. */ -extern int auth_sock; int sys_auth_passwd(Authctxt *authctxt, const char *password) { + struct sshbuf *msg = NULL; size_t blen = 0; DWORD token = 0; - struct sshbuf *msg = NULL; - int r; + extern int auth_sock; + int r = 0; msg = sshbuf_new(); if (!msg) diff --git a/auth.c b/auth.c index a6ba4d4..3cd6e79 100644 --- a/auth.c +++ b/auth.c @@ -490,7 +490,7 @@ auth_secure_path(const char *name, struct stat *stp, const char *pw_dir, uid_t uid, char *err, size_t errlen) { #ifdef WINDOWS - error("auth_secure_path should not be called in Windows"); + error("auth_secure_path should not be called in Windows yet"); return -1; #else /* !WINDOWS */ char buf[PATH_MAX], homedir[PATH_MAX]; @@ -579,7 +579,7 @@ auth_openfile(const char *file, struct passwd *pw, int strict_modes, FILE *f; #ifdef WINDOWS - /* Windows POSIX adpater does not support fdopen() on open(file)*/ + /* Windows POSIX adapter does not support fdopen() on open(file)*/ if ((f = fopen(file, "r")) == NULL) { debug("Could not open %s '%s': %s", file_type, file, strerror(errno)); diff --git a/auth2-pubkey.c b/auth2-pubkey.c index cd8dd1b..55de205 100644 --- a/auth2-pubkey.c +++ b/auth2-pubkey.c @@ -178,14 +178,14 @@ userauth_pubkey(Authctxt *authctxt) authenticated = 0; #ifdef WINDOWS - /* Pass key challenge material to ssh-agent to retrieve token upon succesful authentication */ + /* Pass key challenge material to ssh-agent to retrieve token upon successful authentication */ { - extern int auth_sock; - int r; + struct sshbuf *msg = NULL; u_char *blob = NULL; size_t blen = 0; DWORD token = 0; - struct sshbuf *msg = NULL; + extern int auth_sock; + int r = 0; while (1) { msg = sshbuf_new(); @@ -246,11 +246,7 @@ userauth_pubkey(Authctxt *authctxt) * if a user is not allowed to login. is this an * issue? -markus */ -#ifdef WINDOWS /* key validation in done in agent for Windows */ - { -#else /* !WINDOWS */ if (PRIVSEP(user_key_allowed(authctxt->pw, key, 0))) { -#endif /* !WINDOWS */ packet_start(SSH2_MSG_USERAUTH_PK_OK); packet_put_string(pkalg, alen); packet_put_string(pkblob, blen); diff --git a/authfd.c b/authfd.c index 2fd857d..c8da54d 100644 --- a/authfd.c +++ b/authfd.c @@ -113,7 +113,6 @@ ssh_get_authentication_socket(int *fdp) errno = oerrno; return SSH_ERR_SYSTEM_ERROR; } - if (fdp != NULL) *fdp = sock; else diff --git a/configure.ac b/configure.ac index 972addf..82b28ce 100644 --- a/configure.ac +++ b/configure.ac @@ -1486,6 +1486,7 @@ AC_ARG_WITH(ldns, else LIBS="$LIBS `$LDNSCONFIG --libs`" CPPFLAGS="$CPPFLAGS `$LDNSCONFIG --cflags`" + ldns=yes fi elif test "x$withval" != "xno" ; then CPPFLAGS="$CPPFLAGS -I${withval}/include" @@ -1717,6 +1718,7 @@ AC_CHECK_FUNCS([ \ inet_ntoa \ inet_ntop \ innetgr \ + llabs \ login_getcapbool \ md5_crypt \ memmove \ @@ -2531,8 +2533,8 @@ if test "x$openssl" = "xyes" ; then ssl_library_ver=`cat conftest.ssllibver` # Check version is supported. case "$ssl_library_ver" in - 0090[[0-7]]*|009080[[0-5]]*) - AC_MSG_ERROR([OpenSSL >= 0.9.8f required (have "$ssl_library_ver")]) + 10000*|0*) + AC_MSG_ERROR([OpenSSL >= 1.0.1 required (have "$ssl_library_ver")]) ;; *) ;; esac diff --git a/contrib/cygwin/ssh-host-config b/contrib/cygwin/ssh-host-config index d934d09..db6aaa0 100644 --- a/contrib/cygwin/ssh-host-config +++ b/contrib/cygwin/ssh-host-config @@ -63,7 +63,6 @@ sshd_config_configured=no port_number=22 service_name=sshd strictmodes=yes -privsep_used=yes cygwin_value="" user_account= password_value= @@ -140,33 +139,21 @@ sshd_strictmodes() { # ====================================================================== # Routine: sshd_privsep -# MODIFIES: privsep_used +# Try to create ssshd user account # ====================================================================== sshd_privsep() { local ret=0 if [ "${sshd_config_configured}" != "yes" ] then - echo - csih_inform "Privilege separation is set to 'sandbox' by default since" - csih_inform "OpenSSH 6.1. This is unsupported by Cygwin and has to be set" - csih_inform "to 'yes' or 'no'." - csih_inform "However, using privilege separation requires a non-privileged account" - csih_inform "called 'sshd'." - csih_inform "For more info on privilege separation read /usr/share/doc/openssh/README.privsep." - if csih_request "Should privilege separation be used?" + if ! csih_create_unprivileged_user sshd then - privsep_used=yes - if ! csih_create_unprivileged_user sshd - then - csih_error_recoverable "Couldn't create user 'sshd'!" - csih_error_recoverable "Privilege separation set to 'no' again!" - csih_error_recoverable "Check your ${SYSCONFDIR}/sshd_config file!" - let ++ret - privsep_used=no - fi - else - privsep_used=no + csih_error_recoverable "Could not create user 'sshd'!" + csih_error_recoverable "You will not be able to run an sshd service" + csih_error_recoverable "under a privileged account successfully." + csih_error_recoverable "Make sure to create a non-privileged user 'sshd'" + csih_error_recoverable "manually before trying to run the service!" + let ++ret fi fi return $ret @@ -202,18 +189,6 @@ sshd_config_tweak() { let ++ret fi fi - if [ "${sshd_config_configured}" != "yes" ] - then - /usr/bin/sed -i -e " - s/^#\?UsePrivilegeSeparation .*/UsePrivilegeSeparation ${privsep_used}/" \ - ${SYSCONFDIR}/sshd_config - if [ $? -ne 0 ] - then - csih_warning "Setting privilege separation failed!" - csih_warning "Check your ${SYSCONFDIR}/sshd_config file!" - let ++ret - fi - fi return $ret } # --- End of sshd_config_tweak --- # @@ -693,7 +668,7 @@ then fi fi -# handle sshd_config (and privsep) +# handle sshd_config csih_install_config "${SYSCONFDIR}/sshd_config" "${SYSCONFDIR}/defaults" || let ++warning_cnt if ! /usr/bin/cmp "${SYSCONFDIR}/sshd_config" "${SYSCONFDIR}/defaults/${SYSCONFDIR}/sshd_config" >/dev/null 2>&1 then diff --git a/contrib/redhat/openssh.spec b/contrib/redhat/openssh.spec index 666097c..7de4545 100644 --- a/contrib/redhat/openssh.spec +++ b/contrib/redhat/openssh.spec @@ -1,4 +1,4 @@ -%define ver 7.4p1 +%define ver 7.5p1 %define rel 1 # OpenSSH privilege separation requires a user & group ID diff --git a/contrib/suse/openssh.spec b/contrib/suse/openssh.spec index 4c4bbb6..e62be39 100644 --- a/contrib/suse/openssh.spec +++ b/contrib/suse/openssh.spec @@ -13,7 +13,7 @@ Summary: OpenSSH, a free Secure Shell (SSH) protocol implementation Name: openssh -Version: 7.4p1 +Version: 7.5p1 URL: https://www.openssh.com/ Release: 1 Source0: openssh-%{version}.tar.gz diff --git a/contrib/win32/openssh/AppveyorHelper.psm1 b/contrib/win32/openssh/AppveyorHelper.psm1 new file mode 100644 index 0000000..f0f97c0 --- /dev/null +++ b/contrib/win32/openssh/AppveyorHelper.psm1 @@ -0,0 +1,269 @@ +$ErrorActionPreference = 'Stop' +Import-Module $PSScriptRoot\OpenSSHCommonUtils.psm1 -Force -DisableNameChecking +Import-Module $PSScriptRoot\OpenSSHBuildHelper.psm1 -Force -DisableNameChecking +Import-Module $PSScriptRoot\OpenSSHTestHelper.psm1 -Force -DisableNameChecking + +$repoRoot = Get-RepositoryRoot +$script:messageFile = join-path $repoRoot.FullName "BuildMessage.log" + +# Sets a build variable +Function Write-BuildMessage +{ + param( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] $Message, + $Category, + [string] $Details) + + if($env:AppVeyor) + { + Add-AppveyorMessage @PSBoundParameters + } + + # write it to the log file, if present. + if (-not ([string]::IsNullOrEmpty($script:messageFile))) + { + Add-Content -Path $script:messageFile -Value "$Category--$Message" + } +} + +# Sets a build variable +Function Set-BuildVariable +{ + param( + [Parameter(Mandatory=$true)] + [string] + $Name, + + [Parameter(Mandatory=$true)] + [string] + $Value + ) + + if($env:AppVeyor -and (Get-Command Set-AppveyorBuildVariable -ErrorAction Ignore) -ne $null) + { + Set-AppveyorBuildVariable @PSBoundParameters + } + elseif($env:AppVeyor) + { + appveyor SetVariable -Name $Name -Value $Value + } + else + { + Set-Item env:$Name -Value $Value + } +} + +# Emulates running all of AppVeyor but locally +# should not be used on AppVeyor +function Invoke-AppVeyorFull +{ + param( + [switch] $APPVEYOR_SCHEDULED_BUILD, + [switch] $CleanRepo + ) + if($CleanRepo) + { + Clear-PSRepo + } + + if($env:APPVEYOR) + { + throw "This function is to simulate appveyor, but not to be run from appveyor!" + } + + if($APPVEYOR_SCHEDULED_BUILD) + { + $env:APPVEYOR_SCHEDULED_BUILD = 'True' + } + try { + Set-OpenSSHTestParams + Invoke-AppVeyorBuild + Install-OpenSSH + Install-OpenSSHTestDependencies + Deploy-OpenSSHTests + Setup-OpenSSHTestEnvironment + Run-OpenSSHTests + Publish-Artifact + } + finally { + if($APPVEYOR_SCHEDULED_BUILD -and $env:APPVEYOR_SCHEDULED_BUILD) + { + Remove-Item env:APPVEYOR_SCHEDULED_BUILD + } + } +} + +# Implements the AppVeyor 'build_script' step +function Invoke-AppVeyorBuild +{ + Set-BuildVariable TestPassed True + Build-OpenSSH -Configuration Release -NativeHostArch x64 + Build-OpenSSH -Configuration Debug -NativeHostArch x86 + Write-BuildMessage -Message "OpenSSH binaries build success!" -Category Information +} + +<# + .Synopsis + Adds a build log to the list of published artifacts. + .Description + If a build log exists, it is renamed to reflect the associated CLR runtime then added to the list of + artifacts to publish. If it doesn't exist, a warning is written and the file is skipped. + The rename is needed since publishing overwrites the artifact if it already exists. + .Parameter artifacts + An array list to add the fully qualified build log path + .Parameter buildLog + The build log file produced by the build. +#> +function Add-BuildLog +{ + param + ( + [ValidateNotNull()] + [System.Collections.ArrayList] $artifacts, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] $buildLog + ) + + if (Test-Path -Path $buildLog) + { + $null = $artifacts.Add($buildLog) + } + else + { + Write-Warning "Skip publishing build log. $buildLog does not exist" + } +} + +<# + .Synopsis + Publishes package build artifacts. + .Parameter artifacts + An array list to add the fully qualified build log path + .Parameter FileToAdd + Path to the file +#> +function Add-Artifact +{ + param + ( + [ValidateNotNull()] + [System.Collections.ArrayList] $artifacts, + [string] $FileToAdd + ) + + if ([string]::IsNullOrEmpty($FileToAdd) -or (-not (Test-Path $FileToAdd -PathType Leaf)) ) + { + Write-Host "Skip publishing package artifacts. $FileToAdd does not exist" + } + else + { + $null = $artifacts.Add($FileToAdd) + } +} + +<# + .Synopsis + After build and test run completes, upload all artifacts from the build machine. +#> +function Publish-Artifact +{ + Write-Host -ForegroundColor Yellow "Publishing project artifacts" + [System.Collections.ArrayList] $artifacts = [System.Collections.ArrayList]::new() + + # Get the build.log file for each build configuration + Add-BuildLog -artifacts $artifacts -buildLog (Get-BuildLogFile -root $repoRoot.FullName) + + if($Global:OpenSSHTestInfo) + { + Add-Artifact -artifacts $artifacts -FileToAdd $Global:OpenSSHTestInfo["UnitTestResultsFile"] + Add-Artifact -artifacts $artifacts -FileToAdd $Global:OpenSSHTestInfo["E2ETestResultsFile"] + Add-Artifact -artifacts $artifacts -FileToAdd $Global:OpenSSHTestInfo["TestSetupLogFile"] + } + + foreach ($artifact in $artifacts) + { + Write-Host "Publishing $artifact as Appveyor artifact" + # NOTE: attempt to publish subsequent artifacts even if the current one fails + Push-AppveyorArtifact $artifact -ErrorAction Continue + } +} + +<# + .Synopsis + Runs the tests for this repo +#> +function Run-OpenSSHTests +{ + Write-Host "Start running unit tests" + $unitTestFailed = Run-OpenSSHUnitTest + + if($unitTestFailed) + { + Write-Host "At least one of the unit tests failed!" -ForegroundColor Yellow + Write-BuildMessage "At least one of the unit tests failed!" -Category Error + Set-BuildVariable TestPassed False + } + else + { + Write-Host "All Unit tests passed!" + Write-BuildMessage -Message "All Unit tests passed!" -Category Information + } + # Run all E2E tests. + Run-OpenSSHE2ETest + if (($OpenSSHTestInfo -eq $null) -or (-not (Test-Path $OpenSSHTestInfo["E2ETestResultsFile"]))) + { + Write-Warning "Test result file $OpenSSHTestInfo["E2ETestResultsFile"] not found after tests." + Write-BuildMessage -Message "Test result file $OpenSSHTestInfo["E2ETestResultsFile"] not found after tests." -Category Error + Set-BuildVariable TestPassed False + } + $xml = [xml](Get-Content -raw $OpenSSHTestInfo["E2ETestResultsFile"]) + if ([int]$xml.'test-results'.failures -gt 0) + { + $errorMessage = "$($xml.'test-results'.failures) tests in regress\pesterTests failed. Detail test log is at $($OpenSSHTestInfo["E2ETestResultsFile"])." + Write-Warning $errorMessage + Write-BuildMessage -Message $errorMessage -Category Error + Set-BuildVariable TestPassed False + } + + # Writing out warning when the $Error.Count is non-zero. Tests Should clean $Error after success. + if ($Error.Count -gt 0) + { + Write-BuildMessage -Message "Tests Should clean $Error after success." -Category Warning + } +} + +<# + .Synopsis + upload OpenSSH pester test results. +#> +function Upload-OpenSSHTestResults +{ + if ($env:APPVEYOR_JOB_ID) + { + $resultFile = Resolve-Path $Global:OpenSSHTestInfo["E2ETestResultsFile"] -ErrorAction Ignore + if( (Test-Path $Global:OpenSSHTestInfo["E2ETestResultsFile"]) -and $resultFile) + { + (New-Object 'System.Net.WebClient').UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", $resultFile) + Write-BuildMessage -Message "Test results uploaded!" -Category Information + } + } + + if ($env:DebugMode) + { + Remove-Item $env:DebugMode + } + + if($env:TestPassed -ieq 'True') + { + Write-BuildMessage -Message "The checkin validation success!" -Category Information + } + else + { + Write-BuildMessage -Message "The checkin validation failed!" -Category Error + throw "The checkin validation failed!" + } +} diff --git a/contrib/win32/openssh/OpenSSHBuildHelper.psm1 b/contrib/win32/openssh/OpenSSHBuildHelper.psm1 new file mode 100644 index 0000000..21adf88 --- /dev/null +++ b/contrib/win32/openssh/OpenSSHBuildHelper.psm1 @@ -0,0 +1,592 @@ +Set-StrictMode -Version Latest + +Import-Module $PSScriptRoot\OpenSSHCommonUtils.psm1 -force -DisableNameChecking +[string] $script:platform = $env:PROCESSOR_ARCHITECTURE +[string] $script:vcPath = $null +[System.IO.DirectoryInfo] $script:OpenSSHRoot = $null +[System.IO.DirectoryInfo] $script:gitRoot = $null +[bool] $script:Verbose = $false +[string] $script:BuildLogFile = $null + +<# + 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:BuildLogFile))) + { + Add-Content -Path $script:BuildLogFile -Value $Message + } +} + +<# +.Synopsis + Writes a build message. +.Parameter Message + The message to write. +.Parameter AsInfo + Writes a user message using Write-Information. +.Parameter AsVerbose + Writes a message using Write-Verbose and to the build log if -Verbose was specified to Start-DscBuild. +.Parameter AsWarning + Writes a message using Write-Warning and to the build log. +.Parameter AsError + Writes a message using Write-Error and to the build log. +.Parameter Silent + Writes the message only to the log. +.Parameter ErrorAction + Determines if the script is terminated when errors are written. + This parameter is ignored when -Silent is specified. +.Example + Write-BuildMsg -AsInfo 'Starting the build' + Writes an informational message to the log and to the user +.Example + Write-BuildMsg -AsError 'Terminating build' -Silent + Writes an error message only to the log +.Example + Write-BuildMsg -AsError 'Terminating build' -ErrorAction Stop + Writes an error message to the log and the user and terminates the build. +.Example + Write-BuildMsg -AsInfo 'Nuget is already installed' -Silent:(-not $script:Verbose) + Writes an informational message to the log. If -Verbose was specified, also + writes to message to the user. +#> +function Write-BuildMsg +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] $Message, + + [Parameter(ParameterSetName='Info')] + [switch] $AsInfo, + + [Parameter(ParameterSetName='Verbose')] + [switch] $AsVerbose, + + [Parameter(ParameterSetName='Warning')] + [switch] $AsWarning, + + [Parameter(ParameterSetName='Error')] + [switch] $AsError, + + [switch] $Silent + ) + + if ($AsVerbose) + { + if ($script:Verbose) + { + Write-Log -Message "VERBOSE: $message" + if (-not $Silent) + { + Write-Verbose -Message $message -Verbose + } + } + return + } + + if ($AsInfo) + { + Write-Log -Message "INFO: $message" + if (-not $Silent) + { + Write-Information -MessageData $message -InformationAction Continue + } + return + } + + if ($AsWarning) + { + Write-Log -Message "WARNING: $message" + if (-not $Silent) + { + Write-Warning -Message $message + } + return + } + + if ($AsError) + { + Write-Log -Message "ERROR: $message" + if (-not $Silent) + { + Write-Error -Message $message + } + return + } + + # if we reached here, no output type switch was specified. + Write-BuildMsg -AsError -ErrorAction Stop -Message 'Write-BuildMsg was called without selecting an output type.' +} + +<# +.Synopsis + Verifies all tools and dependencies required for building Open SSH are installed on the machine. +#> +function Start-OpenSSHBootstrap +{ + [bool] $silent = -not $script:Verbose + + Set-StrictMode -Version Latest + Write-BuildMsg -AsInfo -Message "Checking tools and dependencies" -Silent:$silent + + $machinePath = [Environment]::GetEnvironmentVariable('Path', 'MACHINE') + $newMachineEnvironmentPath = $machinePath + + # Install chocolatey + $chocolateyPath = "$env:AllUsersProfile\chocolatey\bin" + if(Get-Command "choco" -ErrorAction SilentlyContinue) + { + Write-BuildMsg -AsVerbose -Message "Chocolatey is already installed. Skipping installation." -Silent:$silent + } + else + { + Write-BuildMsg -AsInfo -Message "Chocolatey not present. Installing chocolatey." -Silent:$silent + Invoke-Expression ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1')) 2>&1 >> $script:BuildLogFile + } + + # Add git\cmd to the path + $gitCmdPath = "$env:ProgramFiles\git\cmd" + if (-not ($machinePath.ToLower().Contains($gitCmdPath.ToLower()))) + { + Write-BuildMsg -AsVerbose -Message "Adding $gitCmdPath to Path environment variable" -Silent:$silent + $newMachineEnvironmentPath = "$gitCmdPath;$newMachineEnvironmentPath" + } + else + { + Write-BuildMsg -AsVerbose -Message "$gitCmdPath already present in Path environment variable" -Silent:$silent + } + + $nativeMSBuildPath = "${env:ProgramFiles(x86)}\MSBuild\14.0\bin" + if($script:platform -ieq "AMD64") + { + $nativeMSBuildPath += "\amd64" + } + + if (-not ($machinePath.ToLower().Contains($nativeMSBuildPath.ToLower()))) + { + Write-BuildMsg -AsVerbose -Message "Adding $nativeMSBuildPath to Path environment variable" -Silent:$silent + $newMachineEnvironmentPath += ";$nativeMSBuildPath" + $env:Path += ";$nativeMSBuildPath" + } + else + { + Write-BuildMsg -AsVerbose -Message "$nativeMSBuildPath already present in Path environment variable" -Silent:$silent + } + + # Update machine environment path + if ($newMachineEnvironmentPath -ne $machinePath) + { + [Environment]::SetEnvironmentVariable('Path', $newMachineEnvironmentPath, 'MACHINE') + } + + # install nasm + $packageName = "nasm" + $nasmPath = "${env:ProgramFiles(x86)}\NASM" + + if (-not (Test-Path -Path $nasmPath -PathType Container)) + { + Write-BuildMsg -AsInfo -Message "$packageName not present. Installing $packageName." -Silent:$silent + choco install $packageName -y --force --limitoutput --execution-timeout 10000 2>&1 >> $script:BuildLogFile + } + else + { + Write-BuildMsg -AsVerbose -Message "$packageName present. Skipping installation." -Silent:$silent + } + + # Install Visual Studio 2015 Community + $packageName = "VisualStudio2015Community" + $VSPackageInstalled = Get-ItemProperty "HKLM:\software\WOW6432Node\Microsoft\VisualStudio\14.0\setup\vs" -ErrorAction SilentlyContinue + + if ($null -eq $VSPackageInstalled) + { + Write-BuildMsg -AsInfo -Message "$packageName not present. Installing $packageName." + $adminFilePath = "$script:OpenSSHRoot\contrib\win32\openssh\VSWithBuildTools.xml" + choco install $packageName -packageParameters "--AdminFile $adminFilePath" -y --force --limitoutput --execution-timeout 10000 2>&1 >> $script:BuildLogFile + } + else + { + Write-BuildMsg -AsVerbose -Message "$packageName present. Skipping installation." -Silent:$silent + } + + # Install Windows 8.1 SDK + $packageName = "windows-sdk-8.1" + $sdkPath = "${env:ProgramFiles(x86)}\Windows Kits\8.1\bin\x86\register_app.vbs" + + if (-not (Test-Path -Path $sdkPath)) + { + Write-BuildMsg -AsInfo -Message "Windows 8.1 SDK not present. Installing $packageName." + choco install $packageName -y --limitoutput --force 2>&1 >> $script:BuildLogFile + } + else + { + Write-BuildMsg -AsInfo -Message "$packageName present. Skipping installation." -Silent:$silent + } + + # Require restarting PowerShell session + if ($null -eq $VSPackageInstalled) + { + Write-Host "To apply changes, please close this PowerShell window, open a new one and call Start-SSHBuild or Start-DscBootstrap again." -ForegroundColor Black -BackgroundColor Yellow + Write-Host -NoNewLine 'Press any key to close this PowerShell window...' -ForegroundColor Black -BackgroundColor Yellow + $null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown') + exit + } + + # Ensure the VS C toolset is installed + if ($null -eq $env:VS140COMNTOOLS) + { + Write-BuildMsg -AsError -ErrorAction Stop -Message "Cannot find Visual Studio 2015 Environment variable VS140COMNTOOlS" + } + + $item = Get-Item(Join-Path -Path $env:VS140COMNTOOLS -ChildPath '../../vc') + + $script:vcPath = $item.FullName + 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, which means some required develop kits are missing on the machine." + } +} + +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" -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" -Silent:$silent + Push-Location $win32OpenSSHPath + git fetch -q origin + git checkout -qf L1-Prod + Pop-Location +} + +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" -Silent:$silent + Copy-Item -Container -Path $sourcePath -Destination $PSScriptRoot -Recurse -Force -ErrorAction SilentlyContinue -ErrorVariable e + if($e -ne $null) + { + Write-BuildMsg -AsError -ErrorAction Stop -Message "Copy OpenSSL from $sourcePath failed " + } +} + +function Package-OpenSSH +{ + [CmdletBinding(SupportsShouldProcess=$false)] + param + ( + [ValidateSet('x86', 'x64')] + [string]$NativeHostArch = "x64", + + [ValidateSet('Debug', 'Release', '')] + [string]$Configuration = "Release" + ) + + [System.IO.DirectoryInfo] $repositoryRoot = Get-RepositoryRoot + $repositoryRoot = Get-Item -Path $repositoryRoot.FullName + $folderName = $NativeHostArch + if($NativeHostArch -ieq 'x86') + { + $folderName = "Win32" + } + $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-lsa.dll", "ssh-shellhost.exe", "ssh-keygen.exe" + $payload += "sshd_config", "install-sshd.ps1", "uninstall-sshd.ps1" + $payload += "install-sshlsa.ps1", "uninstall-sshlsa.ps1" + + $packageName = "OpenSSH-Win64" + if ($NativeHostArch -eq 'x86') { + $packageName = "OpenSSH-Win32" + } + + $packageDir = Join-Path $buildDir $packageName + Remove-Item $packageDir -Recurse -Force -ErrorAction SilentlyContinue + New-Item $packageDir -Type Directory | Out-Null + + $symbolsDir = Join-Path $buildDir ($packageName + '_Symbols') + Remove-Item $symbolsDir -Recurse -Force -ErrorAction SilentlyContinue + New-Item $symbolsDir -Type Directory | Out-Null + + foreach ($file in $payload) { + if ((-not(Test-Path (Join-Path $buildDir $file)))) { + Throw "Cannot find $file under $buildDir. Did you run Build-OpenSSH?" + } + Copy-Item (Join-Path $buildDir $file) $packageDir + if ($file.EndsWith(".exe")) { + $pdb = $file.Replace(".exe", ".pdb") + Copy-Item (Join-Path $buildDir $pdb) $symbolsDir + } + if ($file.EndsWith(".dll")) { + $pdb = $file.Replace(".dll", ".pdb") + Copy-Item (Join-Path $buildDir $pdb) $symbolsDir + } + } + + Remove-Item ($packageDir + '.zip') -Force -ErrorAction SilentlyContinue + Compress-Archive -Path $packageDir -DestinationPath ($packageDir + '.zip') + Remove-Item $packageDir -Recurse -Force -ErrorAction SilentlyContinue + + Remove-Item ($symbolsDir + '.zip') -Force -ErrorAction SilentlyContinue + Compress-Archive -Path $symbolsDir -DestinationPath ($symbolsDir + '.zip') + Remove-Item $symbolsDir -Recurse -Force -ErrorAction SilentlyContinue +} + +function Build-OpenSSH +{ + [CmdletBinding(SupportsShouldProcess=$false)] + param + ( + [ValidateSet('x86', 'x64')] + [string]$NativeHostArch = "x64", + + [ValidateSet('Debug', 'Release', '')] + [string]$Configuration = "Release" + ) + Set-StrictMode -Version Latest + $script:BuildLogFile = $null + + [System.IO.DirectoryInfo] $repositoryRoot = Get-RepositoryRoot + + # Get openssh-portable root + $script:OpenSSHRoot = Get-Item -Path $repositoryRoot.FullName + $script:gitRoot = split-path $script:OpenSSHRoot + + 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 -force + } + + Write-BuildMsg -AsInfo -Message "Starting Open SSH build; Build Log: $($script:BuildLogFile)" + + Start-OpenSSHBootstrap + + Clone-Win32OpenSSH + Copy-OpenSSLSDK + $msbuildCmd = "msbuild.exe" + $solutionFile = Get-SolutionFile -root $repositoryRoot.FullName + $cmdMsg = @("${solutionFile}", "/p:Platform=${NativeHostArch}", "/p:Configuration=${Configuration}", "/m", "/noconlog", "/nologo", "/fl", "/flp:LogFile=${script:BuildLogFile}`;Append`;Verbosity=diagnostic") + + & $msbuildCmd $cmdMsg + $errorCode = $LASTEXITCODE + + if ($errorCode -ne 0) + { + Write-BuildMsg -AsError -ErrorAction Stop -Message "Build failed for OpenSSH.`nExitCode: $error." + } + + Write-BuildMsg -AsInfo -Message "SSH build passed." -Silent:$silent +} + +function Get-BuildLogFile +{ + param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNull()] + [System.IO.DirectoryInfo] $root, + + [ValidateSet('x86', 'x64')] + [string]$NativeHostArch = "x64", + + [ValidateSet('Debug', 'Release', '')] + [string]$Configuration = "Release" + + ) + return Join-Path -Path $root -ChildPath "contrib\win32\openssh\OpenSSH$($Configuration)$($NativeHostArch).log" +} + +function Get-SolutionFile +{ + param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNull()] + [System.IO.DirectoryInfo] $root + ) + return Join-Path -Path $root -ChildPath "contrib\win32\openssh\Win32-OpenSSH.sln" +} + +<# + .Synopsis + Deploy all required files to build a package and create zip file. +#> +function Deploy-Win32OpenSSHBinaries +{ + [CmdletBinding()] + param + ( + [ValidateSet('Debug', 'Release', '')] + [string]$Configuration = "", + [ValidateSet('x86', 'x64', '')] + [string]$NativeHostArch = "", + [string]$OpenSSHDir = "$env:SystemDrive\OpenSSH" + ) + + if (-not (Test-Path -Path $OpenSSHDir -PathType Container)) + { + $null = New-Item -Path $OpenSSHDir -ItemType Directory -Force -ErrorAction Stop + } + + [string] $platform = $env:PROCESSOR_ARCHITECTURE + if(-not [String]::IsNullOrEmpty($NativeHostArch)) + { + $folderName = $NativeHostArch + if($NativeHostArch -ieq 'x86') + { + $folderName = "Win32" + } + } + else + { + if($platform -ieq "AMD64") + { + $folderName = "x64" + } + else + { + $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\$RealConfiguration" + if((Get-Service ssh-agent -ErrorAction Ignore) -ne $null) { + Stop-Service ssh-agent -Force + } + 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 +} + +<# + .Synopsis + Deploy all required files to a location and install the binaries +#> +function Install-OpenSSH +{ + [CmdletBinding()] + param + ( + [ValidateSet('Debug', 'Release', '')] + [string]$Configuration = "", + + [ValidateSet('x86', 'x64', '')] + [string]$NativeHostArch = "", + + [string]$OpenSSHDir = "$env:SystemDrive\OpenSSH" + ) + + Deploy-Win32OpenSSHBinaries @PSBoundParameters + + Push-Location $OpenSSHDir + & ( "$OpenSSHDir\install-sshd.ps1") + .\ssh-keygen.exe -A + & ( "$OpenSSHDir\install-sshlsa.ps1") + + #machine will be reboot after Install-openssh anyway + $machinePath = [Environment]::GetEnvironmentVariable('Path', 'MACHINE') + $newMachineEnvironmentPath = $machinePath + if (-not ($machinePath.ToLower().Contains($OpenSSHDir.ToLower()))) + { + $newMachineEnvironmentPath = "$OpenSSHDir;$newMachineEnvironmentPath" + $env:Path = "$OpenSSHDir;$env:Path" + } + # Update machine environment path + if ($newMachineEnvironmentPath -ne $machinePath) + { + [Environment]::SetEnvironmentVariable('Path', $newMachineEnvironmentPath, 'MACHINE') + } + + Set-Service sshd -StartupType Automatic + Set-Service ssh-agent -StartupType Automatic + Start-Service sshd + + Pop-Location + Write-Log -Message "OpenSSH installed!" +} + +<# + .Synopsis + uninstalled sshd and sshla +#> +function UnInstall-OpenSSH +{ + + [CmdletBinding()] + param + ( + [string]$OpenSSHDir = "$env:SystemDrive\OpenSSH" + ) + + Push-Location $OpenSSHDir + if((Get-Service ssh-agent -ErrorAction Ignore) -ne $null) { + Stop-Service ssh-agent -Force + } + &( "$OpenSSHDir\uninstall-sshd.ps1") + &( "$OpenSSHDir\uninstall-sshlsa.ps1") + + $machinePath = [Environment]::GetEnvironmentVariable('Path', 'MACHINE') + $newMachineEnvironmentPath = $machinePath + if ($machinePath.ToLower().Contains($OpenSSHDir.ToLower())) + { + $newMachineEnvironmentPath.Replace("$OpenSSHDir;", '') + $env:Path = $env:Path.Replace("$OpenSSHDir;", '') + } + + # Update machine environment path + # machine will be reboot after Uninstall-OpenSSH + if ($newMachineEnvironmentPath -ne $machinePath) + { + [Environment]::SetEnvironmentVariable('Path', $newMachineEnvironmentPath, 'MACHINE') + } + + Pop-Location +} + + +Export-ModuleMember -Function Build-OpenSSH, Get-BuildLogFile, Install-OpenSSH, UnInstall-OpenSSH, Package-OpenSSH diff --git a/contrib/win32/openssh/OpenSSHCommonUtils.psm1 b/contrib/win32/openssh/OpenSSHCommonUtils.psm1 new file mode 100644 index 0000000..e8ff879 --- /dev/null +++ b/contrib/win32/openssh/OpenSSHCommonUtils.psm1 @@ -0,0 +1,31 @@ +<# +.Synopsis + Finds the root of the git repository + +.Outputs + A System.IO.DirectoryInfo for the location of the root. + +.Inputs + None + +.Notes + FileNotFoundException is thrown if the current directory does not contain a CMakeLists.txt file. +#> +function Get-RepositoryRoot +{ + $currentDir = (Get-Item -Path $PSCommandPath).Directory + + while ($null -ne $currentDir.Parent) + { + $path = Join-Path -Path $currentDir.FullName -ChildPath '.git' + if (Test-Path -Path $path) + { + return $currentDir + } + $currentDir = $currentDir.Parent + } + + throw new-object System.IO.DirectoryNotFoundException("Could not find the root of the GIT repository") +} + +Export-ModuleMember -Function Get-RepositoryRoot \ No newline at end of file diff --git a/contrib/win32/openssh/OpenSSHTestHelper.psm1 b/contrib/win32/openssh/OpenSSHTestHelper.psm1 new file mode 100644 index 0000000..2740558 --- /dev/null +++ b/contrib/win32/openssh/OpenSSHTestHelper.psm1 @@ -0,0 +1,445 @@ +$ErrorActionPreference = 'Stop' +Import-Module $PSScriptRoot\OpenSSHCommonUtils.psm1 -DisableNameChecking + +[System.IO.DirectoryInfo] $repositoryRoot = Get-RepositoryRoot +# test environment parameters initialized with defaults +$E2ETestResultsFileName = "E2ETestResults.xml" +$UnitTestResultsFileName = "UnitTestResults.txt" +$TestSetupLogFileName = "TestSetupLog.txt" +$SSOUser = "sshtest_ssouser" +$PubKeyUser = "sshtest_pubkeyuser" +$PasswdUser = "sshtest_passwduser" +$OpenSSHTestAccountsPassword = "P@ssw0rd_1" +$OpenSSHTestAccounts = $Script:SSOUser, $Script:PubKeyUser, $Script:PasswdUser + +$Script:TestDataPath = "$env:SystemDrive\OpenSSHTests" +$Script:E2ETestResultsFile = Join-Path $TestDataPath $E2ETestResultsFileName +$Script:UnitTestResultsFile = Join-Path $TestDataPath $UnitTestResultsFileName +$Script:TestSetupLogFile = Join-Path $TestDataPath $TestSetupLogFileName +$Script:E2ETestDirectory = Join-Path $repositoryRoot.FullName -ChildPath "regress\pesterTests" + +<# + .Synopsis + Setup-OpenSSHTestEnvironment + TODO - split these steps into client and server side +#> +function Setup-OpenSSHTestEnvironment +{ + [CmdletBinding()] + param + ( + [switch] $Quiet, + [string] $OpenSSHBinPath, + [string] $TestDataPath = "$env:SystemDrive\OpenSSHTests", + [Boolean] $DebugMode = $false + ) + + if($Global:OpenSSHTestInfo -ne $null) + { + $Global:OpenSSHTestInfo.Clear() + $Global:OpenSSHTestInfo = $null + } + $Script:TestDataPath = $TestDataPath; + $Script:E2ETestResultsFile = Join-Path $TestDataPath "E2ETestResults.xml" + $Script:UnitTestResultsFile = Join-Path $TestDataPath "UnitTestResults.txt" + $Script:TestSetupLogFile = Join-Path $TestDataPath "TestSetupLog.txt" + $Script:UnitTestDirectory = Get-UnitTestDirectory + + + $Global:OpenSSHTestInfo = @{ + "Target"= "localhost"; # test listener name + "Port"= "47002"; # test listener port + "SSOUser"= $SSOUser; # test user with single sign on capability + "PubKeyUser"= $PubKeyUser; # test user to be used with explicit key for key auth + "PasswdUser"= $PasswdUser; # common password for all test accounts + "TestAccountPW"= $OpenSSHTestAccountsPassword; # common password for all test accounts + "TestDataPath" = $TestDataPath; # openssh tests path + "TestSetupLogFile" = $Script:TestSetupLogFile; # openssh test setup log file + "E2ETestResultsFile" = $Script:E2ETestResultsFile; # openssh E2E test results file + "UnitTestResultsFile" = $Script:UnitTestResultsFile; # openssh unittest test results file + "E2ETestDirectory" = $Script:E2ETestDirectory # the directory of E2E tests + "UnitTestDirectory" = $Script:UnitTestDirectory # the directory of unit tests + "DebugMode" = $DebugMode # run openssh E2E in debug mode + } + + #if user does not set path, pick it up + if([string]::IsNullOrEmpty($OpenSSHBinPath)) + { + $sshcmd = get-command ssh.exe -ErrorAction Ignore + if($sshcmd -eq $null) + { + Throw "Cannot find ssh.exe. Please specify -OpenSSHBinPath to the OpenSSH installed location." + } + elseif($Quiet) + { + $dirToCheck = split-path $sshcmd.Path + $script:OpenSSHBinPath = $dirToCheck + } + else + { + $dirToCheck = split-path $sshcmd.Path + $message = "Do you want to test openssh installed at $($dirToCheck)? [Yes] Y; [No] N (default is `"Y`")" + $response = Read-Host -Prompt $message + if( ($response -eq "") -or ($response -ieq "Y") -or ($response -ieq "Yes") ) + { + $script:OpenSSHBinPath = $dirToCheck + } + elseif( ($response -ieq "N") -or ($response -ieq "No") ) + { + Write-Host "User decided not to pick up ssh.exe from $dirToCheck. Please specify -OpenSSHBinPath to the OpenSSH installed location." + return + } + else + { + Throw "User entered invalid option ($response). Please specify -OpenSSHBinPath to the OpenSSH installed location" + } + } + } + else + { + if (-not (Test-Path (Join-Path $OpenSSHBinPath ssh.exe) -PathType Leaf)) + { + Throw "Cannot find OpenSSH binaries under $OpenSSHBinPath. Please specify -OpenSSHBinPathto the OpenSSH installed location" + } + else + { + $script:OpenSSHBinPath = $OpenSSHBinPath + } + } + + $Global:OpenSSHTestInfo.Add("OpenSSHBinPath", $script:OpenSSHBinPath) + + $warning = @" +WARNING: Following changes will be made to OpenSSH configuration + - sshd_config will be backed up as sshd_config.ori + - will be replaced with a test sshd_config + - $HOME\.ssh\known_hosts will be backed up as known_hosts.ori + - will be replaced with a test known_hosts + - sshd test listener will be on port 47002 + - $HOME\.ssh\known_hosts will be modified with test host key entry + - test accounts - ssouser, pubkeyuser, and passwduser will be added + - Setup single signon for ssouser + - To cleanup - Run Cleanup-OpenSSHTestEnvironment +"@ + + if (-not $Quiet) { + Write-Warning $warning + $continue = Read-Host -Prompt "Do you want to continue with the above changes? [Yes] Y; [No] N (default is `"Y`")" + if( ($continue -eq "") -or ($continue -ieq "Y") -or ($continue -ieq "Yes") ) + { + } + elseif( ($continue -ieq "N") -or ($continue -ieq "No") ) + { + Write-Host "User decided not to make the changes." + return + } + else + { + Throw "User entered invalid option ($continue). Exit now." + } + } + + Install-OpenSSHTestDependencies + + if(-not (Test-path $TestDataPath -PathType Container)) + { + New-Item -ItemType Directory -Path $TestDataPath -Force -ErrorAction SilentlyContinue | out-null + } + + #Backup existing OpenSSH configuration + $backupConfigPath = Join-Path $script:OpenSSHBinPath sshd_config.ori + if (-not (Test-Path $backupConfigPath -PathType Leaf)) { + Copy-Item (Join-Path $script:OpenSSHBinPath sshd_config) $backupConfigPath -Force + } + + # copy new sshd_config + Copy-Item (Join-Path $Script:E2ETestDirectory sshd_config) (Join-Path $script:OpenSSHBinPath sshd_config) -Force + Copy-Item "$($Script:E2ETestDirectory)\sshtest*hostkey*" $script:OpenSSHBinPath -Force + Restart-Service sshd -Force + + #Backup existing known_hosts and replace with test version + #TODO - account for custom known_hosts locations + $knowHostsDirectoryPath = Join-Path $home .ssh + $knowHostsFilePath = Join-Path $knowHostsDirectoryPath known_hosts + if(-not (Test-Path $knowHostsDirectoryPath -PathType Container)) + { + New-Item -ItemType Directory -Path $knowHostsDirectoryPath -Force -ErrorAction SilentlyContinue | out-null + } + if ((Test-Path $knowHostsFilePath -PathType Leaf) -and (-not (Test-Path (Join-Path $knowHostsDirectoryPath known_hosts.ori) -PathType Leaf))) { + Copy-Item $knowHostsFilePath (Join-Path $knowHostsDirectoryPath known_hosts.ori) -Force + } + Copy-Item (Join-Path $Script:E2ETestDirectory known_hosts) $knowHostsFilePath -Force + + # create test accounts + #TODO - this is Windows specific. Need to be in PAL + foreach ($user in $OpenSSHTestAccounts) + { + try + { + $objUser = New-Object System.Security.Principal.NTAccount($user) + $strSID = $objUser.Translate([System.Security.Principal.SecurityIdentifier]) + } + catch + { + #only add the local user when it does not exists on the machine + net user $user $Script:OpenSSHTestAccountsPassword /ADD 2>&1 >> $Script:TestSetupLogFile + } + } + + #setup single sign on for ssouser + #TODO - this is Windows specific. Need to be in PAL + $ssousersid = Get-UserSID -User sshtest_ssouser + $ssouserProfileRegistry = Join-Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList" $ssousersid + if (-not (Test-Path $ssouserProfileRegistry) ) { + #create profile + if (-not($env:DISPLAY)) { $env:DISPLAY = 1 } + $env:SSH_ASKPASS="$($env:ComSpec) /c echo $($OpenSSHTestAccountsPassword)" + cmd /c "ssh -p 47002 sshtest_ssouser@localhost echo %userprofile% > profile.txt" + if ($env:DISPLAY -eq 1) { Remove-Item env:\DISPLAY } + remove-item "env:SSH_ASKPASS" -ErrorAction SilentlyContinue + } + $ssouserProfile = (Get-ItemProperty -Path $ssouserProfileRegistry -Name 'ProfileImagePath').ProfileImagePath + New-Item -ItemType Directory -Path (Join-Path $ssouserProfile .ssh) -Force -ErrorAction SilentlyContinue | out-null + $authorizedKeyPath = Join-Path $ssouserProfile .ssh\authorized_keys + $testPubKeyPath = Join-Path $Script:E2ETestDirectory sshtest_userssokey_ed25519.pub + #workaround for the cariggage new line added by git + (Get-Content $testPubKeyPath -Raw).Replace("`r`n","`n") | Set-Content $testPubKeyPath -Force + Copy-Item $testPubKeyPath $authorizedKeyPath -Force -ErrorAction SilentlyContinue + $acl = get-acl $authorizedKeyPath + $ar = New-Object System.Security.AccessControl.FileSystemAccessRule("NT Service\sshd", "Read", "Allow") + $acl.SetAccessRule($ar) + Set-Acl $authorizedKeyPath $acl + $testPriKeypath = Join-Path $Script:E2ETestDirectory sshtest_userssokey_ed25519 + (Get-Content $testPriKeypath -Raw).Replace("`r`n","`n") | Set-Content $testPriKeypath -Force + cmd /c "ssh-add $testPriKeypath 2>&1 >> $Script:TestSetupLogFile" +} + +<# + .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 +{ + [CmdletBinding()] + param () + + # Install chocolatey + if(-not (Get-Command "choco" -ErrorAction SilentlyContinue)) + { + Write-Log -Message "Chocolatey not present. Installing chocolatey." + Invoke-Expression ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1')) 2>&1 >> $Script:TestSetupLogFile + } + + $isModuleAvailable = Get-Module 'Pester' -ListAvailable + if (-not ($isModuleAvailable)) + { + 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 + Get-UserSID +#> +function Get-UserSID +{ + param + ( + [string]$Domain, + [string]$User + ) + if([string]::IsNullOrEmpty($Domain)) + { + $objUser = New-Object System.Security.Principal.NTAccount($User) + } + else + { + $objUser = New-Object System.Security.Principal.NTAccount($Domain, $User) + } + $strSID = $objUser.Translate([System.Security.Principal.SecurityIdentifier]) + $strSID.Value +} + +<# + .Synopsis + Cleanup-OpenSSHTestEnvironment +#> +function Cleanup-OpenSSHTestEnvironment +{ + # .exe - Windows specific. TODO - PAL + if (-not (Test-Path (Join-Path $script:OpenSSHBinPath ssh.exe) -PathType Leaf)) + { + Throw "Cannot find OpenSSH binaries under $script:OpenSSHBinPath. " + } + + #Restore sshd_config + $backupConfigPath = Join-Path $Script:OpenSSHBinPath 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 + Restart-Service sshd + } + + #Restore known_hosts + $originKnowHostsPath = Join-Path $home .ssh\known_hosts.ori + if (Test-Path $originKnowHostsPath) + { + Copy-Item $originKnowHostsPath (Join-Path $home .ssh\known_hosts) -Force -ErrorAction SilentlyContinue + Remove-Item $originKnowHostsPath -Force -ErrorAction SilentlyContinue + } + + #Delete accounts + foreach ($user in $OpenSSHTestAccounts) + { + net user $user /delete + } + + # remove registered keys + cmd /c "ssh-add -d (Join-Path $Script:E2ETestDirectory sshtest_userssokey_ed25519) 2>&1 >> $Script:TestSetupLogFile" + + if($Global:OpenSSHTestInfo -ne $null) + { + $Global:OpenSSHTestInfo.Clear() + $Global:OpenSSHTestInfo = $null + } +} + +<# + .Synopsis + Get-UnitTestDirectory. +#> +function Get-UnitTestDirectory +{ + [CmdletBinding()] + param + ( + [ValidateSet('Debug', 'Release')] + [string]$Configuration = "Release", + + [ValidateSet('x86', 'x64', '')] + [string]$NativeHostArch = "" + ) + + [string] $platform = $env:PROCESSOR_ARCHITECTURE + if(-not [String]::IsNullOrEmpty($NativeHostArch)) + { + $folderName = $NativeHostArch + if($NativeHostArch -eq 'x86') + { + $folderName = "Win32" + } + } + else + { + if($platform -ieq "AMD64") + { + $folderName = "x64" + } + else + { + $folderName = "Win32" + } + } + + if([String]::IsNullOrEmpty($Configuration)) + { + if( $folderName -ieq "Win32" ) + { + $RealConfiguration = "Debug" + } + else + { + $RealConfiguration = "Release" + } + } + else + { + $RealConfiguration = $Configuration + } + $unitTestdir = Join-Path $repositoryRoot.FullName -ChildPath "bin\$folderName\$RealConfiguration" + $unitTestDir +} + +<# + .Synopsis + Run OpenSSH pester tests. +#> +function Run-OpenSSHE2ETest +{ + # Discover all CI tests and run them. + Push-Location $Script:E2ETestDirectory + Write-Log -Message "Running OpenSSH E2E tests..." + $testFolders = Get-ChildItem *.tests.ps1 -Recurse -Exclude SSHDConfig.tests.ps1, SSH.Tests.ps1 | ForEach-Object{ Split-Path $_.FullName} | Sort-Object -Unique + Invoke-Pester $testFolders -OutputFormat NUnitXml -OutputFile $Script:E2ETestResultsFile -Tag 'CI' + Pop-Location +} + +<# + .Synopsis + Run openssh unit tests. +#> +function Run-OpenSSHUnitTest +{ + # Discover all CI tests and run them. + Push-Location $Script:UnitTestDirectory + Write-Log -Message "Running OpenSSH unit tests..." + if (Test-Path $Script:UnitTestResultsFile) + { + $null = Remove-Item -Path $Script:UnitTestResultsFile -Force -ErrorAction SilentlyContinue + } + $testFolders = Get-ChildItem unittest-*.exe -Recurse -Exclude unittest-sshkey.exe,unittest-kex.exe | + ForEach-Object{ Split-Path $_.FullName} | + Sort-Object -Unique + $testfailed = $false + if ($testFolders -ne $null) + { + $testFolders | % { + Push-Location $_ + $unittestFile = "$(Split-Path $_ -Leaf).exe" + Write-log "Running OpenSSH unit $unittestFile ..." + & .\$unittestFile >> $Script:UnitTestResultsFile + + $errorCode = $LASTEXITCODE + if ($errorCode -ne 0) + { + $testfailed = $true + $errorMessage = "$($_.FullName) test failed for OpenSSH.`nExitCode: $errorCode. Detail test log is at $($Script:UnitTestResultsFile)." + Write-Warning $errorMessage + } + Pop-Location + } + } + Pop-Location + $testfailed +} + +<# + Write-Log +#> +function Write-Log +{ + param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] $Message + ) + if(-not (Test-Path (Split-Path $Script:TestSetupLogFile) -PathType Container)) + { + $null = New-Item -ItemType Directory -Path (Split-Path $Script:TestSetupLogFile) -Force -ErrorAction SilentlyContinue | out-null + } + if (-not ([string]::IsNullOrEmpty($Script:TestSetupLogFile))) + { + Add-Content -Path $Script:TestSetupLogFile -Value $Message + } +} + +Export-ModuleMember -Function Setup-OpenSSHTestEnvironment, Cleanup-OpenSSHTestEnvironment, Run-OpenSSHUnitTest, Run-OpenSSHE2ETest diff --git a/contrib/win32/openssh/Win32-OpenSSH.sln b/contrib/win32/openssh/Win32-OpenSSH.sln index 3d860fe..f808422 100644 --- a/contrib/win32/openssh/Win32-OpenSSH.sln +++ b/contrib/win32/openssh/Win32-OpenSSH.sln @@ -126,14 +126,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unittest-win32compat", "uni {0D02F0F0-013B-4EE3-906D-86517F3822C0} = {0D02F0F0-013B-4EE3-906D-86517F3822C0} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unittest-utf8", "unittest-utf8.vcxproj", "{114CAA59-46C0-4B87-BA86-C1946A68101D}" - ProjectSection(ProjectDependencies) = postProject - {05E1115F-8529-46D0-AAAF-52A404CE79A7} = {05E1115F-8529-46D0-AAAF-52A404CE79A7} - {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4} = {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4} - {DD483F7D-C553-4740-BC1A-903805AD0174} = {DD483F7D-C553-4740-BC1A-903805AD0174} - {0D02F0F0-013B-4EE3-906D-86517F3822C0} = {0D02F0F0-013B-4EE3-906D-86517F3822C0} - EndProjectSection -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unittest-hostkeys", "unittest-hostkeys.vcxproj", "{890C6129-286F-4CD8-8252-FB8D3B4E6E1B}" ProjectSection(ProjectDependencies) = postProject {05E1115F-8529-46D0-AAAF-52A404CE79A7} = {05E1115F-8529-46D0-AAAF-52A404CE79A7} @@ -314,14 +306,6 @@ Global {BF295BA9-4BF8-43F8-8CBF-FAE84815466C}.Release|x64.Build.0 = Release|x64 {BF295BA9-4BF8-43F8-8CBF-FAE84815466C}.Release|x86.ActiveCfg = Release|Win32 {BF295BA9-4BF8-43F8-8CBF-FAE84815466C}.Release|x86.Build.0 = Release|Win32 - {114CAA59-46C0-4B87-BA86-C1946A68101D}.Debug|x64.ActiveCfg = Debug|x64 - {114CAA59-46C0-4B87-BA86-C1946A68101D}.Debug|x64.Build.0 = Debug|x64 - {114CAA59-46C0-4B87-BA86-C1946A68101D}.Debug|x86.ActiveCfg = Debug|Win32 - {114CAA59-46C0-4B87-BA86-C1946A68101D}.Debug|x86.Build.0 = Debug|Win32 - {114CAA59-46C0-4B87-BA86-C1946A68101D}.Release|x64.ActiveCfg = Release|x64 - {114CAA59-46C0-4B87-BA86-C1946A68101D}.Release|x64.Build.0 = Release|x64 - {114CAA59-46C0-4B87-BA86-C1946A68101D}.Release|x86.ActiveCfg = Release|Win32 - {114CAA59-46C0-4B87-BA86-C1946A68101D}.Release|x86.Build.0 = Release|Win32 {890C6129-286F-4CD8-8252-FB8D3B4E6E1B}.Debug|x64.ActiveCfg = Debug|x64 {890C6129-286F-4CD8-8252-FB8D3B4E6E1B}.Debug|x64.Build.0 = Debug|x64 {890C6129-286F-4CD8-8252-FB8D3B4E6E1B}.Debug|x86.ActiveCfg = Debug|Win32 @@ -369,7 +353,6 @@ Global {8EC56B06-5A9A-4D6D-804D-037FE26FD43E} = {A8096E32-E084-4FA0-AE01-A8D909EB2BB4} {CD9740CE-C96E-49B3-823F-012E09D17806} = {A8096E32-E084-4FA0-AE01-A8D909EB2BB4} {BF295BA9-4BF8-43F8-8CBF-FAE84815466C} = {A8096E32-E084-4FA0-AE01-A8D909EB2BB4} - {114CAA59-46C0-4B87-BA86-C1946A68101D} = {A8096E32-E084-4FA0-AE01-A8D909EB2BB4} {890C6129-286F-4CD8-8252-FB8D3B4E6E1B} = {A8096E32-E084-4FA0-AE01-A8D909EB2BB4} {FC568FF0-60F2-4B2E-AF62-FD392EDBA1B9} = {A8096E32-E084-4FA0-AE01-A8D909EB2BB4} {484A8CDE-B949-4BDA-B447-74685C8E032F} = {A8096E32-E084-4FA0-AE01-A8D909EB2BB4} diff --git a/contrib/win32/openssh/config.h.vs b/contrib/win32/openssh/config.h.vs index 28592f7..7d5ea2e 100644 --- a/contrib/win32/openssh/config.h.vs +++ b/contrib/win32/openssh/config.h.vs @@ -1681,13 +1681,12 @@ /* Windows specific macro added to workaround mysignal implementaion in bsd-misc.c */ #define HAVE_MYSIGNAL 1 + #define PATH_MAX MAX_PATH - #define S_IFIFO 0x1000 - #define HAVE_EXPLICIT_BZERO - #define HAVE_MBTOWC 1 +#define HAVE_LLABS 1 #include #include diff --git a/contrib/win32/openssh/config.vcxproj b/contrib/win32/openssh/config.vcxproj index 9bf9ee2..1b1ea34 100644 --- a/contrib/win32/openssh/config.vcxproj +++ b/contrib/win32/openssh/config.vcxproj @@ -117,6 +117,10 @@ Generate crtheaders.h and config.h + + copy /Y $(SolutionDir)install-ssh*ps1 $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ & copy /Y $(SolutionDir)uninstall-ssh*ps1 $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ & If NOT exist $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\sshd_config (copy $(SolutionDir)sshd_config $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\) + Copy install-sshd.ps1, uninstall-sshd.ps1 and sshd_config (if not already present) to build directory + @@ -141,6 +145,10 @@ Generate crtheaders.h and config.h + + copy /Y $(SolutionDir)install-ssh*ps1 $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ & copy /Y $(SolutionDir)uninstall-ssh*ps1 $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ & If NOT exist $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\sshd_config (copy $(SolutionDir)sshd_config $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\) + Copy install-sshd.ps1, uninstall-sshd.ps1 and sshd_config (if not already present) to build directory + @@ -169,6 +177,10 @@ Generate crtheaders.h and config.h + + copy /Y $(SolutionDir)install-ssh*ps1 $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ & copy /Y $(SolutionDir)uninstall-ssh*ps1 $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ & If NOT exist $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\sshd_config (copy $(SolutionDir)sshd_config $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\) + Copy install-sshd.ps1, uninstall-sshd.ps1 and sshd_config (if not already present) to build directory + @@ -197,6 +209,10 @@ Generate crtheaders.h and config.h + + copy /Y $(SolutionDir)install-ssh*ps1 $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ & copy /Y $(SolutionDir)uninstall-ssh*ps1 $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ & If NOT exist $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\sshd_config (copy $(SolutionDir)sshd_config $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\) + Copy install-sshd.ps1, uninstall-sshd.ps1 and sshd_config (if not already present) to build directory + diff --git a/contrib/win32/openssh/install-sshd.ps1 b/contrib/win32/openssh/install-sshd.ps1 index f0f2b78..fbdc565 100644 --- a/contrib/win32/openssh/install-sshd.ps1 +++ b/contrib/win32/openssh/install-sshd.ps1 @@ -1,5 +1,6 @@ # @manojampalam - authored initial script # @friism - Fixed issue with invalid SDDL on Set-Acl +# @manojampalam - removed ntrights.exe dependency $scriptpath = $MyInvocation.MyCommand.Path $scriptdir = Split-Path $scriptpath @@ -8,8 +9,71 @@ $sshdpath = Join-Path $scriptdir "sshd.exe" $sshagentpath = Join-Path $scriptdir "ssh-agent.exe" $logsdir = Join-Path $scriptdir "logs" -$account = "NT SERVICE\SSHD" -$ntrights = "ntrights.exe -u `"{0}`" +r SeAssignPrimaryTokenPrivilege" -f $account +$sshdAccount = "NT SERVICE\SSHD" + +#Idea borrowed from http://sqldbamusings.blogspot.com/2012/03/powershell-adding-accounts-to-local.html +function Add-Privilege +{ + param( + [string] $Account, + + [ValidateSet("SeAssignPrimaryTokenPrivilege", "SeServiceLogonRight")] + [string] $Privilege + ) + + #Get $Account SID + $account_sid = $null + try + { + $ntprincipal = new-object System.Security.Principal.NTAccount "$Account" + $sid = $ntprincipal.Translate([System.Security.Principal.SecurityIdentifier]) + $account_sid = $sid.Value.ToString() + } + catch + { + Throw 'Unable to resolve '+ $Account + } + + #Prepare policy settings file to be applied + $settings_to_export = [System.IO.Path]::GetTempFileName() + "[Unicode]" | Set-Content $settings_to_export -Encoding Unicode + "Unicode=yes" | Add-Content $settings_to_export -Force -WhatIf:$false + "[Version]" | Add-Content $settings_to_export -Force -WhatIf:$false + "signature=`"`$CHICAGO`$`"" | Add-Content $settings_to_export -Force -WhatIf:$false + "Revision=1" | Add-Content $settings_to_export -Force -WhatIf:$false + "[Privilege Rights]" | Add-Content $settings_to_export -Force -WhatIf:$false + + #Get Current policy settings + $imported_settings = [System.IO.Path]::GetTempFileName() + secedit.exe /export /areas USER_RIGHTS /cfg "$($imported_settings)" > $null + + if (-not(Test-Path $imported_settings)) { + Throw "Unable to import current security policy settings" + } + + #find current assigned accounts to $Privilege and add it to $settings_to_export + $current_settings = Get-Content $imported_settings -Encoding Unicode + $existing_setting = $null + foreach ($setting in $current_settings) { + if ($setting -like "$Privilege`*") { + $existing_setting = $setting + } + } + + #Add $account_sid to list + if ($existing_setting -eq $null) { + $Privilege + " = *" + $account_sid | Add-Content $settings_to_export -Force -WhatIf:$false + } + else + { + $existing_setting + ",*" + $account_sid | Add-Content $settings_to_export -Force -WhatIf:$false + } + + #export + secedit.exe /configure /db "secedit.sdb" /cfg "$($settings_to_export)" /areas USER_RIGHTS > $null + +} + if (-not (Test-Path $sshdpath)) { throw "sshd.exe is not present in script path" @@ -30,20 +94,18 @@ if (Get-Service ssh-agent -ErrorAction SilentlyContinue) New-Service -Name ssh-agent -BinaryPathName $sshagentpath -Description "SSH Agent" -StartupType Manual | Out-Null cmd.exe /c 'sc.exe sdset ssh-agent D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)(A;;RP;;;AU)' -New-Service -Name sshd -BinaryPathName $sshdpath -Description "SSH Deamon" -StartupType Manual -DependsOn ssh-agent | Out-Null -sc.exe config sshd obj= $account +New-Service -Name sshd -BinaryPathName $sshdpath -Description "SSH Daemon" -StartupType Manual -DependsOn ssh-agent | Out-Null +sc.exe config sshd obj= $sshdAccount -Push-Location -cd $scriptdir -cmd.exe /c $ntrights -Pop-Location +Add-Privilege -Account $sshdAccount -Privilege SeAssignPrimaryTokenPrivilege +Add-Privilege -Account $sshdAccount -Privilege SeServiceLogonRight if(-not (test-path $logsdir -PathType Container)) { $null = New-Item $logsdir -ItemType Directory -Force -ErrorAction Stop } $rights = [System.Security.AccessControl.FileSystemRights]"Read, Write" -$accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($account, $rights, "ContainerInherit,ObjectInherit", "None", "Allow") +$accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($sshdAccount, $rights, "ContainerInherit,ObjectInherit", "None", "Allow") $acl = Get-Acl -Path $logsdir $Acl.SetAccessRule($accessRule) Set-Acl -Path $logsdir -AclObject $acl diff --git a/contrib/win32/openssh/ssh.vcxproj b/contrib/win32/openssh/ssh.vcxproj index f3297a1..d727934 100644 --- a/contrib/win32/openssh/ssh.vcxproj +++ b/contrib/win32/openssh/ssh.vcxproj @@ -290,7 +290,6 @@ - @@ -299,7 +298,8 @@ - + + diff --git a/contrib/win32/openssh/ssh.vcxproj.filters b/contrib/win32/openssh/ssh.vcxproj.filters index 56187a3..8acdd0e 100644 --- a/contrib/win32/openssh/ssh.vcxproj.filters +++ b/contrib/win32/openssh/ssh.vcxproj.filters @@ -305,10 +305,10 @@ Source Files - + Source Files - + Source Files diff --git a/contrib/win32/openssh/sshd.vcxproj b/contrib/win32/openssh/sshd.vcxproj index 1410453..d6e0f6f 100644 --- a/contrib/win32/openssh/sshd.vcxproj +++ b/contrib/win32/openssh/sshd.vcxproj @@ -222,6 +222,7 @@ + @@ -244,9 +245,8 @@ - + - diff --git a/contrib/win32/openssh/sshd.vcxproj.filters b/contrib/win32/openssh/sshd.vcxproj.filters index 96135ea..017b052 100644 --- a/contrib/win32/openssh/sshd.vcxproj.filters +++ b/contrib/win32/openssh/sshd.vcxproj.filters @@ -144,15 +144,15 @@ Source Files - - Source Files - Source Files Source Files + + Source Files + diff --git a/contrib/win32/openssh/sshd_config b/contrib/win32/openssh/sshd_config index 97cd8e8..651af0b 100644 --- a/contrib/win32/openssh/sshd_config +++ b/contrib/win32/openssh/sshd_config @@ -119,4 +119,4 @@ Subsystem sftp sftp-server.exe # X11Forwarding no # AllowTcpForwarding no # ForceCommand cvs server -PubkeyAcceptedKeyTypes ssh-ed25519* \ No newline at end of file +# PubkeyAcceptedKeyTypes ssh-ed25519* \ No newline at end of file diff --git a/contrib/win32/openssh/version.rc b/contrib/win32/openssh/version.rc index 8b8517b..c3fdf82 100644 Binary files a/contrib/win32/openssh/version.rc and b/contrib/win32/openssh/version.rc differ diff --git a/contrib/win32/openssh/win32iocompat.vcxproj b/contrib/win32/openssh/win32iocompat.vcxproj index cff5e2d..c2b0024 100644 --- a/contrib/win32/openssh/win32iocompat.vcxproj +++ b/contrib/win32/openssh/win32iocompat.vcxproj @@ -204,8 +204,9 @@ + - + diff --git a/contrib/win32/openssh/win32iocompat.vcxproj.filters b/contrib/win32/openssh/win32iocompat.vcxproj.filters index 77a05a3..2152b5f 100644 --- a/contrib/win32/openssh/win32iocompat.vcxproj.filters +++ b/contrib/win32/openssh/win32iocompat.vcxproj.filters @@ -139,8 +139,9 @@ inc + - + diff --git a/contrib/win32/win32compat/Debug.h b/contrib/win32/win32compat/Debug.h index 8da03fa..fd47031 100644 --- a/contrib/win32/win32compat/Debug.h +++ b/contrib/win32/win32compat/Debug.h @@ -1,39 +1,10 @@ -/* - * Author: NoMachine - * - * Copyright (c) 2009, 2011 NoMachine - * All rights reserved - * - * Support functions and system calls' replacements needed to let the - * software run on Win32 based operating systems. - * - * 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. - */ +#pragma once -#ifndef Debug_H -#define Debug_H - -#define FAIL(CONDITION) if (CONDITION) goto fail - -#define NTFAIL(NTFUNC) if((ntStat = (NTFUNC))) goto fail - -#endif +/* Enable the following for verbose logging */ +#if (0) +#define debug4 debug2 +#define debug5 debug3 +#else +#define debug4(a,...) +#define debug5(a,...) +#endif \ No newline at end of file diff --git a/contrib/win32/win32compat/console.c b/contrib/win32/win32compat/console.c index 7ec2eeb..1165012 100644 --- a/contrib/win32/win32compat/console.c +++ b/contrib/win32/win32compat/console.c @@ -38,10 +38,6 @@ #include "console.h" -#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING -#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x4 -#endif - HANDLE hOutputConsole = NULL; DWORD dwSavedAttributes = 0; WORD wStartingAttributes = 0; @@ -140,7 +136,7 @@ ConEnterRawMode(DWORD OutputHandle, BOOL fSmartInit) SavedViewRect = csbi.srWindow; debug("console doesn't support the ansi parsing"); } else { - ConMoveCurosorTop(csbi); + ConMoveCursorTop(csbi); debug("console supports the ansi parsing"); } @@ -1075,16 +1071,27 @@ ConScrollUp(int topline, int botline) ); } -void +void ConMoveVisibleWindow(int offset) { CONSOLE_SCREEN_BUFFER_INFO consoleInfo; SMALL_RECT visibleWindowRect; if (GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) { - memcpy(&visibleWindowRect, &consoleInfo.srWindow, sizeof(visibleWindowRect)); - visibleWindowRect.Top += offset; - visibleWindowRect.Bottom += offset; + /* Check if applying the offset results in console buffer overflow. + * if yes, then scrolldown the console buffer. + */ + if ((consoleInfo.srWindow.Bottom + offset) >= (consoleInfo.dwSize.Y - 1)) { + for (int i = 0; i < offset; i++) + ConScrollDown(0, consoleInfo.dwSize.Y - 1); + + if (GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) + memcpy(&visibleWindowRect, &consoleInfo.srWindow, sizeof(visibleWindowRect)); + } else { + memcpy(&visibleWindowRect, &consoleInfo.srWindow, sizeof(visibleWindowRect)); + visibleWindowRect.Top += offset; + visibleWindowRect.Bottom += offset; + } SetConsoleWindowInfo(hOutputConsole, TRUE, &visibleWindowRect); } @@ -1552,10 +1559,48 @@ ConSaveWindowsState() } void -ConMoveCurosorTop(CONSOLE_SCREEN_BUFFER_INFO csbi) +ConMoveCursorTop(CONSOLE_SCREEN_BUFFER_INFO csbi) { + /* Windows server at first sends the "cls" after the connection is established. + * Since we don't want to loose any data on the console, we would like to scroll down + * the visible window. + */ int offset = csbi.dwCursorPosition.Y - csbi.srWindow.Top; ConMoveVisibleWindow(offset); ConSaveViewRect(); } + +HANDLE +get_console_handle(FILE *stream, DWORD * mode) +{ + int file_num = 0, ret = 0; + intptr_t lHandle = 0; + HANDLE hFile = NULL; + DWORD type = 0; + + file_num = (_fileno)(stream); + if (file_num == -1) { + return -1; + } + lHandle = _get_osfhandle(file_num); + if (lHandle == -1 && errno == EBADF) { + return -1; + } + type = GetFileType((HANDLE)lHandle); + if (type == FILE_TYPE_CHAR && file_num >= 0 && file_num <= 2) { + if (file_num == 0) + hFile = GetStdHandle(STD_INPUT_HANDLE); + else if (file_num == 1) + hFile = GetStdHandle(STD_OUTPUT_HANDLE); + else if (file_num == 2) + hFile = GetStdHandle(STD_ERROR_HANDLE); + + if ((hFile != NULL) && + (hFile != INVALID_HANDLE_VALUE) && + (GetFileType(hFile) == FILE_TYPE_CHAR) && + GetConsoleMode(hFile, mode)) + return hFile; + } + return INVALID_HANDLE_VALUE; +} diff --git a/contrib/win32/win32compat/console.h b/contrib/win32/win32compat/console.h index c98386d..46c73bf 100644 --- a/contrib/win32/win32compat/console.h +++ b/contrib/win32/win32compat/console.h @@ -79,6 +79,10 @@ #define false FALSE #define bool BOOL +#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING +#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x4 +#endif + typedef void * SCREEN_HANDLE; int ConEnterRawMode(DWORD OutputHandle, BOOL fSmartInit); @@ -137,5 +141,6 @@ void ConSaveWindowsState(); void ConMoveVisibleWindow(int offset); int is_cursor_at_lastline_of_visible_window(); void ConGetCursorPosition(int *x, int *y); -void ConMoveCurosorTop(CONSOLE_SCREEN_BUFFER_INFO csbi); +void ConMoveCursorTop(CONSOLE_SCREEN_BUFFER_INFO csbi); +HANDLE get_console_handle(FILE *, DWORD *); #endif diff --git a/contrib/win32/win32compat/fileio.c b/contrib/win32/win32compat/fileio.c index 5fb40c8..49da1ad 100644 --- a/contrib/win32/win32compat/fileio.c +++ b/contrib/win32/win32compat/fileio.c @@ -39,6 +39,7 @@ #include "inc\utf.h" #include "inc\fcntl.h" #include "misc_internal.h" +#include "debug.h" /* internal read buffer size */ #define READ_BUFFER_SIZE 100*1024 @@ -97,7 +98,7 @@ fileio_connect(struct w32_io* pio, char* name) int ret = 0; if (pio->handle != 0 && pio->handle != INVALID_HANDLE_VALUE) { - debug("fileio_connect called in unexpected state, pio = %p", pio); + debug3("fileio_connect called in unexpected state, pio = %p", pio); errno = EOTHER; ret = -1; goto cleanup; @@ -114,13 +115,13 @@ fileio_connect(struct w32_io* pio, char* name) /* TODO - support nonblocking connect */ /* wait until we have a server pipe instance to connect */ while (h == INVALID_HANDLE_VALUE && GetLastError() == ERROR_PIPE_BUSY) { - debug2("waiting for agent connection, retrying after 1 sec"); + debug4("waiting for agent connection, retrying after 1 sec"); if ((ret = wait_for_any_event(NULL, 0, 1000) != 0) != 0) goto cleanup; } if (h == INVALID_HANDLE_VALUE) { - debug("unable to connect to pipe %ls, error: %d", name_w, GetLastError()); + debug3("unable to connect to pipe %ls, error: %d", name_w, GetLastError()); errno = errno_from_Win32LastError(); ret = -1; goto cleanup; @@ -129,7 +130,7 @@ fileio_connect(struct w32_io* pio, char* name) if (SetHandleInformation(h, HANDLE_FLAG_INHERIT, pio->fd_flags & FD_CLOEXEC ? 0 : HANDLE_FLAG_INHERIT) == FALSE) { errno = errno_from_Win32LastError(); - debug("SetHandleInformation failed, error = %d, pio = %p", GetLastError(), pio); + debug3("SetHandleInformation failed, error = %d, pio = %p", GetLastError(), pio); ret = -1; goto cleanup; } @@ -162,7 +163,7 @@ fileio_pipe(struct w32_io* pio[2]) if (pio == NULL) { errno = EINVAL; - debug("pipe - ERROR invalid parameter"); + debug3("pipe - ERROR invalid parameter"); return -1; } @@ -170,7 +171,7 @@ fileio_pipe(struct w32_io* pio[2]) if (-1 == sprintf_s(pipe_name, PATH_MAX, "\\\\.\\Pipe\\W32PosixPipe.%08x.%08x", GetCurrentProcessId(), pipe_counter++)) { errno = EOTHER; - debug("pipe - ERROR sprintf_s %d", errno); + debug3("pipe - ERROR sprintf_s %d", errno); goto error; } @@ -179,31 +180,31 @@ fileio_pipe(struct w32_io* pio[2]) sec_attributes.nLength = 0; /* create named pipe */ - read_handle = CreateNamedPipeA(pipe_name, - PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, + write_handle = CreateNamedPipeA(pipe_name, + PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_WAIT, 1, 4096, 4096, 0, &sec_attributes); - if (read_handle == INVALID_HANDLE_VALUE) { + if (write_handle == INVALID_HANDLE_VALUE) { errno = errno_from_Win32LastError(); - debug("pipe - CreateNamedPipe() ERROR:%d", errno); + debug3("pipe - CreateNamedPipe() ERROR:%d", errno); goto error; } /* connect to named pipe */ - write_handle = CreateFileA(pipe_name, - GENERIC_WRITE, + read_handle = CreateFileA(pipe_name, + GENERIC_READ, 0, &sec_attributes, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); - if (write_handle == INVALID_HANDLE_VALUE) { + if (read_handle == INVALID_HANDLE_VALUE) { errno = errno_from_Win32LastError(); - debug("pipe - ERROR CreateFile() :%d", errno); + debug3("pipe - ERROR CreateFile() :%d", errno); goto error; } @@ -213,7 +214,7 @@ fileio_pipe(struct w32_io* pio[2]) if (!pio_read || !pio_write) { errno = ENOMEM; - debug("pip - ERROR:%d", errno); + debug3("pip - ERROR:%d", errno); goto error; } @@ -252,21 +253,21 @@ createFile_flags_setup(int flags, int mode, struct createFile_flags* cf_flags) * O_RDONLY, O_WRONLY, or O_RDWR */ if ((rwflags != O_RDONLY) && (rwflags != O_WRONLY) && (rwflags != O_RDWR)) { - debug("open - flags ERROR: wrong rw flags: %d", flags); + debug3("open - flags ERROR: wrong rw flags: %d", flags); errno = EINVAL; return -1; } /*only following create and status flags currently supported*/ if (c_s_flags & ~(O_NONBLOCK | O_APPEND | O_CREAT | O_TRUNC | O_EXCL | O_BINARY)) { - debug("open - ERROR: Unsupported flags: %d", flags); + debug3("open - ERROR: Unsupported flags: %d", flags); errno = ENOTSUP; return -1; } /*validate mode*/ if (mode &~(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) { - debug("open - ERROR: unsupported mode: %d", mode); + debug3("open - ERROR: unsupported mode: %d", mode); errno = ENOTSUP; return -1; } @@ -310,6 +311,8 @@ createFile_flags_setup(int flags, int mode, struct createFile_flags* cf_flags) return 0; } + +#define NULL_DEVICE "/dev/null" /* open() implementation. Uses CreateFile to open file, console, device, etc */ struct w32_io* fileio_open(const char *path_utf8, int flags, int mode) @@ -319,17 +322,21 @@ fileio_open(const char *path_utf8, int flags, int mode) HANDLE handle; wchar_t *path_utf16 = NULL; - debug2("open - pathname:%s, flags:%d, mode:%d", path_utf8, flags, mode); + debug4("open - pathname:%s, flags:%d, mode:%d", path_utf8, flags, mode); /* check input params*/ if (path_utf8 == NULL) { errno = EINVAL; - debug("open - ERROR:%d", errno); + debug3("open - ERROR:%d", errno); return NULL; } + /* if opening null device, point to Windows equivalent */ + if (strncmp(path_utf8, NULL_DEVICE, strlen(NULL_DEVICE)) == 0) + path_utf8 = "NUL"; + if ((path_utf16 = utf8_to_utf16(path_utf8)) == NULL) { errno = ENOMEM; - debug("utf8_to_utf16 failed for file:%s error:%d", path_utf8, GetLastError()); + debug3("utf8_to_utf16 failed for file:%s error:%d", path_utf8, GetLastError()); return NULL; } @@ -342,7 +349,7 @@ fileio_open(const char *path_utf8, int flags, int mode) if (handle == INVALID_HANDLE_VALUE) { errno = errno_from_Win32LastError(); - debug("failed to open file:%s error:%d", path_utf8, GetLastError()); + debug3("failed to open file:%s error:%d", path_utf8, GetLastError()); free(path_utf16); return NULL; } @@ -352,7 +359,7 @@ fileio_open(const char *path_utf8, int flags, int mode) if (pio == NULL) { CloseHandle(handle); errno = ENOMEM; - debug("fileio_open(), failed to allocate memory error:%d", errno); + debug3("fileio_open(), failed to allocate memory error:%d", errno); return NULL; } @@ -369,7 +376,7 @@ VOID CALLBACK ReadCompletionRoutine(_In_ DWORD dwErrorCode, _In_ DWORD dwNumberOfBytesTransfered, _Inout_ LPOVERLAPPED lpOverlapped) { struct w32_io* pio = (struct w32_io*)((char*)lpOverlapped - offsetof(struct w32_io, read_overlapped)); - debug2("ReadCB pio:%p, pending_state:%d, error:%d, received:%d", + debug4("ReadCB pio:%p, pending_state:%d, error:%d, received:%d", pio, pio->read_details.pending, dwErrorCode, dwNumberOfBytesTransfered); pio->read_details.error = dwErrorCode; pio->read_details.remaining = dwNumberOfBytesTransfered; @@ -383,13 +390,13 @@ ReadCompletionRoutine(_In_ DWORD dwErrorCode, _In_ DWORD dwNumberOfBytesTransfer int fileio_ReadFileEx(struct w32_io* pio, unsigned int bytes_requested) { - debug2("ReadFileEx io:%p", pio); + debug4("ReadFileEx io:%p", pio); if (pio->read_details.buf == NULL) { pio->read_details.buf = malloc(READ_BUFFER_SIZE); if (!pio->read_details.buf) { errno = ENOMEM; - debug2("ReadFileEx - ERROR: %d, io:%p", errno, pio); + debug4("ReadFileEx - ERROR: %d, io:%p", errno, pio); return -1; } } @@ -404,7 +411,7 @@ fileio_ReadFileEx(struct w32_io* pio, unsigned int bytes_requested) pio->read_details.pending = TRUE; else { errno = errno_from_Win32LastError(); - debug("ReadFileEx() ERROR:%d, io:%p", GetLastError(), pio); + debug3("ReadFileEx() ERROR:%d, io:%p", GetLastError(), pio); return -1; } @@ -417,18 +424,18 @@ fileio_read(struct w32_io* pio, void *dst, unsigned int max) { int bytes_copied; - debug3("read - io:%p remaining:%d", pio, pio->read_details.remaining); + debug5("read - io:%p remaining:%d", pio, pio->read_details.remaining); /* if read is pending */ if (pio->read_details.pending) { if (w32_io_is_blocking(pio)) { - debug2("read - io is pending, blocking call made, io:%p", pio); + debug4("read - io is pending, blocking call made, io:%p", pio); while (fileio_is_io_available(pio, TRUE) == FALSE) { if (-1 == wait_for_any_event(NULL, 0, INFINITE)) return -1; } } errno = EAGAIN; - debug2("read - io is already pending, io:%p", pio); + debug4("read - io is already pending, io:%p", pio); return -1; } @@ -442,14 +449,14 @@ fileio_read(struct w32_io* pio, void *dst, unsigned int max) if ((FILETYPE(pio) == FILE_TYPE_PIPE) && (errno == ERROR_BROKEN_PIPE)) { /* write end of the pipe closed */ - debug("read - no more data, io:%p", pio); + debug3("read - no more data, io:%p", pio); errno = 0; return 0; } /* on W2012, ReadFileEx on file throws a synchronous EOF error*/ else if ((FILETYPE(pio) == FILE_TYPE_DISK) && (errno == ERROR_HANDLE_EOF)) { - debug("read - no more data, io:%p", pio); + debug3("read - no more data, io:%p", pio); errno = 0; return 0; } @@ -468,7 +475,7 @@ fileio_read(struct w32_io* pio, void *dst, unsigned int max) } else if (pio->read_details.pending) { errno = EAGAIN; - debug2("read - IO is pending, io:%p", pio); + debug4("read - IO is pending, io:%p", pio); return -1; } } @@ -478,12 +485,12 @@ fileio_read(struct w32_io* pio, void *dst, unsigned int max) /*write end of the pipe is closed or pipe broken or eof reached*/ if ((pio->read_details.error == ERROR_BROKEN_PIPE) || (pio->read_details.error == ERROR_HANDLE_EOF)) { - debug2("read - (2) no more data, io:%p", pio); + debug4("read - (2) no more data, io:%p", pio); errno = 0; pio->read_details.error = 0; return 0; } - debug("read - ERROR from cb :%d, io:%p", errno, pio); + debug3("read - ERROR from cb :%d, io:%p", errno, pio); pio->read_details.error = 0; return -1; } @@ -492,7 +499,7 @@ fileio_read(struct w32_io* pio, void *dst, unsigned int max) memcpy(dst, pio->read_details.buf + pio->read_details.completed, bytes_copied); pio->read_details.remaining -= bytes_copied; pio->read_details.completed += bytes_copied; - debug2("read - io:%p read: %d remaining: %d", pio, bytes_copied, + debug4("read - io:%p read: %d remaining: %d", pio, bytes_copied, pio->read_details.remaining); return bytes_copied; } @@ -504,13 +511,13 @@ WriteCompletionRoutine(_In_ DWORD dwErrorCode, { struct w32_io* pio = (struct w32_io*)((char*)lpOverlapped - offsetof(struct w32_io, write_overlapped)); - debug2("WriteCB - pio:%p, pending_state:%d, error:%d, transferred:%d of remaining: %d", + debug4("WriteCB - pio:%p, pending_state:%d, error:%d, transferred:%d of remaining: %d", pio, pio->write_details.pending, dwErrorCode, dwNumberOfBytesTransfered, pio->write_details.remaining); pio->write_details.error = dwErrorCode; /* TODO - assert that remaining == dwNumberOfBytesTransfered */ if ((dwErrorCode == 0) && (pio->write_details.remaining != dwNumberOfBytesTransfered)) { - debug("WriteCB - ERROR: broken assumption, io:%p, wrote:%d, remaining:%d", pio, + debug3("WriteCB - ERROR: broken assumption, io:%p, wrote:%d, remaining:%d", pio, dwNumberOfBytesTransfered, pio->write_details.remaining); DebugBreak(); } @@ -524,27 +531,28 @@ int fileio_write(struct w32_io* pio, const void *buf, unsigned int max) { int bytes_copied; + DWORD pipe_flags = 0, pipe_instances = 0; - debug2("write - io:%p", pio); + debug4("write - io:%p", pio); if (pio->write_details.pending) { if (w32_io_is_blocking(pio)) { - debug2("write - io pending, blocking call made, io:%p", pio); + debug4("write - io pending, blocking call made, io:%p", pio); while (pio->write_details.pending) if (wait_for_any_event(NULL, 0, INFINITE) == -1) return -1; } else { errno = EAGAIN; - debug2("write - IO is already pending, io:%p", pio); + debug4("write - IO is already pending, io:%p", pio); return -1; } } if (pio->write_details.error) { errno = errno_from_Win32Error(pio->write_details.error); - debug("write - ERROR:%d on prior unblocking write, io:%p", errno, pio); + debug3("write - ERROR:%d on prior unblocking write, io:%p", errno, pio); pio->write_details.error = 0; if ((FILETYPE(pio) == FILE_TYPE_PIPE) && (errno == ERROR_BROKEN_PIPE)) { - debug("write - ERROR:read end of the pipe closed, io:%p", pio); + debug3("write - ERROR:read end of the pipe closed, io:%p", pio); errno = EPIPE; } return -1; @@ -554,7 +562,7 @@ fileio_write(struct w32_io* pio, const void *buf, unsigned int max) pio->write_details.buf = malloc(WRITE_BUFFER_SIZE); if (pio->write_details.buf == NULL) { errno = ENOMEM; - debug("write - ERROR:%d, io:%p", errno, pio); + debug3("write - ERROR:%d, io:%p", errno, pio); return -1; } pio->write_details.buf_size = WRITE_BUFFER_SIZE; @@ -570,6 +578,39 @@ fileio_write(struct w32_io* pio, const void *buf, unsigned int max) } else return -1; + } else if ( FILETYPE(pio) == FILE_TYPE_PIPE && + GetNamedPipeInfo(WINHANDLE(pio), &pipe_flags, NULL, NULL, &pipe_instances) && + pipe_flags == PIPE_CLIENT_END && pipe_instances == 1) { + /* + * TODO - Figure out a better solution to this problem + * IO handle corresponding to this object (pio->handle) may be referring + * to something that isn't opened in overlapped mode. While all handles + * opened by this POSIX wrapper are opened in overlapped mode, other handles + * that are inherited (ex. via std i/o) are typically not. + * Ex. When we do this in Powershell + * $o = ssh.exe user@target hostname + * Powershell creates anonymous pipes (that do not support overlapped i.o) + * Calling asynchronous I/O APIs (WriteFileEx) for example will not work in + * those cases (the callback is never called and it typically manifests as a + * hang to end user + * + * This conditional logic is put in place to specifically handle Powershell + * redirection scenarios. Thinking behind these conditions + * - should be a pipe handle. console I/O is handled in termio.c, impacting file i/o + * scenarios not found yet. + * - pipe should be the client end. This is to skip pipes created internally in POSIX + * wrapper (by pipe() calls) - The write ends on these pipes are on server + * - pipe_instances == 1. This is to skip pipe handles created as part of Connect(AF_UNIX) + * sockets (that typically are created for unlimited instances). + * For such I/O we do a synchronous write. + */ + /* DebugBreak() */; + if (WriteFile(WINHANDLE(pio), pio->write_details.buf, bytes_copied, &bytes_copied, NULL) == FALSE) { + errno = errno_from_Win32LastError(); + debug3("write - WriteFile() ERROR:%d, io:%p", GetLastError(), pio); + return -1; + } + return bytes_copied; } else { if (WriteFileEx(WINHANDLE(pio), pio->write_details.buf, bytes_copied, &pio->write_overlapped, &WriteCompletionRoutine)) { @@ -579,10 +620,10 @@ fileio_write(struct w32_io* pio, const void *buf, unsigned int max) errno = errno_from_Win32LastError(); /* read end of the pipe closed ? */ if ((FILETYPE(pio) == FILE_TYPE_PIPE) && (errno == ERROR_BROKEN_PIPE)) { - debug("write - ERROR:read end of the pipe closed, io:%p", pio); + debug3("write - ERROR:read end of the pipe closed, io:%p", pio); errno = EPIPE; } - debug("write ERROR from cb(2):%d, io:%p", errno, pio); + debug3("write ERROR from cb(2):%d, io:%p", errno, pio); return -1; } } @@ -604,11 +645,11 @@ fileio_write(struct w32_io* pio, const void *buf, unsigned int max) /* if write has completed, pick up any error reported*/ if (!pio->write_details.pending && pio->write_details.error) { errno = errno_from_Win32Error(pio->write_details.error); - debug("write - ERROR from cb:%d, io:%p", pio->write_details.error, pio); + debug3("write - ERROR from cb:%d, io:%p", pio->write_details.error, pio); pio->write_details.error = 0; return -1; } - debug2("write - reporting %d bytes written, io:%p", bytes_copied, pio); + debug4("write - reporting %d bytes written, io:%p", bytes_copied, pio); return bytes_copied; } @@ -618,7 +659,7 @@ int fileio_fstat(struct w32_io* pio, struct _stat64 *buf) { int fd = _open_osfhandle((intptr_t)pio->handle, 0); - debug2("fstat - pio:%p", pio); + debug4("fstat - pio:%p", pio); if (fd == -1) { errno = EOTHER; return -1; @@ -630,33 +671,31 @@ fileio_fstat(struct w32_io* pio, struct _stat64 *buf) int fileio_stat(const char *path, struct _stat64 *buf) { - wchar_t wpath[PATH_MAX]; - wchar_t* wtmp = NULL; - struct w32_io* pio; + wchar_t* wpath = NULL; + int r = -1; - if ((wtmp = utf8_to_utf16(path)) == NULL) + if ((wpath = utf8_to_utf16(path)) == NULL) fatal("failed to covert input arguments"); - /* If we doesn't have sufficient permissions then _wstat4() is returning - * file not found so added fileio_open() which will set the errorno correctly (access denied) - */ - if (NULL == (pio = fileio_open(path, O_RDONLY, 0))) - return -1; - - fileio_close(pio); + r = _wstat64(wpath, buf); - wcscpy(&wpath[0], wtmp); - free(wtmp); + /* + * If we doesn't have sufficient permissions then _wstat64() is returning "file not found" + * TODO - Replace the above call with GetFileAttributesEx + */ - return _wstat64(wpath, buf); +cleanup: + if (wpath) + free(wpath); + return r; } long fileio_lseek(struct w32_io* pio, long offset, int origin) { - debug2("lseek - pio:%p", pio); + debug4("lseek - pio:%p", pio); if (origin != SEEK_SET) { - debug("lseek - ERROR, origin is not supported %d", origin); + debug3("lseek - ERROR, origin is not supported %d", origin); errno = ENOTSUP; return -1; } @@ -671,7 +710,7 @@ FILE* fileio_fdopen(struct w32_io* pio, const char *mode) { int fd_flags = 0; - debug2("fdopen - io:%p", pio); + debug4("fdopen - io:%p", pio); /* logic below doesn't work with overlapped file HANDLES */ if (mode[1] == '\0') { @@ -686,12 +725,12 @@ fileio_fdopen(struct w32_io* pio, const char *mode) break; default: errno = ENOTSUP; - debug("fdopen - ERROR unsupported mode %s", mode); + debug3("fdopen - ERROR unsupported mode %s", mode); return NULL; } } else { errno = ENOTSUP; - debug("fdopen - ERROR unsupported mode %s", mode); + debug3("fdopen - ERROR unsupported mode %s", mode); return NULL; } @@ -699,7 +738,7 @@ fileio_fdopen(struct w32_io* pio, const char *mode) if (fd == -1) { errno = EOTHER; - debug("fdopen - ERROR:%d _open_osfhandle()", errno); + debug3("fdopen - ERROR:%d _open_osfhandle()", errno); return NULL; } @@ -732,7 +771,7 @@ fileio_on_select(struct w32_io* pio, BOOL rd) int fileio_close(struct w32_io* pio) { - debug2("fileclose - pio:%p", pio); + debug4("fileclose - pio:%p", pio); /* handle can be null on AF_UNIX sockets that are not yet connected */ if (WINHANDLE(pio) == 0 || WINHANDLE(pio) == INVALID_HANDLE_VALUE) { diff --git a/contrib/win32/win32compat/inc/unistd.h b/contrib/win32/win32compat/inc/unistd.h index 444dee1..9737ae1 100644 --- a/contrib/win32/win32compat/inc/unistd.h +++ b/contrib/win32/win32compat/inc/unistd.h @@ -81,4 +81,21 @@ char *crypt(const char *key, const char *salt); int link(const char *oldpath, const char *newpath); int readlink(const char *path, char *link, int linklen); -int spawn_child(char* cmd, int in, int out, int err, unsigned long flags); \ No newline at end of file +int spawn_child(char* cmd, char** argv, int in, int out, int err, unsigned long flags); + + +/* + * readpassphrase.h definitions + * cannot create a separate header due to the way + * its included in openbsdcompat.h + */ + +#define RPP_ECHO_OFF 0x00 /* Turn off echo (default). */ +#define RPP_ECHO_ON 0x01 /* Leave echo on. */ +#define RPP_REQUIRE_TTY 0x02 /* Fail if there is no tty. */ +#define RPP_FORCELOWER 0x04 /* Force input to lower case. */ +#define RPP_FORCEUPPER 0x08 /* Force input to upper case. */ +#define RPP_SEVENBIT 0x10 /* Strip the high bit from input. */ +#define RPP_STDIN 0x20 /* Read from stdin, not /dev/tty */ + +char * readpassphrase(const char *, char *, size_t, int); \ No newline at end of file diff --git a/contrib/win32/win32compat/misc.c b/contrib/win32/win32compat/misc.c index 014fa31..93b1af3 100644 --- a/contrib/win32/win32compat/misc.c +++ b/contrib/win32/win32compat/misc.c @@ -33,6 +33,7 @@ #include #include +#include "inc\unistd.h" #include "inc\sys\stat.h" #include "inc\sys\statvfs.h" #include "inc\sys\time.h" @@ -44,6 +45,7 @@ #include "inc\fcntl.h" #include "inc\utf.h" #include "signal_internal.h" +#include "debug.h" static char* s_programdir = NULL; @@ -249,7 +251,7 @@ w32_fopen_utf8(const char *path, const char *mode) 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()); + debug3("WideCharToMultiByte failed for %c - ERROR:%d", path, GetLastError()); return NULL; } @@ -402,15 +404,26 @@ w32_ioctl(int d, int request, ...) } } +/* + * spawn a child process + * - specified by cmd with agruments argv + * - with std handles set to in, out, err + * - flags are passed to CreateProcess call + * + * cmd will be internally decoarated with a set of '"' + * to account for any spaces within the commandline + * this decoration is done only when additional arguments are passed in argv + */ int -spawn_child(char* cmd, int in, int out, int err, DWORD flags) +spawn_child(char* cmd, char** argv, int in, int out, int err, DWORD flags) { PROCESS_INFORMATION pi; STARTUPINFOW si; BOOL b; - char *abs_cmd, *t; - wchar_t * cmd_utf16; - int add_module_path = 0; + char *cmdline, *t, **t1; + DWORD cmdline_len = 0; + wchar_t * cmdline_utf16; + int add_module_path = 0, ret = -1; /* should module path be added */ do { @@ -424,31 +437,57 @@ spawn_child(char* cmd, int in, int out, int err, DWORD flags) add_module_path = 1; } while (0); - /* add current module path to start if needed */ - if (add_module_path) { - char* ctr; - abs_cmd = malloc(strlen(w32_programdir()) + 1 + strlen(cmd) + 1); - if (abs_cmd == NULL) { - errno = ENOMEM; - return -1; - } - ctr = abs_cmd; - memcpy(ctr, w32_programdir(), strlen(w32_programdir())); - ctr += strlen(w32_programdir()); - *ctr++ = '\\'; - memcpy(ctr, cmd, strlen(cmd) + 1); - } else - abs_cmd = cmd; + /* compute total cmdline len*/ + if (add_module_path) + cmdline_len += strlen(w32_programdir()) + 1 + strlen(cmd) + 1 + 2; + else + cmdline_len += strlen(cmd) + 1 + 2; - debug("spawning %s", abs_cmd); - - if ((cmd_utf16 = utf8_to_utf16(abs_cmd)) == NULL) { - errno = ENOMEM; - return -1; + if (argv) { + t1 = argv; + while (*t1) + cmdline_len += strlen(*t1++) + 1 + 2; } - if (abs_cmd != cmd) - free(abs_cmd); + if ((cmdline = malloc(cmdline_len)) == NULL) { + errno = ENOMEM; + goto cleanup; + } + + /* add current module path to start if needed */ + t = cmdline; + if (argv && argv[0]) + *t++ = '\"'; + if (add_module_path) { + memcpy(t, w32_programdir(), strlen(w32_programdir())); + t += strlen(w32_programdir()); + *t++ = '\\'; + } + + memcpy(t, cmd, strlen(cmd)); + t += strlen(cmd); + + if (argv && argv[0]) + *t++ = '\"'; + + if (argv) { + t1 = argv; + while (*t1) { + *t++ = ' '; + *t++ = '\"'; + memcpy(t, *t1, strlen(*t1)); + t += strlen(*t1); + *t++ = '\"'; + t1++; + } + } + + *t = '\0'; + + if ((cmdline_utf16 = utf8_to_utf16(cmdline)) == NULL) { + errno = ENOMEM; + goto cleanup; + } memset(&si, 0, sizeof(STARTUPINFOW)); si.cb = sizeof(STARTUPINFOW); @@ -457,22 +496,29 @@ spawn_child(char* cmd, int in, int out, int err, DWORD flags) si.hStdError = w32_fd_to_handle(err); si.dwFlags = STARTF_USESTDHANDLES; - b = CreateProcessW(NULL, cmd_utf16, NULL, NULL, TRUE, flags, NULL, NULL, &si, &pi); + debug3("spawning %ls", cmdline_utf16); + b = CreateProcessW(NULL, cmdline_utf16, NULL, NULL, TRUE, flags, NULL, NULL, &si, &pi); if (b) { if (register_child(pi.hProcess, pi.dwProcessId) == -1) { TerminateProcess(pi.hProcess, 0); CloseHandle(pi.hProcess); - pi.dwProcessId = -1; + goto cleanup; } CloseHandle(pi.hThread); } else { errno = GetLastError(); - pi.dwProcessId = -1; + goto cleanup; } - free(cmd_utf16); - return pi.dwProcessId; + ret = pi.dwProcessId; +cleanup: + if (cmdline) + free(cmdline); + if (cmdline_utf16) + free(cmdline_utf16); + + return ret; } void @@ -618,13 +664,13 @@ settimes(wchar_t * path, FILETIME *cretime, FILETIME *acttime, FILETIME *modtime if (handle == INVALID_HANDLE_VALUE) { /* TODO - convert Win32 error to errno */ errno = GetLastError(); - debug("w32_settimes - CreateFileW ERROR:%d", errno); + debug3("w32_settimes - CreateFileW ERROR:%d", errno); return -1; } if (SetFileTime(handle, cretime, acttime, modtime) == 0) { errno = GetLastError(); - debug("w32_settimes - SetFileTime ERROR:%d", errno); + debug3("w32_settimes - SetFileTime ERROR:%d", errno); CloseHandle(handle); return -1; } @@ -953,12 +999,12 @@ statvfs(const char *path, struct statvfs *buf) 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); + debug5("path : [%s]", path); + debug5("sectorsPerCluster : [%lu]", sectorsPerCluster); + debug5("bytesPerSector : [%lu]", bytesPerSector); + debug5("bytesPerCluster : [%lu]", sectorsPerCluster * bytesPerSector); + debug5("freeClusters : [%lu]", freeClusters); + debug5("totalClusters : [%lu]", totalClusters); buf->f_bsize = sectorsPerCluster * bytesPerSector; buf->f_frsize = sectorsPerCluster * bytesPerSector; @@ -975,7 +1021,7 @@ statvfs(const char *path, struct statvfs *buf) free(path_utf16); return 0; } else { - debug3("ERROR: Cannot get free space for [%s]. Error code is : %d.\n", path, GetLastError()); + debug5("ERROR: Cannot get free space for [%s]. Error code is : %d.\n", path, GetLastError()); free(path_utf16); return -1; @@ -996,3 +1042,58 @@ w32_strerror(int errnum) return _sys_errlist_ext[errnum - EADDRINUSE]; return strerror(errnum); } +/* + * Temporary implementation of readpassphrase. + * TODO - this needs to be reimplemented as per + * https://linux.die.net/man/3/readpassphrase + */ +char * +readpassphrase(const char *prompt, char *out, size_t out_len, int flags) { + char *askpass = NULL; + char *ret = NULL; + + DWORD mode; + size_t len = 0; + int retr = 0; + + /* prompt user */ + wchar_t* wtmp = utf8_to_utf16(prompt); + if (wtmp == NULL) + fatal("unable to alloc memory"); + _cputws(wtmp); + free(wtmp); + + len = retr = 0; + + while (_kbhit()) + _getch(); + + while (len < out_len) { + out[len] = (unsigned char)_getch(); + + if (out[len] == '\r') { + if (_kbhit()) /* read linefeed if its there */ + _getch(); + break; + } + else if (out[len] == '\n') { + break; + } + else if (out[len] == '\b') { /* backspace */ + if (len > 0) + len--; /* overwrite last character */ + } + else if (out[len] == '\003') { + /* exit on Ctrl+C */ + fatal(""); + } + else { + len++; /* keep reading in the loop */ + } + } + + out[len] = '\0'; /* get rid of the cr/lf */ + _cputs("\n"); /*show a newline as we do not echo password or the line */ + + return out; +} \ No newline at end of file diff --git a/contrib/win32/win32compat/pwd.c b/contrib/win32/win32compat/pwd.c index 7accd81..557a8fb 100644 --- a/contrib/win32/win32compat/pwd.c +++ b/contrib/win32/win32compat/pwd.c @@ -41,6 +41,7 @@ #include "inc\grp.h" #include "inc\utf.h" #include "misc_internal.h" +#include "debug.h" static struct passwd pw; static char* pw_shellpath = NULL; @@ -128,7 +129,7 @@ get_passwd(const char *user_utf8, LPWSTR user_sid) if (user_sid == NULL) { NET_API_STATUS status; if ((status = NetUserGetInfo(udom_utf16, uname_utf16, 23, &user_info)) != NERR_Success) { - debug("NetUserGetInfo() failed with error: %d for user: %ls and domain: %ls \n", status, uname_utf16, udom_utf16); + debug3("NetUserGetInfo() failed with error: %d for user: %ls and domain: %ls \n", status, uname_utf16, udom_utf16); if ((dsStatus = DsGetDcNameW(NULL, udom_utf16, NULL, NULL, DS_DIRECTORY_SERVICE_PREFERRED, &pdc)) != ERROR_SUCCESS) { error("DsGetDcNameW() failed with error: %d \n", dsStatus); @@ -137,14 +138,14 @@ get_passwd(const char *user_utf8, LPWSTR user_sid) } if ((status = NetUserGetInfo(pdc->DomainControllerName, uname_utf16, 23, &user_info)) != NERR_Success) { - debug("NetUserGetInfo() with domainController: %ls failed with error: %d \n", pdc->DomainControllerName, status); + debug3("NetUserGetInfo() with domainController: %ls failed with error: %d \n", pdc->DomainControllerName, status); errno = ENOENT; goto done; } } if (ConvertSidToStringSidW(((LPUSER_INFO_23)user_info)->usri23_user_sid, &user_sid_local) == FALSE) { - debug("NetUserGetInfo() Succeded but ConvertSidToStringSidW() failed with error: %d\n", GetLastError()); + debug3("NetUserGetInfo() Succeded but ConvertSidToStringSidW() failed with error: %d\n", GetLastError()); errno = ENOENT; goto done; } diff --git a/contrib/win32/win32compat/signal.c b/contrib/win32/win32compat/signal.c index 04ff903..035f79c 100644 --- a/contrib/win32/win32compat/signal.c +++ b/contrib/win32/win32compat/signal.c @@ -32,6 +32,7 @@ #include "w32fd.h" #include "signal_internal.h" #include "inc\signal.h" +#include "debug.h" #undef signal #undef raise @@ -56,28 +57,28 @@ extern struct _children children; static VOID CALLBACK sigint_APCProc(_In_ ULONG_PTR dwParam) { - debug3("SIGINT APCProc()"); + debug5("SIGINT APCProc()"); sigaddset(&pending_signals, W32_SIGINT); } static VOID CALLBACK sigterm_APCProc(_In_ ULONG_PTR dwParam) { - debug3("SIGTERM APCProc()"); + debug5("SIGTERM APCProc()"); sigaddset(&pending_signals, W32_SIGTERM); } static VOID CALLBACK sigtstp_APCProc(_In_ ULONG_PTR dwParam) { - debug3("SIGTSTP APCProc()"); + debug5("SIGTSTP APCProc()"); sigaddset(&pending_signals, W32_SIGTSTP); } BOOL WINAPI native_sig_handler(DWORD dwCtrlType) { - debug("Native Ctrl+C handler, CtrlType %d", dwCtrlType); + debug3("Native Ctrl+C handler, CtrlType %d", dwCtrlType); switch (dwCtrlType) { case CTRL_C_EVENT: QueueUserAPC(sigint_APCProc, main_thread, (ULONG_PTR)NULL); @@ -100,7 +101,7 @@ native_sig_handler(DWORD dwCtrlType) static VOID CALLBACK sigwinch_APCProc(_In_ ULONG_PTR dwParam) { - debug3("SIGTERM APCProc()"); + debug5("SIGTERM APCProc()"); sigaddset(&pending_signals, W32_SIGWINCH); } @@ -128,7 +129,7 @@ sighandler_t w32_signal(int signum, sighandler_t handler) { sighandler_t prev; - debug2("signal() sig:%d, handler:%p", signum, handler); + debug4("signal() sig:%d, handler:%p", signum, handler); if (signum >= W32_SIGMAX) { errno = EINVAL; return W32_SIG_ERR; @@ -144,7 +145,7 @@ w32_sigprocmask(int how, const sigset_t *set, sigset_t *oldset) { /* this is only used by sshd to block SIGCHLD while doing waitpid() */ /* our implementation of waidpid() is never interrupted, so no need to implement this for now*/ - debug3("sigprocmask() how:%d"); + debug5("sigprocmask() how:%d"); return 0; } @@ -153,7 +154,7 @@ w32_sigprocmask(int how, const sigset_t *set, sigset_t *oldset) int w32_raise(int sig) { - debug("raise sig:%d", sig); + debug3("raise sig:%d", sig); if (sig == W32_SIGSEGV) return raise(SIGSEGV); /* raise native exception handler*/ @@ -191,7 +192,7 @@ sw_process_pending_signals() sigset_t pending_tmp = pending_signals; BOOL sig_int = FALSE; /* has any signal actually interrupted */ - debug3("process_signals()"); + debug5("process_signals()"); int i, exp[] = { W32_SIGCHLD , W32_SIGINT , W32_SIGALRM, W32_SIGTERM, W32_SIGTSTP, W32_SIGWINCH }; /* check for expected signals*/ @@ -199,7 +200,7 @@ sw_process_pending_signals() sigdelset(&pending_tmp, exp[i]); if (pending_tmp) { /* unexpected signals queued up */ - debug("process_signals() - ERROR unexpected signals in queue: %d", pending_tmp); + debug3("process_signals() - ERROR unexpected signals in queue: %d", pending_tmp); errno = ENOTSUP; DebugBreak(); return -1; @@ -228,7 +229,7 @@ sw_process_pending_signals() DebugBreak(); if (sig_int) { - debug("process_queued_signals: WARNING - A signal has interrupted and was processed"); + debug3("process_queued_signals: WARNING - A signal has interrupted and was processed"); errno = EINTR; return -1; } @@ -257,7 +258,7 @@ wait_for_any_event(HANDLE* events, int num_events, DWORD milli_seconds) num_all_events = num_events + live_children; if (num_all_events > MAXIMUM_WAIT_OBJECTS) { - debug("wait() - ERROR max events reached"); + debug3("wait() - ERROR max events reached"); errno = ENOTSUP; return -1; } @@ -265,7 +266,7 @@ wait_for_any_event(HANDLE* events, int num_events, DWORD milli_seconds) memcpy(all_events, children.handles, live_children * sizeof(HANDLE)); memcpy(all_events + live_children, events, num_events * sizeof(HANDLE)); - debug3("wait() on %d events and %d children", num_events, live_children); + debug5("wait() on %d events and %d children", num_events, live_children); /* TODO - implement signal catching and handling */ if (num_all_events) { DWORD ret = WaitForMultipleObjectsEx(num_all_events, all_events, FALSE, milli_seconds, TRUE); @@ -284,7 +285,7 @@ wait_for_any_event(HANDLE* events, int num_events, DWORD milli_seconds) return 0; } else { /* some other error*/ errno = EOTHER; - debug("ERROR: unxpected wait end: %d", ret); + debug3("ERROR: unxpected wait end: %d", ret); return -1; } } else { @@ -296,7 +297,7 @@ wait_for_any_event(HANDLE* events, int num_events, DWORD milli_seconds) return 0; } else { /* some other error */ errno = EOTHER; - debug("ERROR: unxpected SleepEx error: %d", ret); + debug3("ERROR: unxpected SleepEx error: %d", ret); return -1; } } diff --git a/contrib/win32/win32compat/signal_sigalrm.c b/contrib/win32/win32compat/signal_sigalrm.c index 31f5527..77ca7a1 100644 --- a/contrib/win32/win32compat/signal_sigalrm.c +++ b/contrib/win32/win32compat/signal_sigalrm.c @@ -30,6 +30,7 @@ #include "signal_internal.h" #include "inc\signal.h" +#include "debug.h" struct _timer_info timer_info; extern sigset_t pending_signals; @@ -49,7 +50,7 @@ w32_alarm(unsigned int sec) ULONGLONG sec_passed; int ret = 0; - debug3("alarm() %d secs", sec); + debug5("alarm() %d secs", sec); errno = 0; /* cancel any live timer if seconds is 0*/ if (sec == 0) { @@ -63,7 +64,7 @@ w32_alarm(unsigned int sec) due.QuadPart *= sec; /* this call resets the timer if it is already active */ if (!SetWaitableTimer(timer_info.timer, &due, 0, sigalrm_APC, NULL, FALSE)) { - debug("alram() - ERROR SetWaitableTimer() %d", GetLastError()); + debug3("alram() - ERROR SetWaitableTimer() %d", GetLastError()); return 0;; } diff --git a/contrib/win32/win32compat/signal_sigchld.c b/contrib/win32/win32compat/signal_sigchld.c index 7a43ee7..c9fadc9 100644 --- a/contrib/win32/win32compat/signal_sigchld.c +++ b/contrib/win32/win32compat/signal_sigchld.c @@ -30,6 +30,7 @@ #include "signal_internal.h" #include "inc\sys\wait.h" +#include "debug.h" struct _children children; @@ -38,7 +39,7 @@ register_child(HANDLE child, DWORD pid) { DWORD first_zombie_index; - debug("Register child %p pid %d, %d zombies of %d", child, pid, + debug3("Register child %p pid %d, %d zombies of %d", child, pid, children.num_zombies, children.num_children); if (children.num_children == MAX_CHILDREN) { errno = ENOMEM; @@ -65,7 +66,7 @@ int sw_remove_child_at_index(DWORD index) { DWORD last_non_zombie; - debug("Unregister child at index %d, %d zombies of %d", index, + debug3("Unregister child at index %d, %d zombies of %d", index, children.num_zombies, children.num_children); if ((index >= children.num_children) || (children.num_children == 0)) { @@ -103,7 +104,7 @@ sw_child_to_zombie(DWORD index) DWORD last_non_zombie, zombie_pid; HANDLE zombie_handle; - debug("zombie'ing child at index %d, %d zombies of %d", index, + debug3("zombie'ing child at index %d, %d zombies of %d", index, children.num_zombies, children.num_children); if (index >= children.num_children) { @@ -152,7 +153,7 @@ waitpid(int pid, int *status, int options) DWORD index, ret, ret_id, exit_code, timeout = 0; HANDLE process = NULL; - debug3("waitpid - pid:%d, options:%d", pid, options); + debug5("waitpid - pid:%d, options:%d", pid, options); if (options & (~WNOHANG)) { errno = ENOTSUP; DebugBreak(); diff --git a/contrib/win32/win32compat/socketio.c b/contrib/win32/win32compat/socketio.c index af94683..f935fe3 100644 --- a/contrib/win32/win32compat/socketio.c +++ b/contrib/win32/win32compat/socketio.c @@ -36,6 +36,7 @@ #include #include "w32fd.h" #include "inc\utf.h" +#include "debug.h" #define INTERNAL_SEND_BUFFER_SIZE 70*1024 //70KB #define INTERNAL_RECV_BUFFER_SIZE 70*1024 //70KB @@ -103,7 +104,7 @@ int socketio_acceptEx(struct w32_io* pio) { struct acceptEx_context *context; - debug3("acceptEx - io:%p", pio); + debug5("acceptEx - io:%p", pio); context = (struct acceptEx_context *)pio->internal.context; ResetEvent(pio->read_overlapped.hEvent); @@ -111,7 +112,7 @@ socketio_acceptEx(struct w32_io* pio) context->accept_socket = socket(AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); if (context->accept_socket == INVALID_SOCKET) { errno = errno_from_WSALastError(); - debug("acceptEx - socket() ERROR:%d, io:%p", errno, pio); + debug3("acceptEx - socket() ERROR:%d, io:%p", errno, pio); return -1; } @@ -130,7 +131,7 @@ socketio_acceptEx(struct w32_io* pio) /* if overlapped io is in progress, we are good */ if (WSAGetLastError() != ERROR_IO_PENDING) { errno = errno_from_WSALastError(); - debug("acceptEx - AcceptEx() ERROR:%d, io:%p", errno, pio); + debug3("acceptEx - AcceptEx() ERROR:%d, io:%p", errno, pio); return -1; } } @@ -147,7 +148,7 @@ CALLBACK WSARecvCompletionRoutine(IN DWORD dwError, { struct w32_io* pio = (struct w32_io*)((char*)lpOverlapped - offsetof(struct w32_io, read_overlapped)); - debug2("WSARecvCompletionCB - io:%p, pending_state:%d, flags:%d, error:%d, received:%d", + debug4("WSARecvCompletionCB - io:%p, pending_state:%d, flags:%d, error:%d, received:%d", pio, pio->read_details.pending, dwFlags, dwError, cbTransferred); if (!dwError && !cbTransferred) dwError = ERROR_GRACEFUL_DISCONNECT; @@ -166,7 +167,7 @@ socketio_WSARecv(struct w32_io* pio, BOOL* completed) WSABUF wsabuf; DWORD recv_flags = 0; - debug3("WSARecv - pio: %p", pio); + debug5("WSARecv - pio: %p", pio); if (completed) *completed = FALSE; @@ -176,7 +177,7 @@ socketio_WSARecv(struct w32_io* pio, BOOL* completed) wsabuf.buf = malloc(wsabuf.len); if (!wsabuf.buf) { errno = ENOMEM; - debug("WSARecv - ERROR:%d, io:%p", errno, pio); + debug3("WSARecv - ERROR:%d, io:%p", errno, pio); return -1; } @@ -189,17 +190,17 @@ socketio_WSARecv(struct w32_io* pio, BOOL* completed) if (ret == 0) { pio->read_details.pending = TRUE; /* receive has completed but APC is pending to be scheduled */ - debug2("WSARecv - WSARecv() returned 0, io:%p", pio); + debug4("WSARecv - WSARecv() returned 0, io:%p", pio); if (completed) *completed = TRUE; } else { /* (ret == SOCKET_ERROR) */ if (WSAGetLastError() == WSA_IO_PENDING) { /* io is initiated and pending */ - debug2("WSARecv - reported IO pending"); + debug4("WSARecv - reported IO pending"); pio->read_details.pending = TRUE; } else { errno = errno_from_WSALastError(); - debug("WSARecv - WSARecv() ERROR: io:%p %d", pio, errno); + debug3("WSARecv - WSARecv() ERROR: io:%p %d", pio, errno); return -1; } } @@ -214,7 +215,7 @@ socketio_socket(int domain, int type, int protocol) struct w32_io *pio = (struct w32_io*)malloc(sizeof(struct w32_io)); if (!pio) { errno = ENOMEM; - debug("socket - ERROR:%d, io:%p", errno, pio); + debug3("socket - ERROR:%d, io:%p", errno, pio); return NULL; } @@ -223,7 +224,7 @@ socketio_socket(int domain, int type, int protocol) if (pio->sock == INVALID_SOCKET) { errno = errno_from_WSALastError(); free(pio); - debug("socket - socket() ERROR:%d, io:%p", errno, pio); + debug3("socket - socket() ERROR:%d, io:%p", errno, pio); return NULL; } @@ -235,7 +236,7 @@ socketio_socket(int domain, int type, int protocol) int ret = (expr); \ if (ret == SOCKET_ERROR) { \ errno = errno_from_WSALastError(); \ - debug("%s - ERROR:%d", __FUNCTION__, errno); \ + debug3("%s - ERROR:%d", __FUNCTION__, errno); \ } \ return ret; \ } while (0) @@ -248,7 +249,7 @@ socketio_setsockopt(struct w32_io* pio, int level, int optname, const char* optv (optname == TCP_NODELAY) || (optname == IPV6_V6ONLY)) SET_ERRNO_ON_ERROR(setsockopt(pio->sock, level, optname, optval, optlen)); else { - debug("setsockop - ERROR: unsupported optname:%d io:%p", optname, pio); + debug3("setsockop - ERROR: unsupported optname:%d io:%p", optname, pio); errno = ENOTSUP; return -1; } @@ -283,7 +284,7 @@ socketio_listen(struct w32_io* pio, int backlog) if (SOCKET_ERROR == listen(pio->sock, backlog)) { errno = errno_from_WSALastError(); - debug("listen - listen() ERROR:%d io:%p", errno, pio); + debug3("listen - listen() ERROR:%d io:%p", errno, pio); return -1; } @@ -296,7 +297,7 @@ socketio_listen(struct w32_io* pio, int backlog) context = (struct acceptEx_context*)malloc(sizeof(struct acceptEx_context)); if (context == NULL) { errno = ENOMEM; - debug("listen - ERROR:%d, io:%p", errno, pio); + debug3("listen - ERROR:%d, io:%p", errno, pio); return -1; } memset(context, 0, sizeof(struct acceptEx_context)); @@ -307,7 +308,7 @@ socketio_listen(struct w32_io* pio, int backlog) &dwBytes, NULL, NULL)) { free(context); errno = errno_from_WSALastError(); - debug("listen - Ioctl1 ERROR:%d, io:%p", errno, pio); + debug3("listen - Ioctl1 ERROR:%d, io:%p", errno, pio); return -1; } @@ -318,7 +319,7 @@ socketio_listen(struct w32_io* pio, int backlog) &dwBytes, NULL, NULL)) { free(context); errno = errno_from_WSALastError(); - debug("listen - Ioctl2 ERROR:%d, io:%p", errno, pio); + debug3("listen - Ioctl2 ERROR:%d, io:%p", errno, pio); return -1; } @@ -326,7 +327,7 @@ socketio_listen(struct w32_io* pio, int backlog) if ((pio->read_overlapped.hEvent) == NULL) { free(context); errno = ENOMEM; - debug("listen - CreateEvent() ERROR:%d, io:%p", errno, pio); + debug3("listen - CreateEvent() ERROR:%d, io:%p", errno, pio); return -1; } @@ -350,16 +351,16 @@ int socketio_recv(struct w32_io* pio, void *buf, size_t len, int flags) { BOOL completed = FALSE; - debug3("recv - io:%p", pio); + debug5("recv - io:%p", pio); if ((buf == NULL) || (len == 0)) { errno = EINVAL; - debug("recv - ERROR: invalid arguments, buf:%p, len:%d, io:%p", buf, len, pio); + debug3("recv - ERROR: invalid arguments, buf:%p, len:%d, io:%p", buf, len, pio); return -1; } if (flags != 0) { errno = ENOTSUP; - debug("recv - ERROR: flags are not currently supported, io:%p", pio); + debug3("recv - ERROR: flags are not currently supported, io:%p", pio); return -1; } @@ -368,14 +369,14 @@ socketio_recv(struct w32_io* pio, void *buf, size_t len, int flags) if (pio->read_details.pending) { /* if recv is now in blocking mode, wait for data to be available */ if (w32_io_is_blocking(pio)) { - debug2("recv - io is pending, call is blocking, io:%p", pio); + debug4("recv - io is pending, call is blocking, io:%p", pio); while (socketio_is_io_available(pio, TRUE) == FALSE) { if (0 != wait_for_any_event(NULL, 0, INFINITE)) return -1; } } else { errno = EAGAIN; - debug2("recv - io is already pending, io:%p", pio); + debug4("recv - io is already pending, io:%p", pio); return -1; } } @@ -387,7 +388,7 @@ socketio_recv(struct w32_io* pio, void *buf, size_t len, int flags) num_bytes_copied); pio->read_details.remaining -= num_bytes_copied; pio->read_details.completed += num_bytes_copied; - debug2("recv - returning %d bytes from prior completed IO, remaining:%d, io:%p", + debug4("recv - returning %d bytes from prior completed IO, remaining:%d, io:%p", num_bytes_copied, pio->read_details.remaining, pio); return num_bytes_copied; } @@ -395,12 +396,12 @@ socketio_recv(struct w32_io* pio, void *buf, size_t len, int flags) /* if there was an error on async call, return */ if (pio->read_details.error) { if (pio->read_details.error == ERROR_GRACEFUL_DISCONNECT) { - debug2("recv - connection closed, io:%p", pio); + debug4("recv - connection closed, io:%p", pio); /* connection is closed */ return 0; } else { errno = errno_from_WSAError(pio->read_details.error); - debug("recv - from CB ERROR:%d, io:%p", pio->read_details.error, pio); + debug3("recv - from CB ERROR:%d, io:%p", pio->read_details.error, pio); pio->read_details.error = 0; return -1; } @@ -411,19 +412,19 @@ socketio_recv(struct w32_io* pio, void *buf, size_t len, int flags) if (completed) { /* Let APC be scheduled */ - debug2("recv - Letting APC to execute, io:%p", pio); + debug4("recv - Letting APC to execute, io:%p", pio); SleepEx(0, TRUE); if (pio->read_details.pending) { /* this shouldn't be happening */ errno = EOTHER; - debug("recv - ERROR: Unexpected IO state, io:%p", pio); + debug3("recv - ERROR: Unexpected IO state, io:%p", pio); return -1; } } if (w32_io_is_blocking(pio)) { /* wait until io is done */ - debug3("recv - socket in blocking mode, io:%p", pio); + debug5("recv - socket in blocking mode, io:%p", pio); while (socketio_is_io_available(pio, TRUE) == FALSE) { if (0 != wait_for_any_event(NULL, 0, INFINITE)) return -1; @@ -431,7 +432,7 @@ socketio_recv(struct w32_io* pio, void *buf, size_t len, int flags) } else { if (socketio_is_io_available(pio, TRUE) == FALSE) { errno = EAGAIN; - debug2("recv - IO is pending, io:%p", pio); + debug4("recv - IO is pending, io:%p", pio); return -1; } } @@ -443,12 +444,12 @@ socketio_recv(struct w32_io* pio, void *buf, size_t len, int flags) if (pio->read_details.error) { if (pio->read_details.error == ERROR_GRACEFUL_DISCONNECT) { /* connection is closed */ - debug2("recv - connection closed(2), io:%p", pio); + debug4("recv - connection closed(2), io:%p", pio); return 0; } else { errno = errno_from_WSAError(pio->read_details.error); pio->read_details.error = 0; - debug("recv - from CB(2) ERROR:%d, io:%p", errno, pio); + debug3("recv - from CB(2) ERROR:%d, io:%p", errno, pio); return -1; } } @@ -458,13 +459,13 @@ socketio_recv(struct w32_io* pio, void *buf, size_t len, int flags) memcpy(buf, pio->read_details.buf, num_bytes_copied); pio->read_details.remaining -= num_bytes_copied; pio->read_details.completed = num_bytes_copied; - debug2("recv - (2) returning %d bytes from completed IO, remaining:%d, io:%p", + debug4("recv - (2) returning %d bytes from completed IO, remaining:%d, io:%p", num_bytes_copied, pio->read_details.remaining, pio); return num_bytes_copied; } else { /* this should not happen */ errno = EOTHER; - debug("recv - (2) ERROR:Unexpected IO state, io:%p", pio); + debug3("recv - (2) ERROR:Unexpected IO state, io:%p", pio); return -1; } } @@ -476,13 +477,13 @@ CALLBACK WSASendCompletionRoutine(IN DWORD dwError, IN DWORD dwFlags) { struct w32_io* pio = (struct w32_io*)((char*)lpOverlapped - offsetof(struct w32_io, write_overlapped)); - debug2("WSASendCB - io:%p, pending_state:%d, error:%d, sent:%d of remaining:%d", + debug4("WSASendCB - io:%p, pending_state:%d, error:%d, sent:%d of remaining:%d", pio, pio->write_details.pending, dwError, cbTransferred, pio->write_details.remaining); pio->write_details.error = dwError; /* TODO - assert that remaining == cbTransferred */ if ((dwError == 0) && (pio->write_details.remaining != cbTransferred)) { - debug("WSASendCB - ERROR: broken assumption, io:%p, sent:%d, remaining:%d", pio, + debug3("WSASendCB - ERROR: broken assumption, io:%p, sent:%d, remaining:%d", pio, cbTransferred, pio->write_details.remaining); DebugBreak(); } @@ -497,16 +498,16 @@ socketio_send(struct w32_io* pio, const void *buf, size_t len, int flags) int ret = 0; WSABUF wsabuf; - debug2("send - io:%p", pio); + debug4("send - io:%p", pio); if ((buf == NULL) || (len == 0)) { errno = EINVAL; - debug("send - ERROR invalid arguments, buf:%p, len:%d, io:%p", buf, len, pio); + debug3("send - ERROR invalid arguments, buf:%p, len:%d, io:%p", buf, len, pio); return -1; } if (flags != 0) { errno = ENOTSUP; - debug("send - ERROR: flags are not currently supported, io:%p", pio); + debug3("send - ERROR: flags are not currently supported, io:%p", pio); return -1; } @@ -514,20 +515,20 @@ socketio_send(struct w32_io* pio, const void *buf, size_t len, int flags) /* if io is already pending */ if (pio->write_details.pending) { if (w32_io_is_blocking(pio)) { - debug2("send - io is pending, call is blocking, io:%p", pio); + debug4("send - io is pending, call is blocking, io:%p", pio); while (pio->write_details.pending) if (wait_for_any_event(NULL, 0, INFINITE) == -1) return -1; } else { errno = EAGAIN; - debug2("send - IO currently pending, EAGAIN, io:%p", pio); + debug4("send - IO currently pending, EAGAIN, io:%p", pio); return -1; } } if (pio->write_details.error) { errno = errno_from_WSAError(pio->write_details.error); - debug("ERROR:%d, io:%p", errno, pio); + debug3("ERROR:%d, io:%p", errno, pio); return -1; } @@ -537,7 +538,7 @@ socketio_send(struct w32_io* pio, const void *buf, size_t len, int flags) wsabuf.buf = malloc(wsabuf.len); if (!wsabuf.buf) { errno = ENOMEM; - debug("send - ERROR:%d, io:%p", errno, pio); + debug3("send - ERROR:%d, io:%p", errno, pio); return -1; } @@ -554,13 +555,13 @@ socketio_send(struct w32_io* pio, const void *buf, size_t len, int flags) if (ret == 0) { /* send has completed and APC is scheduled, let it run */ - debug2("send - WSASend() returned 0, APC scheduled io:%p", pio); + debug4("send - WSASend() returned 0, APC scheduled io:%p", pio); pio->write_details.pending = TRUE; pio->write_details.remaining = wsabuf.len; SleepEx(0, TRUE); if ((pio->write_details.pending) || (pio->write_details.remaining != 0)) { errno = EOTHER; - debug("send - ERROR: Unexpected IO state, io:%p", pio); + debug3("send - ERROR: Unexpected IO state, io:%p", pio); return -1; } @@ -569,12 +570,12 @@ socketio_send(struct w32_io* pio, const void *buf, size_t len, int flags) } else { if (WSAGetLastError() == WSA_IO_PENDING) { /* io is initiated and pending */ - debug2("send - WSASend reported IO pending, io:%p", pio); + debug4("send - WSASend reported IO pending, io:%p", pio); pio->write_details.pending = TRUE; pio->write_details.remaining = wsabuf.len; if (w32_io_is_blocking(pio)) { /* wait until io is done */ - debug3("send - waiting as socket is in blocking mode, io:%p", pio); + debug5("send - waiting as socket is in blocking mode, io:%p", pio); while (pio->write_details.pending) if (wait_for_any_event(NULL, 0, INFINITE) == -1) { /* if interrupted but send has completed, we are good*/ @@ -584,11 +585,11 @@ socketio_send(struct w32_io* pio, const void *buf, size_t len, int flags) } } - debug3("send - returning %d, io:%p", wsabuf.len, pio); + debug5("send - returning %d, io:%p", wsabuf.len, pio); return wsabuf.len; } else { errno = errno_from_WSALastError(); - debug("send - WSASend() ERROR:%d, io:%p", errno, pio); + debug3("send - WSASend() ERROR:%d, io:%p", errno, pio); return -1; } } @@ -605,13 +606,13 @@ socketio_shutdown(struct w32_io* pio, int how) int socketio_close(struct w32_io* pio) { - debug2("close - io:%p", pio); + debug4("close - io:%p", pio); closesocket(pio->sock); /* wait for pending io to abort */ SleepEx(0, TRUE); if (((pio->internal.state == SOCK_CONNECTED) || (pio->internal.state == SOCK_ACCEPTED)) && (pio->read_details.pending || pio->write_details.pending)) { - debug2("close - IO is still pending on closed socket. read:%d, write:%d, io:%p", + debug4("close - IO is still pending on closed socket. read:%d, write:%d, io:%p", pio->read_details.pending, pio->write_details.pending, pio); DebugBreak(); } @@ -649,7 +650,7 @@ socketio_accept(struct w32_io* pio, struct sockaddr* addr, int* addrlen) struct sockaddr *local_address, *remote_address; int local_address_len, remote_address_len; - debug3("accept - io:%p", pio); + debug5("accept - io:%p", pio); /* start io if not already started */ if (pio->read_details.pending == FALSE) { if (socketio_acceptEx(pio) != 0) @@ -666,7 +667,7 @@ socketio_accept(struct w32_io* pio, struct sockaddr* addr, int* addrlen) /* if i/o is not ready */ if (FALSE == socketio_is_io_available(pio, TRUE)) { errno = EAGAIN; - debug2("accept is pending, io:%p", pio); + debug4("accept is pending, io:%p", pio); return NULL; } } @@ -677,21 +678,21 @@ socketio_accept(struct w32_io* pio, struct sockaddr* addr, int* addrlen) if (pio->read_details.error) { errno = errno_from_WSAError(pio->read_details.error); - debug("accept - ERROR: async io completed with error: %d, io:%p", errno, pio); + debug3("accept - ERROR: async io completed with error: %d, io:%p", errno, pio); goto on_error; } if (0 != setsockopt(context->accept_socket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (char*)&pio->sock, sizeof(pio->sock))) { errno = errno_from_WSALastError(); - debug("accept - ERROR: setsockopt failed:%d, io:%p", errno, pio); + debug3("accept - ERROR: setsockopt failed:%d, io:%p", errno, pio); goto on_error; } accept_io = (struct w32_io*)malloc(sizeof(struct w32_io)); if (!accept_io) { errno = ENOMEM; - debug("accept - ERROR:%d, io:%p", errno, pio); + debug3("accept - ERROR:%d, io:%p", errno, pio); goto on_error; } memset(accept_io, 0, sizeof(struct w32_io)); @@ -699,7 +700,7 @@ socketio_accept(struct w32_io* pio, struct sockaddr* addr, int* addrlen) accept_io->sock = context->accept_socket; accept_io->internal.state = SOCK_ACCEPTED; context->accept_socket = INVALID_SOCKET; - debug2("accept io:%p", accept_io); + debug4("accept io:%p", accept_io); if ((addr != NULL) && (addrlen != NULL)) { context->lpfnGuidGetAcceptExSockaddrs(context->lpOutputBuf, 0, @@ -735,7 +736,7 @@ socketio_connectex(struct w32_io* pio, const struct sockaddr* name, int namelen) GUID connectex_guid = WSAID_CONNECTEX; LPFN_CONNECTEX ConnectEx; - debug3("connectex - io:%p", pio); + debug5("connectex - io:%p", pio); if (name->sa_family == AF_INET6) { ZeroMemory(&tmp_addr6, sizeof(tmp_addr6)); tmp_addr6.sin6_family = AF_INET6; @@ -750,13 +751,13 @@ socketio_connectex(struct w32_io* pio, const struct sockaddr* name, int namelen) tmp_addr_len = sizeof(tmp_addr4); } else { errno = ENOTSUP; - debug("connectex - ERROR: unsuppored address family:%d, io:%p", name->sa_family, pio); + debug3("connectex - ERROR: unsuppored address family:%d, io:%p", name->sa_family, pio); return -1; } if (SOCKET_ERROR == bind(pio->sock, tmp_addr, (int)tmp_addr_len)) { errno = errno_from_WSALastError(); - debug("connectex - ERROR: bind failed :%d, io:%p", WSAGetLastError(), pio); + debug3("connectex - ERROR: bind failed :%d, io:%p", WSAGetLastError(), pio); return -1; } @@ -765,14 +766,14 @@ socketio_connectex(struct w32_io* pio, const struct sockaddr* name, int namelen) &ConnectEx, sizeof(ConnectEx), &tmp_bytes, NULL, NULL)) { errno = errno_from_WSALastError(); - debug("connectex - ioctl ERROR:%d, io:%p", WSAGetLastError(), pio); + debug3("connectex - ioctl ERROR:%d, io:%p", WSAGetLastError(), pio); return -1; } if ((!pio->write_overlapped.hEvent) && ((pio->write_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL)) { errno = ENOMEM; - debug("connectex - ERROR CreateEvent failed:%d, io:%p", errno, pio); + debug3("connectex - ERROR CreateEvent failed:%d, io:%p", errno, pio); return -1; } @@ -786,7 +787,7 @@ socketio_connectex(struct w32_io* pio, const struct sockaddr* name, int namelen) CloseHandle(pio->write_overlapped.hEvent); pio->write_overlapped.hEvent = 0; errno = errno_from_WSALastError(); - debug("connectex - ERROR ConnectEx() :%d, io:%p", errno, pio); + debug3("connectex - ERROR ConnectEx() :%d, io:%p", errno, pio); return -1; } } @@ -801,7 +802,7 @@ int socketio_connect(struct w32_io* pio, const struct sockaddr* name, int namelen) { - debug3("connect - io:%p", pio); + debug5("connect - io:%p", pio); if (pio->write_details.pending == FALSE) { if (-1 == socketio_connectex(pio, name, namelen)) return -1; @@ -817,7 +818,7 @@ socketio_connect(struct w32_io* pio, const struct sockaddr* name, int namelen) /* if i/o is not ready */ if (FALSE == socketio_is_io_available(pio, TRUE)) { errno = EINPROGRESS; - debug2("connect - in progress, io:%p", pio); + debug4("connect - in progress, io:%p", pio); return -1; } } @@ -828,16 +829,16 @@ socketio_connect(struct w32_io* pio, const struct sockaddr* name, int namelen) int socketio_finish_connect(struct w32_io* pio) { - debug3("finish_connect, io:%p", pio); + debug5("finish_connect, io:%p", pio); if (pio->write_details.error) { errno = errno_from_WSAError(pio->write_details.error); - debug("finish_connect - ERROR: async io completed with error: %d, io:%p", errno, pio); + debug3("finish_connect - ERROR: async io completed with error: %d, io:%p", errno, pio); return -1; } if (0 != setsockopt(pio->sock, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0)) { errno = errno_from_WSALastError(); - debug("finish_connect - ERROR: setsockopt failed:%d, io:%p", errno, pio); + debug3("finish_connect - ERROR: setsockopt failed:%d, io:%p", errno, pio); return -1; } @@ -896,7 +897,7 @@ void socketio_on_select(struct w32_io* pio, BOOL rd) { enum w32_io_sock_state sock_state = pio->internal.state; - debug2("on_select - io:%p type:%d rd:%d", pio, pio->type, rd); + debug4("on_select - io:%p type:%d rd:%d", pio, pio->type, rd); /* nothing to do for writes (that includes connect) */ if (!rd) diff --git a/contrib/win32/win32compat/ssh-agent/agentconfig.c b/contrib/win32/win32compat/ssh-agent/agentconfig.c index 9761a02..155fd2c 100644 --- a/contrib/win32/win32compat/ssh-agent/agentconfig.c +++ b/contrib/win32/win32compat/ssh-agent/agentconfig.c @@ -63,6 +63,12 @@ mm_is_monitor(void) { return 0; } +int +mm_user_key_allowed(struct passwd *pw, Key *k, int i) +{ + return 0; +} + int kexgex_server(struct ssh * sh) { return -1; } diff --git a/contrib/win32/win32compat/termio.c b/contrib/win32/win32compat/termio.c index d637ade..33ed14e 100644 --- a/contrib/win32/win32compat/termio.c +++ b/contrib/win32/win32compat/termio.c @@ -39,6 +39,7 @@ #include "w32fd.h" #include "tncon.h" #include "inc\utf.h" +#include "debug.h" #include "tnnet.h" #define TERM_IO_BUF_SIZE 2048 @@ -57,7 +58,7 @@ static VOID CALLBACK ReadAPCProc(_In_ ULONG_PTR dwParam) { struct w32_io* pio = (struct w32_io*)dwParam; - debug3("TermRead CB - io:%p, bytes: %d, pending: %d, error: %d", pio, read_status.transferred, + debug5("TermRead CB - io:%p, bytes: %d, pending: %d, error: %d", pio, read_status.transferred, pio->read_details.pending, read_status.error); pio->read_details.error = read_status.error; pio->read_details.remaining = read_status.transferred; @@ -75,7 +76,7 @@ ReadConsoleThread(_In_ LPVOID lpParameter) int nBytesReturned = 0; struct w32_io* pio = (struct w32_io*)lpParameter; - debug3("TermRead thread, io:%p", pio); + debug5("TermRead thread, io:%p", pio); memset(&read_status, 0, sizeof(read_status)); while (nBytesReturned == 0) { nBytesReturned = ReadConsoleForTermEmul(WINHANDLE(pio), @@ -83,7 +84,7 @@ ReadConsoleThread(_In_ LPVOID lpParameter) } read_status.transferred = nBytesReturned; if (0 == QueueUserAPC(ReadAPCProc, main_thread, (ULONG_PTR)pio)) { - debug("TermRead thread - ERROR QueueUserAPC failed %d, io:%p", GetLastError(), pio); + debug3("TermRead thread - ERROR QueueUserAPC failed %d, io:%p", GetLastError(), pio); pio->read_details.pending = FALSE; pio->read_details.error = GetLastError(); DebugBreak(); @@ -98,7 +99,7 @@ termio_initiate_read(struct w32_io* pio) { HANDLE read_thread; - debug3("TermRead initiate io:%p", pio); + debug5("TermRead initiate io:%p", pio); if (pio->read_details.buf_size == 0) { pio->read_details.buf = malloc(TERM_IO_BUF_SIZE); if (pio->read_details.buf == NULL) { @@ -111,7 +112,7 @@ termio_initiate_read(struct w32_io* pio) read_thread = CreateThread(NULL, 0, ReadConsoleThread, pio, 0, NULL); if (read_thread == NULL) { errno = errno_from_Win32Error(GetLastError()); - debug("TermRead initiate - ERROR CreateThread %d, io:%p", GetLastError(), pio); + debug3("TermRead initiate - ERROR CreateThread %d, io:%p", GetLastError(), pio); return -1; } @@ -125,7 +126,7 @@ static VOID CALLBACK WriteAPCProc(_In_ ULONG_PTR dwParam) { struct w32_io* pio = (struct w32_io*)dwParam; - debug3("TermWrite CB - io:%p, bytes: %d, pending: %d, error: %d", pio, write_status.transferred, + debug5("TermWrite CB - io:%p, bytes: %d, pending: %d, error: %d", pio, write_status.transferred, pio->write_details.pending, write_status.error); pio->write_details.error = write_status.error; pio->write_details.remaining -= write_status.transferred; @@ -144,10 +145,9 @@ WriteThread(_In_ LPVOID lpParameter) { struct w32_io* pio = (struct w32_io*)lpParameter; char *respbuf = NULL; - size_t resplen = 0; - DWORD dwSavedAttributes = ENABLE_PROCESSED_INPUT; - debug3("TermWrite thread, io:%p", pio); - + size_t resplen = 0; + debug5("TermWrite thread, io:%p", pio); + pio->write_details.buf[write_status.to_transfer] = '\0'; if (0 == in_raw_mode) { @@ -162,7 +162,7 @@ WriteThread(_In_ LPVOID lpParameter) write_status.transferred = write_status.to_transfer; if (0 == QueueUserAPC(WriteAPCProc, main_thread, (ULONG_PTR)pio)) { - debug("TermWrite thread - ERROR QueueUserAPC failed %d, io:%p", GetLastError(), pio); + debug3("TermWrite thread - ERROR QueueUserAPC failed %d, io:%p", GetLastError(), pio); pio->write_details.pending = FALSE; pio->write_details.error = GetLastError(); DebugBreak(); @@ -176,13 +176,13 @@ int termio_initiate_write(struct w32_io* pio, DWORD num_bytes) { HANDLE write_thread; - debug3("TermWrite initiate io:%p", pio); + debug5("TermWrite initiate io:%p", pio); memset(&write_status, 0, sizeof(write_status)); write_status.to_transfer = num_bytes; write_thread = CreateThread(NULL, 0, WriteThread, pio, 0, NULL); if (write_thread == NULL) { errno = errno_from_Win32Error(GetLastError()); - debug("TermWrite initiate - ERROR CreateThread %d, io:%p", GetLastError(), pio); + debug3("TermWrite initiate - ERROR CreateThread %d, io:%p", GetLastError(), pio); return -1; } @@ -195,7 +195,7 @@ termio_initiate_write(struct w32_io* pio, DWORD num_bytes) int termio_close(struct w32_io* pio) { - debug2("termio_close - pio:%p", pio); + debug4("termio_close - pio:%p", pio); HANDLE h; CancelIoEx(WINHANDLE(pio), NULL); /* If io is pending, let write worker threads exit. The read thread is blocked so terminate it.*/ diff --git a/contrib/win32/win32compat/w32fd.c b/contrib/win32/win32compat/w32fd.c index 52fcbb7..4e48f96 100644 --- a/contrib/win32/win32compat/w32fd.c +++ b/contrib/win32/win32compat/w32fd.c @@ -48,6 +48,7 @@ #include "Shlwapi.h" #include #include "misc_internal.h" +#include "debug.h" /* internal table that stores the fd to w32_io mapping*/ struct w32fd_table { @@ -99,7 +100,7 @@ fd_table_get_min_index() min_index += 8; if (min_index >= MAX_FDS) { errno = EMFILE; - debug("ERROR: MAX_FDS limit reached"); + debug3("ERROR: MAX_FDS limit reached"); return -1; } } @@ -180,11 +181,10 @@ w32_io_on_select(struct w32_io* pio, BOOL rd) } #define CHECK_FD(fd) do { \ - debug3("%s fd:%d", __FUNCTION__, fd); \ errno = 0; \ if ((fd < 0) || (fd > MAX_FDS - 1) || fd_table.w32_ios[fd] == NULL) { \ errno = EBADF; \ - debug("%s ERROR: bad fd: %d", __FUNCTION__, fd); \ + debug3("%s ERROR: bad fd: %d", __FUNCTION__, fd); \ return -1; \ } \ } while (0) @@ -193,7 +193,7 @@ w32_io_on_select(struct w32_io* pio, BOOL rd) errno = 0; \ if (pio->type != SOCK_FD) { \ errno = ENOTSOCK; \ - debug("%s ERROR: not sock :%d", __FUNCTION__, pio->type); \ + debug3("%s ERROR: not sock :%d", __FUNCTION__, pio->type); \ return -1; \ } \ } while (0) @@ -221,7 +221,7 @@ w32_socket(int domain, int type, int protocol) } fd_table_set(pio, min_index); - debug("socket:%d, socktype:%d, io:%p, fd:%d ", pio->sock, type, pio, min_index); + debug3("socket:%d, socktype:%d, io:%p, fd:%d ", pio->sock, type, pio, min_index); return min_index; } @@ -242,7 +242,7 @@ w32_accept(int fd, struct sockaddr* addr, int* addrlen) pio->type = SOCK_FD; fd_table_set(pio, min_index); - debug("socket:%d, io:%p, fd:%d ", pio->sock, pio, min_index); + debug3("socket:%d, io:%p, fd:%d ", pio->sock, pio, min_index); return min_index; } @@ -329,7 +329,7 @@ w32_send(int fd, const void *buf, size_t len, int flags) int w32_shutdown(int fd, int how) { - debug2("shutdown - fd:%d how:%d", fd, how); + debug4("shutdown - fd:%d how:%d", fd, how); CHECK_FD(fd); CHECK_SOCK_IO(fd_table.w32_ios[fd]); return socketio_shutdown(fd_table.w32_ios[fd], how); @@ -339,7 +339,7 @@ int w32_socketpair(int domain, int type, int protocol, int sv[2]) { errno = ENOTSUP; - debug("socketpair - ERROR not supported"); + debug3("socketpair - ERROR not supported"); return -1; } @@ -371,7 +371,7 @@ w32_pipe(int *pfds) fd_table_set(pio[1], write_index); pfds[0] = read_index; pfds[1] = write_index; - debug("pipe - r-h:%d,io:%p,fd:%d w-h:%d,io:%p,fd:%d", + debug3("pipe - r-h:%d,io:%p,fd:%d w-h:%d,io:%p,fd:%d", pio[0]->handle, pio[0], read_index, pio[1]->handle, pio[1], write_index); return 0; @@ -393,8 +393,8 @@ w32_open(const char *pathname, int flags, ...) pio->type = NONSOCK_FD; fd_table_set(pio, min_index); - debug("open - handle:%p, io:%p, fd:%d", pio->handle, pio, min_index); - debug3("open - path:%s", pathname); + debug3("open - handle:%p, io:%p, fd:%d", pio->handle, pio, min_index); + debug5("open - path:%s", pathname); return min_index; } @@ -473,7 +473,7 @@ w32_fdopen(int fd, const char *mode) errno = 0; if ((fd < 0) || (fd > MAX_FDS - 1) || fd_table.w32_ios[fd] == NULL) { errno = EBADF; - debug("fdopen - ERROR bad fd: %d", fd); + debug3("fdopen - ERROR bad fd: %d", fd); return NULL; } return fileio_fdopen(fd_table.w32_ios[fd], mode); @@ -490,7 +490,7 @@ w32_close(int fd) pio = fd_table.w32_ios[fd]; - debug("close - io:%p, type:%d, fd:%d, table_index:%d", pio, pio->type, fd, + debug3("close - io:%p, type:%d, fd:%d, table_index:%d", pio, pio->type, fd, pio->table_index); fd_table_clear(pio->table_index); @@ -510,7 +510,7 @@ w32_io_process_fd_flags(struct w32_io* pio, int flags) { DWORD shi_flags; if (flags & ~FD_CLOEXEC) { - debug("fcntl - ERROR unsupported flags %d, io:%p", flags, pio); + debug3("fcntl - ERROR unsupported flags %d, io:%p", flags, pio); errno = ENOTSUP; return -1; } @@ -523,7 +523,7 @@ w32_io_process_fd_flags(struct w32_io* pio, int flags) * UF_UNIX sockets that are not connected yet */ if (GetLastError() != ERROR_INVALID_HANDLE) { - debug("fcntl - SetHandleInformation failed %d, io:%p", + debug3("fcntl - SetHandleInformation failed %d, io:%p", GetLastError(), pio); errno = EOTHER; return -1; @@ -559,7 +559,7 @@ w32_fcntl(int fd, int cmd, ... /* arg */) break; default: errno = EINVAL; - debug("fcntl - ERROR not supported cmd:%d", cmd); + debug3("fcntl - ERROR not supported cmd:%d", cmd); ret = -1; break; } @@ -589,20 +589,20 @@ w32_select(int fds, w32_fd_set* readfds, w32_fd_set* writefds, w32_fd_set* excep if (fds > MAX_FDS) { errno = EINVAL; - debug("select - ERROR: invalid fds: %d", fds); + debug3("select - ERROR: invalid fds: %d", fds); return -1; } if (!readfds && !writefds) { errno = EINVAL; - debug("select - ERROR: null fd_sets"); + debug3("select - ERROR: null fd_sets"); return -1; } /* TODO - see if this needs to be supported */ /* if (exceptfds) { errno = EOPNOTSUPP; - debug("select - ERROR: exceptfds not supported"); + debug3("select - ERROR: exceptfds not supported"); DebugBreak(); return -1; } */ @@ -626,11 +626,11 @@ w32_select(int fds, w32_fd_set* readfds, w32_fd_set* writefds, w32_fd_set* excep /* if none of input fds are set return error */ if (in_set_fds == 0) { errno = EINVAL; - debug("select - ERROR: empty fd_sets"); + debug3("select - ERROR: empty fd_sets"); return -1; } - debug3("Total in fds:%d", in_set_fds); + debug5("Total in fds:%d", in_set_fds); /* * start async io on selected fds if needed and pick up any events * that select needs to listen on @@ -641,7 +641,7 @@ w32_select(int fds, w32_fd_set* readfds, w32_fd_set* writefds, w32_fd_set* excep if ((fd_table.w32_ios[i]->type == SOCK_FD) && (fd_table.w32_ios[i]->internal.state == SOCK_LISTENING)) { if (num_events == SELECT_EVENT_LIMIT) { - debug("select - ERROR: max #events breach"); + debug3("select - ERROR: max #events breach"); errno = ENOMEM; return -1; } @@ -654,7 +654,7 @@ w32_select(int fds, w32_fd_set* readfds, w32_fd_set* writefds, w32_fd_set* excep if ((fd_table.w32_ios[i]->type == SOCK_FD) && (fd_table.w32_ios[i]->internal.state == SOCK_CONNECTING)) { if (num_events == SELECT_EVENT_LIMIT) { - debug("select - ERROR: max #events reached for select"); + debug3("select - ERROR: max #events reached for select"); errno = ENOMEM; return -1; } @@ -695,7 +695,7 @@ w32_select(int fds, w32_fd_set* readfds, w32_fd_set* writefds, w32_fd_set* excep if (timeout != NULL) { if (timeout_ms < ticks_spent) { - debug("select - timing out"); + debug3("select - timing out"); break; } time_rem = timeout_ms - (ticks_spent & 0xffffffff); @@ -725,7 +725,7 @@ w32_select(int fds, w32_fd_set* readfds, w32_fd_set* writefds, w32_fd_set* excep } if (out_ready_fds == 0) - debug3("select - wait ended without any IO completion, looping again"); + debug5("select - wait ended without any IO completion, looping again"); } /* clear out fds that are not ready yet */ @@ -754,7 +754,7 @@ w32_select(int fds, w32_fd_set* readfds, w32_fd_set* writefds, w32_fd_set* excep FD_CLR(i, writefds); } - debug3("select - returning %d", out_ready_fds); + debug5("select - returning %d", out_ready_fds); return out_ready_fds; } @@ -768,7 +768,7 @@ w32_dup(int oldfd) CHECK_FD(oldfd); if (oldfd > STDERR_FILENO) { errno = EOPNOTSUPP; - debug("dup - ERROR: supports only std io, fd:%d", oldfd); + debug3("dup - ERROR: supports only std io, fd:%d", oldfd); return -1; } @@ -778,13 +778,13 @@ w32_dup(int oldfd) src = GetStdHandle(fd_table.w32_ios[oldfd]->std_handle); if (src == INVALID_HANDLE_VALUE) { errno = EINVAL; - debug("dup - ERROR: unable to get underlying handle for std fd:%d", oldfd); + debug3("dup - ERROR: unable to get underlying handle for std fd:%d", oldfd); return -1; } if (!DuplicateHandle(GetCurrentProcess(), src, GetCurrentProcess(), &target, 0, TRUE, DUPLICATE_SAME_ACCESS)) { errno = EOTHER; - debug("dup - ERROR: DuplicatedHandle() :%d", GetLastError()); + debug3("dup - ERROR: DuplicatedHandle() :%d", GetLastError()); return -1; } @@ -792,7 +792,7 @@ w32_dup(int oldfd) if (pio == NULL) { CloseHandle(target); errno = ENOMEM; - debug("dup - ERROR: %d", errno); + debug3("dup - ERROR: %d", errno); return -1; } @@ -808,7 +808,7 @@ w32_dup2(int oldfd, int newfd) { CHECK_FD(oldfd); errno = EOPNOTSUPP; - debug("dup2 - ERROR: not implemented yet"); + debug3("dup2 - ERROR: not implemented yet"); return -1; } diff --git a/contrib/win32/win32compat/win32-utf8.c b/contrib/win32/win32compat/win32-utf8.c index f1fd186..3ca38da 100644 --- a/contrib/win32/win32compat/win32-utf8.c +++ b/contrib/win32/win32compat/win32-utf8.c @@ -1,34 +1,51 @@ /* - * Temporary Windows versions of functions implemented in utf8.c + * Windows versions of functions implemented in utf8.c */ #include #include +#include + +#include "console.h" + int -vfmprintf(FILE *f, const char *fmt, va_list list) +vfmprintf(FILE *stream, const char *fmt, va_list ap) { - return vfprintf(f, fmt, list); + DWORD saved_mode = 0, new_mode = 0; + int ret; + HANDLE hFile; + hFile = get_console_handle(stream, &saved_mode); + if(hFile != INVALID_HANDLE_VALUE && + ((saved_mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) == ENABLE_VIRTUAL_TERMINAL_PROCESSING)) { + new_mode = saved_mode & (~ENABLE_VIRTUAL_TERMINAL_PROCESSING); + SetConsoleMode(hFile, new_mode); + } + + ret = vfprintf(stream, fmt, ap); + if (saved_mode != 0 && new_mode != saved_mode) + SetConsoleMode(hFile, saved_mode); + return ret; } int mprintf(const char *fmt, ...) { int ret = 0; - va_list valist; - va_start(valist, fmt); - ret = vfmprintf(stdout, fmt, valist); - va_end(valist); + va_list ap; + va_start(ap, fmt); + ret = vfmprintf(stdout, fmt, ap); + va_end(ap); return ret; } int -fmprintf(FILE *f, const char *fmt, ...) +fmprintf(FILE *stream, const char *fmt, ...) { int ret = 0; - va_list valist; - va_start(valist, fmt); - ret = vfmprintf(f, fmt, valist); - va_end(valist); + va_list ap; + va_start(ap, fmt); + ret = vfmprintf(stream, fmt, ap); + va_end(ap); return ret; } @@ -49,6 +66,5 @@ snmprintf(char *buf, size_t len, int *written, const char *fmt, ...) void msetlocale(void) { - return; } diff --git a/contrib/win32/win32compat/win32_sshpty.c b/contrib/win32/win32compat/win32_sshpty.c new file mode 100644 index 0000000..957718a --- /dev/null +++ b/contrib/win32/win32compat/win32_sshpty.c @@ -0,0 +1,58 @@ +/* + * Windows version of sshpty* routines in sshpty.c + */ + + + +#include +#include "..\..\..\sshpty.h" + + +/* + * Windows versions of pty_*. Some of them are NO-OPs and should go + * away when pty logic is refactored and abstracted out + * + */ +int +pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, size_t namebuflen) +{ + /* + * Simple console screen implementation in Win32 to give a + * Unix like pty for interactive sessions + */ + *ttyfd = 0; + *ptyfd = 0; + strlcpy(namebuf, "console", namebuflen); + return 1; +} + +void +pty_release(const char *tty) { + /* NO-OP */ +} + +void +pty_make_controlling_tty(int *ttyfd, const char *tty) { + /* NO-OP */ +} + +void +pty_change_window_size(int ptyfd, u_int row, u_int col, + u_int xpixel, u_int ypixel) { + COORD coord; + coord.X = col; + coord.Y = 9999; + SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coord); +} + + +void +pty_setowner(struct passwd *pw, const char *tty) { + /* NO-OP */ +} + +void +disconnect_controlling_tty(void) { + /* NO-OP */ +} + diff --git a/contrib/win32/win32compat/win32_sshtty.c b/contrib/win32/win32compat/win32_sshtty.c new file mode 100644 index 0000000..84e80ca --- /dev/null +++ b/contrib/win32/win32compat/win32_sshtty.c @@ -0,0 +1,40 @@ +/* + * Windows version of sshtty* routines implemented in sshtty.c + */ + +#include +#include "..\..\..\sshpty.h" + +static struct termios _saved_tio; +static int _in_raw_mode = 0; + + +/* + * TTY raw mode routines for Windows + */ + +int ConEnterRawMode(DWORD OutputHandle, BOOL fSmartInit); +int ConExitRawMode(void); + +struct termios term_settings; + +/* + * TODO - clean this up for Windows, ConInit should return previous terminal + * settings that need to be stored in term_settings + */ + +struct termios * + get_saved_tio(void) { + memset(&term_settings, 0, sizeof(term_settings)); + return &term_settings; +} + +void +leave_raw_mode(int quiet) { + ConExitRawMode(); +} + +void +enter_raw_mode(int quiet) { + ConEnterRawMode(STD_OUTPUT_HANDLE, TRUE); +} diff --git a/groupaccess.c b/groupaccess.c index bea3d6d..71ea9df 100644 --- a/groupaccess.c +++ b/groupaccess.c @@ -53,21 +53,21 @@ int ga_init(const char *user, gid_t base) { #ifdef WINDOWS - DWORD i = 0, j = 0; LPLOCALGROUP_USERS_INFO_0 local_groups_info = NULL, tmp_groups_info; wchar_t *user_utf16 = NULL, *full_name_utf16 = NULL, *udom_utf16 = NULL, *tmp; char *group_utf8 = NULL; + DWORD i = 0, j = 0; DWORD entries_read = 0, total_entries = 0, full_name_len = 0, index = 0; NET_API_STATUS nStatus; if (ngroups > 0) ga_free(); - user_utf16 = utf8_to_utf16(user); if ((user_utf16 = utf8_to_utf16(user)) == NULL) { errno = ENOMEM; goto done; } + full_name_len = wcslen(user_utf16) + 1; if ((full_name_utf16 = malloc(full_name_len * sizeof(wchar_t))) == NULL) { errno = ENOMEM; @@ -151,7 +151,6 @@ done: free(groups_bygid); #endif /* !WINDOWS */ return (ngroups = j); - } /* diff --git a/kex.c b/kex.c index 8ac0029..cf4ac0d 100644 --- a/kex.c +++ b/kex.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kex.c,v 1.130 2017/03/10 04:07:20 djm Exp $ */ +/* $OpenBSD: kex.c,v 1.131 2017/03/15 07:07:39 markus Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * @@ -341,7 +341,6 @@ kex_reset_dispatch(struct ssh *ssh) { ssh_dispatch_range(ssh, SSH2_MSG_TRANSPORT_MIN, SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error); - ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit); } static int @@ -431,6 +430,7 @@ kex_input_newkeys(int type, u_int32_t seq, void *ctxt) debug("SSH2_MSG_NEWKEYS received"); ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_protocol_error); + ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit); if ((r = sshpkt_get_end(ssh)) != 0) return r; if ((r = ssh_set_newkeys(ssh, MODE_IN)) != 0) @@ -545,6 +545,7 @@ kex_new(struct ssh *ssh, char *proposal[PROPOSAL_MAX], struct kex **kexp) goto out; kex->done = 0; kex_reset_dispatch(ssh); + ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit); r = 0; *kexp = kex; out: diff --git a/krl.c b/krl.c index e271a19..3f28178 100644 --- a/krl.c +++ b/krl.c @@ -14,7 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $OpenBSD: krl.c,v 1.38 2016/09/12 01:22:38 deraadt Exp $ */ +/* $OpenBSD: krl.c,v 1.39 2017/03/10 07:18:32 dtucker Exp $ */ #include "includes.h" @@ -1089,7 +1089,7 @@ ssh_krl_from_blob(struct sshbuf *buf, struct ssh_krl **krlp, break; case KRL_SECTION_SIGNATURE: /* Handled above, but still need to stay in synch */ - sshbuf_reset(sect); + sshbuf_free(sect); sect = NULL; if ((r = sshbuf_skip_string(copy)) != 0) goto out; @@ -1288,7 +1288,8 @@ ssh_krl_file_contains_key(const char *path, const struct sshkey *key) debug2("%s: checking KRL %s", __func__, path); r = ssh_krl_check_key(krl, key); out: - close(fd); + if (fd != -1) + close(fd); sshbuf_free(krlbuf); ssh_krl_free(krl); if (r != 0) diff --git a/log.c b/log.c index 945fd9d..d0f86cf 100644 --- a/log.c +++ b/log.c @@ -455,15 +455,7 @@ do_log(LogLevel level, const char *fmt, va_list args) } else if (log_on_stderr) { snprintf(msgbuf, sizeof msgbuf, "%.*s\r\n", (int)sizeof msgbuf - 3, fmtbuf); -#ifdef WINDOWS - /* - * In Windows, write is implemented as part of POSIX compat layer - * that itself may "log" resulting in a infinite recursion loop - */ - _write(STDERR_FILENO, msgbuf, strlen(msgbuf)); -#else /* !WINDOWS */ (void)write(log_stderr_fd, msgbuf, strlen(msgbuf)); -#endif /* !WINDOWS */ } else { #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata); diff --git a/misc.c b/misc.c index 8a64405..70bf517 100644 --- a/misc.c +++ b/misc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: misc.c,v 1.107 2016/11/30 00:28:31 dtucker Exp $ */ +/* $OpenBSD: misc.c,v 1.109 2017/03/14 00:55:37 dtucker Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2005,2006 Damien Miller. All rights reserved. @@ -310,7 +310,7 @@ a2tun(const char *s, int *remote) long convtime(const char *s) { - long total, secs; + long total, secs, multiplier = 1; const char *p; char *endp; @@ -337,23 +337,28 @@ convtime(const char *s) break; case 'm': case 'M': - secs *= MINUTES; + multiplier = MINUTES; break; case 'h': case 'H': - secs *= HOURS; + multiplier = HOURS; break; case 'd': case 'D': - secs *= DAYS; + multiplier = DAYS; break; case 'w': case 'W': - secs *= WEEKS; + multiplier = WEEKS; break; default: return -1; } + if (secs >= LONG_MAX / multiplier) + return -1; + secs *= multiplier; + if (total >= LONG_MAX - secs) + return -1; total += secs; if (total < 0) return -1; diff --git a/openbsd-compat/bsd-misc.c b/openbsd-compat/bsd-misc.c index 6285ff4..e516946 100644 --- a/openbsd-compat/bsd-misc.c +++ b/openbsd-compat/bsd-misc.c @@ -307,3 +307,11 @@ mbtowc(wchar_t *pwc, const char *s, size_t n) return 1; } #endif + +#ifndef HAVE_LLABS +long long +llabs(long long j) +{ + return (j < 0 ? -j : j); +} +#endif diff --git a/openbsd-compat/bsd-misc.h b/openbsd-compat/bsd-misc.h index 6f08b09..70a538f 100644 --- a/openbsd-compat/bsd-misc.h +++ b/openbsd-compat/bsd-misc.h @@ -135,4 +135,8 @@ void errx(int, const char *, ...) __attribute__((format(printf, 2, 3))); void warn(const char *, ...) __attribute__((format(printf, 1, 2))); #endif +#ifndef HAVE_LLABS +long long llabs(long long); +#endif + #endif /* _BSD_MISC_H */ diff --git a/openbsd-compat/fmt_scaled.c b/openbsd-compat/fmt_scaled.c index edd682a..e5533b2 100644 --- a/openbsd-compat/fmt_scaled.c +++ b/openbsd-compat/fmt_scaled.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fmt_scaled.c,v 1.9 2007/03/20 03:42:52 tedu Exp $ */ +/* $OpenBSD: fmt_scaled.c,v 1.13 2017/03/11 23:37:23 djm Exp $ */ /* * Copyright (c) 2001, 2002, 2003 Ian F. Darwin. All rights reserved. @@ -69,7 +69,7 @@ static long long scale_factors[] = { #define MAX_DIGITS (SCALE_LENGTH * 3) /* XXX strlen(sprintf("%lld", -1)? */ -/** Convert the given input string "scaled" into numeric in "result". +/* Convert the given input string "scaled" into numeric in "result". * Return 0 on success, -1 and errno set on error. */ int @@ -81,7 +81,7 @@ scan_scaled(char *scaled, long long *result) long long scale_fact = 1, whole = 0, fpart = 0; /* Skip leading whitespace */ - while (isascii(*p) && isspace(*p)) + while (isascii((unsigned char)*p) && isspace((unsigned char)*p)) ++p; /* Then at most one leading + or - */ @@ -108,7 +108,8 @@ scan_scaled(char *scaled, long long *result) * (but note that E for Exa might look like e to some!). * Advance 'p' to end, to get scale factor. */ - for (; isascii(*p) && (isdigit(*p) || *p=='.'); ++p) { + for (; isascii((unsigned char)*p) && + (isdigit((unsigned char)*p) || *p=='.'); ++p) { if (*p == '.') { if (fract_digits > 0) { /* oops, more than one '.' */ errno = EINVAL; @@ -124,6 +125,10 @@ scan_scaled(char *scaled, long long *result) /* ignore extra fractional digits */ continue; fract_digits++; /* for later scaling */ + if (fpart >= LLONG_MAX / 10) { + errno = ERANGE; + return -1; + } fpart *= 10; fpart += i; } else { /* normal digit */ @@ -131,6 +136,10 @@ scan_scaled(char *scaled, long long *result) errno = ERANGE; return -1; } + if (whole >= LLONG_MAX / 10) { + errno = ERANGE; + return -1; + } whole *= 10; whole += i; } @@ -150,17 +159,22 @@ scan_scaled(char *scaled, long long *result) /* Validate scale factor, and scale whole and fraction by it. */ for (i = 0; i < SCALE_LENGTH; i++) { - /** Are we there yet? */ + /* Are we there yet? */ if (*p == scale_chars[i] || - *p == tolower(scale_chars[i])) { + *p == tolower((unsigned char)scale_chars[i])) { /* If it ends with alphanumerics after the scale char, bad. */ - if (isalnum(*(p+1))) { + if (isalnum((unsigned char)*(p+1))) { errno = EINVAL; return -1; } scale_fact = scale_factors[i]; + if (whole >= LLONG_MAX / scale_fact) { + errno = ERANGE; + return -1; + } + /* scale whole part */ whole *= scale_fact; @@ -181,7 +195,9 @@ scan_scaled(char *scaled, long long *result) return 0; } } - errno = ERANGE; + + /* Invalid unit or character */ + errno = EINVAL; return -1; } @@ -196,7 +212,7 @@ fmt_scaled(long long number, char *result) unsigned int i; unit_type unit = NONE; - abval = (number < 0LL) ? -number : number; /* no long long_abs yet */ + abval = llabs(number); /* Not every negative long long has a positive representation. * Also check for numbers that are just too darned big to format diff --git a/packet.c b/packet.c index 01e2d45..2f3a2ec 100644 --- a/packet.c +++ b/packet.c @@ -1,4 +1,4 @@ -/* $OpenBSD: packet.c,v 1.246 2017/02/28 06:10:08 djm Exp $ */ +/* $OpenBSD: packet.c,v 1.247 2017/03/11 13:07:35 markus Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1850,11 +1850,11 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) if (r != SSH_ERR_MAC_INVALID) goto out; logit("Corrupted MAC on input."); - if (need > PACKET_MAX_SIZE) + if (need + block_size > PACKET_MAX_SIZE) return SSH_ERR_INTERNAL_ERROR; return ssh_packet_start_discard(ssh, enc, mac, sshbuf_len(state->incoming_packet), - PACKET_MAX_SIZE - need); + PACKET_MAX_SIZE - need - block_size); } /* Remove MAC from input buffer */ DBG(debug("MAC #%d ok", state->p_read.seqnr)); diff --git a/readpass.c b/readpass.c index 78f8f07..de62434 100644 --- a/readpass.c +++ b/readpass.c @@ -69,7 +69,7 @@ ssh_askpass(char *askpass, const char *msg) #ifdef WINDOWS /* spawd child for Windows */ fcntl(p[0], F_SETFD, FD_CLOEXEC); - pid = spawn_child(askpass, p[1], p[1], STDERR_FILENO, 0); + pid = spawn_child(askpass, NULL, p[1], p[1], STDERR_FILENO, 0); if (pid < 0) { #else /* !WINDOWS */ if ((pid = fork()) < 0) { @@ -125,71 +125,6 @@ ssh_askpass(char *askpass, const char *msg) char * read_passphrase(const char *prompt, int flags) { - -#ifdef WINDOWS - /* TODO - do flags apply on Windows? */ - char *askpass = NULL; - char *ret = NULL; - char buf[1024] = { 0 }; - - DWORD mode; - size_t len = 0; - int retr = 0; - - if (getenv(SSH_ASKPASS_ENV)) { - askpass = getenv(SSH_ASKPASS_ENV); - if ((ret = ssh_askpass(askpass, prompt)) == NULL) - return xstrdup(""); - return ret; - } - - /* prompt user */ - wchar_t* wtmp = utf8_to_utf16(prompt); - if (wtmp == NULL) - fatal("unable to alloc memory"); - _cputws(wtmp); - free(wtmp); - - len = retr = 0; - int bufsize = sizeof(buf); - - while (_kbhit()) - _getch(); - - while (len < bufsize) { - buf[len] = (unsigned char)_getch(); - - if (buf[len] == '\r') { - if (_kbhit()) /* read linefeed if its there */ - _getch(); - break; - } - else if (buf[len] == '\n') { - break; -} - else if (buf[len] == '\b') { /* backspace */ - if (len > 0) - len--; /* overwrite last character */ - } - else if (buf[len] == '\003') { - /* exit on Ctrl+C */ - fatal(""); - } - else { - len++; /* keep reading in the loop */ - } - } - - buf[len] = '\0'; /* get rid of the cr/lf */ - _cputs("\n"); /*show a newline as we do not echo password or the line */ - - ret = xstrdup(buf); - - memset(buf, 'x', sizeof(buf)); - - return ret; - -#else /* !WINDOWS */ char *askpass = NULL, *ret, buf[1024]; int rppflags, use_askpass = 0, ttyfd; @@ -236,7 +171,6 @@ read_passphrase(const char *prompt, int flags) ret = xstrdup(buf); explicit_bzero(buf, sizeof(buf)); return ret; -#endif /* !WINDOWS */ } int diff --git a/regress/Makefile b/regress/Makefile index c2dba4f..b23496b 100644 --- a/regress/Makefile +++ b/regress/Makefile @@ -222,6 +222,7 @@ unit: $$V ${.OBJDIR}/unittests/sshkey/test_sshkey \ -d ${.CURDIR}/unittests/sshkey/testdata ; \ $$V ${.OBJDIR}/unittests/bitmap/test_bitmap ; \ + $$V ${.OBJDIR}/unittests/conversion/test_conversion ; \ $$V ${.OBJDIR}/unittests/kex/test_kex ; \ $$V ${.OBJDIR}/unittests/hostkeys/test_hostkeys \ -d ${.CURDIR}/unittests/hostkeys/testdata ; \ diff --git a/regress/cert-file.sh b/regress/cert-file.sh index b184e7f..43b8e02 100644 --- a/regress/cert-file.sh +++ b/regress/cert-file.sh @@ -1,4 +1,4 @@ -# $OpenBSD: cert-file.sh,v 1.4 2016/12/16 02:48:55 djm Exp $ +# $OpenBSD: cert-file.sh,v 1.5 2017/03/11 23:44:16 djm Exp $ # Placed in the Public Domain. tid="ssh with certificates" @@ -17,24 +17,59 @@ ${SSHKEYGEN} -q -N '' -t ed25519 -f $OBJ/user_key1 || \ fatal "ssh-keygen failed" ${SSHKEYGEN} -q -N '' -t ed25519 -f $OBJ/user_key2 || \ fatal "ssh-keygen failed" +${SSHKEYGEN} -q -N '' -t ed25519 -f $OBJ/user_key3 || \ + fatal "ssh-keygen failed" +${SSHKEYGEN} -q -N '' -t ed25519 -f $OBJ/user_key4 || \ + fatal "ssh-keygen failed" +${SSHKEYGEN} -q -N '' -t ed25519 -f $OBJ/user_key5 || \ + fatal "ssh-keygen failed" + # Move the certificate to a different address to better control # when it is offered. ${SSHKEYGEN} -q -s $OBJ/user_ca_key1 -I "regress user key for $USER" \ -z $$ -n ${USER} $OBJ/user_key1 || - fail "couldn't sign user_key1 with user_ca_key1" + fatal "couldn't sign user_key1 with user_ca_key1" mv $OBJ/user_key1-cert.pub $OBJ/cert_user_key1_1.pub ${SSHKEYGEN} -q -s $OBJ/user_ca_key2 -I "regress user key for $USER" \ -z $$ -n ${USER} $OBJ/user_key1 || - fail "couldn't sign user_key1 with user_ca_key2" + fatal "couldn't sign user_key1 with user_ca_key2" mv $OBJ/user_key1-cert.pub $OBJ/cert_user_key1_2.pub +${SSHKEYGEN} -q -s $OBJ/user_ca_key1 -I "regress user key for $USER" \ + -z $$ -n ${USER} $OBJ/user_key3 || + fatal "couldn't sign user_key3 with user_ca_key1" +rm $OBJ/user_key3.pub # to test use of private key w/o public half. +${SSHKEYGEN} -q -s $OBJ/user_ca_key1 -I "regress user key for $USER" \ + -z $$ -n ${USER} $OBJ/user_key4 || + fatal "couldn't sign user_key4 with user_ca_key1" +rm $OBJ/user_key4 $OBJ/user_key4.pub # to test no matching pub/private key case. trace 'try with identity files' opts="-F $OBJ/ssh_proxy -oIdentitiesOnly=yes" opts2="$opts -i $OBJ/user_key1 -i $OBJ/user_key2" echo "cert-authority $(cat $OBJ/user_ca_key1.pub)" > $OBJ/authorized_keys_$USER +# Make a clean config that doesn't have any pre-added identities. +cat $OBJ/ssh_proxy | grep -v IdentityFile > $OBJ/no_identity_config + +# XXX: verify that certificate used was what we expect. Needs exposure of +# keys via enviornment variable or similar. + for p in ${SSH_PROTOCOLS}; do + # Key with no .pub should work - finding the equivalent *-cert.pub. + verbose "protocol $p: identity cert with no plain public file" + ${SSH} -F $OBJ/no_identity_config -oIdentitiesOnly=yes \ + -i $OBJ/user_key3 somehost exit 5$p + [ $? -ne 5$p ] && fail "ssh failed" + + # CertificateFile matching private key with no .pub file should work. + verbose "protocol $p: CertificateFile with no plain public file" + ${SSH} -F $OBJ/no_identity_config -oIdentitiesOnly=yes \ + -oCertificateFile=$OBJ/user_key3-cert.pub \ + -i $OBJ/user_key3 somehost exit 5$p + [ $? -ne 5$p ] && fail "ssh failed" + # Just keys should fail + verbose "protocol $p: plain keys" ${SSH} $opts2 somehost exit 5$p r=$? if [ $r -eq 5$p ]; then @@ -42,6 +77,7 @@ for p in ${SSH_PROTOCOLS}; do fi # Keys with untrusted cert should fail. + verbose "protocol $p: untrusted cert" opts3="$opts2 -oCertificateFile=$OBJ/cert_user_key1_2.pub" ${SSH} $opts3 somehost exit 5$p r=$? @@ -50,6 +86,7 @@ for p in ${SSH_PROTOCOLS}; do fi # Good cert with bad key should fail. + verbose "protocol $p: good cert, bad key" opts3="$opts -i $OBJ/user_key2" opts3="$opts3 -oCertificateFile=$OBJ/cert_user_key1_1.pub" ${SSH} $opts3 somehost exit 5$p @@ -59,6 +96,7 @@ for p in ${SSH_PROTOCOLS}; do fi # Keys with one trusted cert, should succeed. + verbose "protocol $p: single trusted" opts3="$opts2 -oCertificateFile=$OBJ/cert_user_key1_1.pub" ${SSH} $opts3 somehost exit 5$p r=$? @@ -67,6 +105,7 @@ for p in ${SSH_PROTOCOLS}; do fi # Multiple certs and keys, with one trusted cert, should succeed. + verbose "protocol $p: multiple trusted" opts3="$opts2 -oCertificateFile=$OBJ/cert_user_key1_2.pub" opts3="$opts3 -oCertificateFile=$OBJ/cert_user_key1_1.pub" ${SSH} $opts3 somehost exit 5$p @@ -74,14 +113,6 @@ for p in ${SSH_PROTOCOLS}; do if [ $r -ne 5$p ]; then fail "ssh failed with multiple certs in protocol $p" fi - - #Keys with trusted certificate specified in config options, should succeed. - opts3="$opts2 -oCertificateFile=$OBJ/cert_user_key1_1.pub" - ${SSH} $opts3 somehost exit 5$p - r=$? - if [ $r -ne 5$p ]; then - fail "ssh failed with trusted cert in config in protocol $p" - fi done #next, using an agent in combination with the keys diff --git a/regress/forwarding.sh b/regress/forwarding.sh index 60c37d8..45c596d 100644 --- a/regress/forwarding.sh +++ b/regress/forwarding.sh @@ -10,7 +10,7 @@ start_sshd base=33 last=$PORT fwd="" -CTL=$OBJ/ctl-sock +CTL=/tmp/openssh.regress.ctl-sock.$$ for j in 0 1 2; do for i in 0 1 2; do diff --git a/regress/keytype.sh b/regress/keytype.sh index 8f69778..88b022d 100644 --- a/regress/keytype.sh +++ b/regress/keytype.sh @@ -1,13 +1,8 @@ -# $OpenBSD: keytype.sh,v 1.4 2015/07/10 06:23:25 markus Exp $ +# $OpenBSD: keytype.sh,v 1.5 2017/03/20 22:08:06 djm Exp $ # Placed in the Public Domain. tid="login with different key types" -TIME=`which time 2>/dev/null` -if test ! -x "$TIME"; then - TIME="" -fi - cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak cp $OBJ/ssh_proxy $OBJ/ssh_proxy_bak @@ -26,8 +21,8 @@ for kt in $ktypes; do rm -f $OBJ/key.$kt bits=`echo ${kt} | awk -F- '{print $2}'` type=`echo ${kt} | awk -F- '{print $1}'` - printf "keygen $type, $bits bits:\t" - ${TIME} ${SSHKEYGEN} -b $bits -q -N '' -t $type -f $OBJ/key.$kt ||\ + verbose "keygen $type, $bits bits" + ${SSHKEYGEN} -b $bits -q -N '' -t $type -f $OBJ/key.$kt ||\ fail "ssh-keygen for type $type, $bits bits failed" done @@ -63,8 +58,8 @@ for ut in $ktypes; do ) > $OBJ/known_hosts cat $OBJ/key.$ut.pub > $OBJ/authorized_keys_$USER for i in $tries; do - printf "userkey $ut, hostkey ${ht}:\t" - ${TIME} ${SSH} -F $OBJ/ssh_proxy 999.999.999.999 true + verbose "userkey $ut, hostkey ${ht}" + ${SSH} -F $OBJ/ssh_proxy 999.999.999.999 true if [ $? -ne 0 ]; then fail "ssh userkey $ut, hostkey $ht failed" fi diff --git a/regress/pesterTests/PlatformAbstractLayer.psm1 b/regress/pesterTests/PlatformAbstractLayer.psm1 index 48f2b38..5999746 100644 --- a/regress/pesterTests/PlatformAbstractLayer.psm1 +++ b/regress/pesterTests/PlatformAbstractLayer.psm1 @@ -64,7 +64,7 @@ function Is-CoreCLR { Class Machine { - [string] $MachineName = $env:COMPUTERNAME + [string] $MachineName = "localhost" [MachineRole] $Role = [MachineRole]::Client [PlatformType] $Platform [boolean] $IsCoreCLR @@ -72,8 +72,9 @@ Class Machine #Members on server role [string []] $PublicHostKeyPaths [string []] $PrivateHostKeyPaths - [string] $localAdminUserName = "localadmin" - [string] $localAdminPassword = "Bull_dog1" + [string] $ssouser = "sshtest_ssouser" + [string] $passwduser = "sshtest_passwduser" + [string] $passwduser_pw = "P@ssw0rd_1" [string] $localAdminAuthorizedKeyPath [string] $sshdConfigFile = (join-path $PSScriptRoot "sshd_config") [string] $backupFileName = (join-path $PSScriptRoot "sshd_backup") @@ -92,19 +93,19 @@ Class Machine Machine() { $this.Platform = Set-Platform $this.IsCoreCLR = Is-CoreCLR - $this.InitializeClient() - $this.InitializeServer() + #$this.InitializeClient() + #$this.InitializeServer() } Machine ([MachineRole] $r) { $this.Platform = Set-Platform $this.IsCoreCLR = Is-CoreCLR $this.Role = $r - if($this.Role -eq [MachineRole]::Client) { - $this.InitializeClient() - } else { - $this.InitializeServer() - } + #if($this.Role -eq [MachineRole]::Client) { + # $this.InitializeClient() + #} else { + # $this.InitializeServer() + #} } [void] InitializeClient() { @@ -127,14 +128,6 @@ Class Machine } } - foreach($key in @("ed25519")) #@("rsa","dsa","ecdsa","ed25519") - { - $keyPath = "$($this.ClientKeyDirectory)\id_$key" - $this.clientPrivateKeyPaths += $keyPath - $this.clientPublicKeyPaths += "$keyPath.pub" - $str = ".\ssh-keygen -t $key -P """" -f $keyPath" - $this.RunCmd($str) - } } [void] InitializeServer() { @@ -157,13 +150,6 @@ Class Machine } $this.localAdminAuthorizedKeyPath = join-path $($this.localUserprofilePath) ".ssh/authorized_keys" Remove-Item -Path $($this.localAdminAuthorizedKeyPath) -Force -ea silentlycontinue - - #Generate all host keys - .\ssh-keygen -A - $this.PublicHostKeyPaths = @("$psscriptroot\ssh_host_ed25519_key.pub") - # @("$psscriptroot\ssh_host_rsa_key.pub","$psscriptroot\ssh_host_dsa_key.pub","$psscriptroot\ssh_host_ecdsa_key.pub","$psscriptroot\ssh_host_ed25519_key.pub") - $this.PrivateHostKeyPaths = @("$psscriptroot\ssh_host_ed25519_key") - # @("$psscriptroot\ssh_host_rsa_key","$psscriptroot\ssh_host_dsa_key","$psscriptroot\ssh_host_ecdsa_key","$psscriptroot\ssh_host_ed25519_key") } [void] SetupClient([Machine] $server) { @@ -251,6 +237,11 @@ Class Machine { $this.SetKeys($null, $publicKeyPath, $($this.localAdminAuthorizedKeyPath)) } + # Provide Read Access to NT Service\sshd + $acl = get-acl $($this.localAdminAuthorizedKeyPath) + $ar = New-Object System.Security.AccessControl.FileSystemAccessRule("NT Service\sshd", "Read", "Allow") + $acl.SetAccessRule($ar) + Set-Acl $($this.localAdminAuthorizedKeyPath) $acl } [void] CleanupServer() { @@ -351,7 +342,8 @@ Class Machine } [void] AddPasswordSetting([string] $pass) { - if ($this.Platform -eq [PlatformType]::Windows) { + if ($this.Platform -eq [PlatformType]::Windows) { + if (-not($env:DISPLAY)) {$env:DISPLAY=1} $env:SSH_ASKPASS="$($env:ComSpec) /c echo $pass" } } @@ -359,6 +351,7 @@ Class Machine [void] CleanupPasswordSetting() { if ($this.Platform -eq [PlatformType]::Windows -and (Test-Path env:SSH_ASKPASS)) { + if ($env:DISPLAY -eq 1) {Remove-Item env:\DISPLAY} remove-item "env:SSH_ASKPASS" -ErrorAction SilentlyContinue } } diff --git a/regress/pesterTests/PortForwarding.Tests.ps1 b/regress/pesterTests/PortForwarding.Tests.ps1 index 4a2eb32..8fd2ff1 100644 --- a/regress/pesterTests/PortForwarding.Tests.ps1 +++ b/regress/pesterTests/PortForwarding.Tests.ps1 @@ -1,53 +1,45 @@ -using module .\PlatformAbstractLayer.psm1 - + Describe "Tests for portforwarding" -Tags "CI" { - BeforeAll { + BeforeAll { + + if($OpenSSHTestInfo -eq $null) + { + Throw "`$OpenSSHTestInfo is null. Please run Setup-OpenSSHTestEnvironment to setup test environment." + } $fileName = "test.txt" $filePath = Join-Path ${TestDrive} $fileName - - [Machine] $client = [Machine]::new([MachineRole]::Client) - [Machine] $server = [Machine]::new([MachineRole]::Server) - $client.SetupClient($server) - $server.SetupServer($client) - - $server.SecureHostKeys($server.PrivateHostKeyPaths) - $server.SetupServerRemoting([Protocol]::WSMAN) - #setup single signon - .\ssh-add.exe $client.clientPrivateKeyPaths[0] - Remove-Item -Path $filePath -Force -ea silentlycontinue + $logName = "log.txt" + $logPath = Join-Path ${TestDrive} $logName + $server = $OpenSSHTestInfo["Target"] + $port = $OpenSSHTestInfo["Port"] + $ssouser = $OpenSSHTestInfo["SSOUser"] $testData = @( @{ Title = "Local port forwarding" Options = "-L 5432:127.0.0.1:47001" - Port = 5432 + FwdedPort = 5432 }, @{ Title = "Remote port forwarding" Options = "-R 5432:127.0.0.1:47001" - Port = 5432 + FwdedPort = 5432 } ) } - AfterAll { - #cleanup single signon - .\ssh-add.exe -D - $Server.CleanupHostKeys() - $client.CleanupClient() - $server.CleanupServer() - } - AfterEach { Remove-Item -Path $filePath -Force -ea silentlycontinue + Remove-Item -Path $logPath -Force -ea silentlycontinue } It '' -TestCases:$testData { - param([string]$Title, $Options, $port) - - $str = ".\ssh $($Options) $($server.localAdminUserName)@$($server.MachineName) powershell.exe Test-WSMan -computer 127.0.0.1 -port $port > $filePath" - $client.RunCmd($str) + param([string]$Title, $Options, $FwdedPort) + + $str = "ssh -p $($port) -E $logPath $($Options) $($ssouser)@$($server) powershell.exe Test-WSMan -computer 127.0.0.1 -port $FwdedPort > $filePath" + # TODO - move this to PAL + cmd /c $str #validate file content. $content = Get-Content $filePath $content -like "wsmid*" | Should Not Be $null diff --git a/regress/pesterTests/PowerShell.SSH.Tests.ps1 b/regress/pesterTests/PowerShell.SSH.Tests.ps1 index 4e87200..1f8acd7 100644 --- a/regress/pesterTests/PowerShell.SSH.Tests.ps1 +++ b/regress/pesterTests/PowerShell.SSH.Tests.ps1 @@ -1,6 +1,4 @@ -using module .\PlatformAbstractLayer.psm1 - -Describe "Tests for powershell over ssh" -Tags "Scenario" { +Describe "Tests for powershell over ssh" -Tags "Scenario" { BeforeAll { $defaultParamValues = $PSDefaultParameterValues.Clone() #Skip on windows powershell. this feature only supported in powershell core from git diff --git a/regress/pesterTests/README.md b/regress/pesterTests/README.md new file mode 100644 index 0000000..9d41eac --- /dev/null +++ b/regress/pesterTests/README.md @@ -0,0 +1,42 @@ +Run OpenSSH Pester Tests: +================================== + +#### To setup the test environment before test run: + +```powershell +Import-Module .\openssh-portable\contrib\win32\openssh\OpenSSHTestHelper.psm1 –Force +Setup-OpenSSHTestEnvironment +``` + +`Setup-OpenSSHTestEnvironment` contains below parameters: +* `-OpenSSHBinPath`: Specify the location where ssh.exe should be picked up. If not specified, the function will prompt to user if he/she want to choose the first ssh.exe found in `$env:path` if exists. +* `-TestDataPath`: Specify the location where the test binaries deploy to. The default is `$env:SystemDrive\OpenSSHTests` if it not specified. +* `-Quiet`: If it is set, the function will do all the changes without prompting to user to confirm. +* `-DebugMode`: If it is set, the subsequent tests will be running in debug mode. User can modify by setting $OpenSSHTestInfo["DebugMode"] . + +#### To run the test suites: + +```powershell +Run-OpenSSHE2ETest +Run-OpenSSHUnitTest +``` + +#### To run a particular test, just run the script or the executatlbe directly + +```powershell +C:\git\openssh-portable\regress\pesterTests\SCP.Tests.ps1 +C:\git\openssh-portable\bin\x64\Release\unittest-bitmap\unittest-bitmap.exe +``` + +#### To verify / modify (Ex- DebugMode) the Test setup environment + +```powershell +$OpenSSHTestInfo +$OpenSSHTestInfo["DebugMode"] = $true +``` + +#### To revert what's done in Setup-OpenSSHTestEnvironment: + +```powershell +Cleanup-OpenSSHTestEnvironment +``` diff --git a/regress/pesterTests/SCP.Tests.ps1 b/regress/pesterTests/SCP.Tests.ps1 index c05ca53..30c78a2 100644 --- a/regress/pesterTests/SCP.Tests.ps1 +++ b/regress/pesterTests/SCP.Tests.ps1 @@ -1,30 +1,39 @@ -using module .\PlatformAbstractLayer.psm1 - + #covered -i -p -q -r -v -c -S -C #todo: -F, -l and -P should be tested over the network Describe "Tests for scp command" -Tags "CI" { - BeforeAll { + BeforeAll { + if($OpenSSHTestInfo -eq $null) + { + Throw "`$OpenSSHTestInfo is null. Please run Setup-OpenSSHTestEnvironment to setup test environment." + } + + if(-not (Test-Path $OpenSSHTestInfo["TestDataPath"])) + { + $null = New-Item $OpenSSHTestInfo["TestDataPath"] -ItemType directory -Force -ErrorAction SilentlyContinue + } + $fileName1 = "test.txt" $fileName2 = "test2.txt" $SourceDirName = "SourceDir" - $SourceDir = Join-Path ${TestDrive} $SourceDirName + $SourceDir = Join-Path "$($OpenSSHTestInfo["TestDataPath"])\SCP" $SourceDirName $SourceFilePath = Join-Path $SourceDir $fileName1 - $DestinationDir = Join-Path ${TestDrive} "DestDir" + $DestinationDir = Join-Path "$($OpenSSHTestInfo["TestDataPath"])\SCP" "DestDir" $DestinationFilePath = Join-Path $DestinationDir $fileName1 $NestedSourceDir= Join-Path $SourceDir "nested" $NestedSourceFilePath = Join-Path $NestedSourceDir $fileName2 - $null = New-Item $SourceDir -ItemType directory -Force - $null = New-Item $NestedSourceDir -ItemType directory -Force - $null = New-item -path $SourceFilePath -force - $null = New-item -path $NestedSourceFilePath -force + $null = New-Item $SourceDir -ItemType directory -Force -ErrorAction SilentlyContinue + $null = New-Item $NestedSourceDir -ItemType directory -Force -ErrorAction SilentlyContinue + $null = New-item -path $SourceFilePath -force -ErrorAction SilentlyContinue + $null = New-item -path $NestedSourceFilePath -force -ErrorAction SilentlyContinue "Test content111" | Set-content -Path $SourceFilePath "Test content in nested dir" | Set-content -Path $NestedSourceFilePath - $null = New-Item $DestinationDir -ItemType directory -Force - - [Machine] $client = [Machine]::new([MachineRole]::Client) - [Machine] $server = [Machine]::new([MachineRole]::Server) - $client.SetupClient($server) - $server.SetupServer($client) + $null = New-Item $DestinationDir -ItemType directory -Force -ErrorAction SilentlyContinue + $sshcmd = (get-command ssh).Path + + $server = $OpenSSHTestInfo["Target"] + $port = $OpenSSHTestInfo["Port"] + $ssouser = $OpenSSHTestInfo["SSOUser"] $script:logNum = 0 $testData = @( @@ -32,31 +41,37 @@ Describe "Tests for scp command" -Tags "CI" { Title = 'Simple copy local file to local file' Source = $SourceFilePath Destination = $DestinationFilePath + Options = "-P $port " }, @{ Title = 'Simple copy local file to remote file' Source = $SourceFilePath - Destination = "$($server.localAdminUserName)@$($server.MachineName):$DestinationFilePath" + Destination = "$($ssouser)@$($server):$DestinationFilePath" + Options = "-P $port -S $sshcmd" }, @{ Title = 'Simple copy remote file to local file' - Source = "$($server.localAdminUserName)@$($server.MachineName):$SourceFilePath" - Destination = $DestinationFilePath + Source = "$($ssouser)@$($server):$SourceFilePath" + Destination = $DestinationFilePath + Options = "-P $port -p -c aes128-ctr -C" }, @{ Title = 'Simple copy local file to local dir' Source = $SourceFilePath Destination = $DestinationDir + Options = "-P $port " }, @{ Title = 'simple copy local file to remote dir' Source = $SourceFilePath - Destination = "$($server.localAdminUserName)@$($server.MachineName):$DestinationDir" + Destination = "$($ssouser)@$($server):$DestinationDir" + Options = "-P $port -C -q" }, @{ Title = 'simple copy remote file to local dir' - Source = "$($server.localAdminUserName)@$($server.MachineName):$SourceFilePath" + Source = "$($ssouser)@$($server):$SourceFilePath" Destination = $DestinationDir + Options = "-P $port " } ) @@ -64,27 +79,45 @@ Describe "Tests for scp command" -Tags "CI" { @{ Title = 'copy from local dir to remote dir' Source = $sourceDir - Destination = "$($server.localAdminUserName)@$($server.MachineName):$DestinationDir" + Destination = "$($ssouser)@$($server):$DestinationDir" + Options = "-P $port -r -p -c aes128-ctr" }, - <# @{ + @{ Title = 'copy from local dir to local dir' Source = $sourceDir Destination = $DestinationDir - },#> + Options = "-r " + }, @{ Title = 'copy from remote dir to local dir' - Source = "$($server.localAdminUserName)@$($server.MachineName):$sourceDir" + Source = "$($ssouser)@$($server):$sourceDir" Destination = $DestinationDir + Options = "-P $port -C -r -q" } ) + # for the first time, delete the existing log files. + if ($OpenSSHTestInfo['DebugMode']) + { + Clear-Content "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\ssh-agent.log" -Force -ErrorAction ignore + Clear-Content "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\sshd.log" -Force -ErrorAction ignore + } + function CheckTarget { param([string]$target) if(-not (Test-path $target)) - { - Copy-Item .\logs\ssh-agent.log ".\logs\failedagent$script:logNum.log" -Force - Copy-Item .\logs\sshd.log ".\logs\failedsshd$script:logNum.log" -Force - $script:logNum++ + { + if( $OpenSSHTestInfo["DebugMode"]) + { + Copy-Item "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\ssh-agent.log" "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\failedagent$script:logNum.log" -Force + Copy-Item "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\sshd.log" "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\failedsshd$script:logNum.log" -Force + + $script:logNum++ + + # clear the ssh-agent, sshd logs so that next testcase will get fresh logs. + Clear-Content "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\ssh-agent.log" -Force -ErrorAction ignore + Clear-Content "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\sshd.log" -Force -ErrorAction ignore + } return $false } @@ -93,11 +126,21 @@ Describe "Tests for scp command" -Tags "CI" { } AfterAll { - $client.CleanupClient() - $server.CleanupServer() - - Get-Item $SourceDir | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue - Get-Item $DestinationDir | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue + if($OpenSSHTestInfo -eq $null) + { + #do nothing + } + elseif( -not $OpenSSHTestInfo['DebugMode']) + { + if(-not [string]::IsNullOrEmpty($SourceDir)) + { + Get-Item $SourceDir | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue + } + if(-not [string]::IsNullOrEmpty($DestinationDir)) + { + Get-Item $DestinationDir | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue + } + } } BeforeAll { @@ -106,170 +149,50 @@ Describe "Tests for scp command" -Tags "CI" { AfterEach { Get-ChildItem $DestinationDir -Recurse | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue - } - - <#Context "SCP usage" { - It 'SCP usage' { - #TODO: usage output does not redirect to file - } - }#> + } - Context "Key is Secured in ssh-agent on server" { - BeforeAll { - $Server.SecureHostKeys($server.PrivateHostKeyPaths) - $privateKeyFile = $client.clientPrivateKeyPaths[0] - } - BeforeEach { - if ($env:DebugMode) - { - Stop-Service ssh-agent -Force - Start-Sleep 2 - Remove-Item .\logs\ssh-agent.log -Force -ErrorAction ignore - Remove-Item .\logs\sshd.log -Force -ErrorAction ignore - Start-Service sshd - } - } - AfterAll { - $Server.CleanupHostKeys() - } - - It 'File copy with -i option and private key: <Title> ' -TestCases:$testData { - param([string]$Title, $Source, $Destination) - .\scp -i $privateKeyFile $Source $Destination - $LASTEXITCODE | Should Be 0 - - #validate file content. DestPath is the path to the file. - CheckTarget -target $DestinationFilePath | Should Be $true - $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 and private key: <Title> ' -TestCases:$testData1 { - param([string]$Title, $Source, $Destination) - - .\scp -r -i $privateKeyFile $Source $Destination - $LASTEXITCODE | Should Be 0 - CheckTarget -target (join-path $DestinationDir $SourceDirName) | Should Be $true + It 'File copy: <Title> ' -TestCases:$testData { + param([string]$Title, $Source, $Destination, $Options) - $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 "Single signon with keys -p -v -c option Secured in ssh-agent" { - BeforeAll { - $Server.SecureHostKeys($server.PrivateHostKeyPaths) - $identifyFile = $client.clientPrivateKeyPaths[0] - #setup single signon - .\ssh-add.exe $identifyFile - } + iex "scp $Options $Source $Destination" + $LASTEXITCODE | Should Be 0 + #validate file content. DestPath is the path to the file. + CheckTarget -target $DestinationFilePath | Should Be $true - AfterAll { - $Server.CleanupHostKeys() + $equal = @(Compare-Object (Get-ChildItem -path $SourceFilePath) (Get-ChildItem -path $DestinationFilePath) -Property Name, Length ).Length -eq 0 + $equal | Should Be $true - #cleanup single signon - .\ssh-add.exe -D - } - - It 'File copy with -S -v option (positive)' { - .\scp -S .\ssh.exe -v $SourceFilePath "$($server.localAdminUserName)@$($server.MachineName):$DestinationFilePath" - $LASTEXITCODE | Should Be 0 - #validate file content. DestPath is the path to the file. - CheckTarget -target $DestinationFilePath | Should Be $true - $equal = @(Compare-Object (Get-ChildItem -path $SourceFilePath) (Get-ChildItem -path $DestinationFilePath) -Property Name, Length).Length -eq 0 + if($Options.contains("-p")) + { + $equal = @(Compare-Object (Get-ChildItem -path $SourceFilePath).LastWriteTime.DateTime (Get-ChildItem -path $DestinationFilePath).LastWriteTime.DateTime ).Length -eq 0 $equal | Should Be $true } - - It 'File copy with -p -c option: <Title> ' -TestCases:$testData { - param([string]$Title, $Source, $Destination) - - .\scp -p -c aes128-ctr -C $Source $Destination - $LASTEXITCODE | Should Be 0 - #validate file content. DestPath is the path to the file. - CheckTarget -target $DestinationFilePath | Should Be $true - $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 -c option: <Title> ' -TestCases:$testData1 { - param([string]$Title, $Source, $Destination) + It 'Directory recursive copy: <Title> ' -TestCases:$testData1 { + param([string]$Title, $Source, $Destination, $Options) - .\scp -r -p -c aes128-ctr $Source $Destination - $LASTEXITCODE | Should Be 0 - CheckTarget -target (join-path $DestinationDir $SourceDirName) | Should Be $true - $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 - } - } - - 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{ - param([string]$Title, $Source, $Destination) + iex "scp $Options $Source $Destination" + $LASTEXITCODE | Should Be 0 + CheckTarget -target (join-path $DestinationDir $SourceDirName) | Should Be $true - .\scp -i $identifyFile -C -q $Source $Destination - $LASTEXITCODE | Should Be 0 - #validate file content. DestPath is the path to the file. - CheckTarget -target $DestinationFilePath | Should Be $true - $equal = @(Compare-Object (Get-ChildItem -path $SourceFilePath) (Get-ChildItem -path $DestinationFilePath) -Property Name, Length).Length -eq 0 + $equal = @(Compare-Object (Get-Item -path $SourceDir ) (Get-Item -path (join-path $DestinationDir $SourceDirName) ) -Property Name, Length).Length -eq 0 + $equal | Should Be $true + + if($Options.contains("-p")) + { + $equal = @(Compare-Object (Get-Item -path $SourceDir).LastWriteTime.DateTime (Get-Item -path (join-path $DestinationDir $SourceDirName)).LastWriteTime.DateTime).Length -eq 0 $equal | Should Be $true } - It 'Directory recursive copy with -i -C -r and -q options: <Title> ' -TestCases:$testData1 { - param([string]$Title, $Source, $Destination) + $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 - .\scp -i $identifyFile -C -r -q $Source $Destination - $LASTEXITCODE | Should Be 0 - CheckTarget -target (join-path $DestinationDir $SourceDirName) | Should Be $true - $equal = @(Compare-Object (Get-Item -path $SourceDir ) (Get-Item -path (join-path $DestinationDir $SourceDirName) ) -Property Name, Length).Length -eq 0 + if($Options.contains("-p")) + { + $equal = @(Compare-Object (Get-ChildItem -Recurse -path $SourceDir).LastWriteTime.DateTime (Get-ChildItem -Recurse -path (join-path $DestinationDir $SourceDirName) ).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).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 - $LASTEXITCODE | Should Be 0 - #validate file content. DestPath is the path to the file. - CheckTarget -target $DestinationFilePath | Should Be $true - $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 - $LASTEXITCODE | Should Be 0 - CheckTarget -target (join-path $DestinationDir $SourceDirName) | Should Be $true - $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/SFTP.Tests.ps1 b/regress/pesterTests/SFTP.Tests.ps1 index 0060ff8..9f82e0f 100644 --- a/regress/pesterTests/SFTP.Tests.ps1 +++ b/regress/pesterTests/SFTP.Tests.ps1 @@ -1,75 +1,80 @@ -using module .\PlatformAbstractLayer.psm1 - -Describe "SFTP Testcases" -Tags "CI" { +Describe "SFTP Test Cases" -Tags "CI" { BeforeAll { - $rootDirectory = $TestDrive + if($OpenSSHTestInfo -eq $null) + { + Throw "`$OpenSSHTestInfo is null. Please run Setup-OpenSSHTestEnvironment to setup test environment." + } + + if(-not (Test-Path $OpenSSHTestInfo["TestDataPath"])) + { + $null = New-Item $OpenSSHTestInfo["TestDataPath"] -ItemType directory -Force -ErrorAction SilentlyContinue + } + + $rootDirectory = "$($OpenSSHTestInfo["TestDataPath"])\SFTP" $outputFileName = "output.txt" $batchFileName = "sftp-batchcmds.txt" $outputFilePath = Join-Path $rootDirectory $outputFileName $batchFilePath = Join-Path $rootDirectory $batchFileName - + $tempFileName = "tempFile.txt" $tempFilePath = Join-Path $rootDirectory $tempFileName - + $tempUnicodeFileName = "tempFile_язык.txt" $tempUnicodeFilePath = Join-Path $rootDirectory $tempUnicodeFileName - + $clientDirectory = Join-Path $rootDirectory 'client_dir' $serverDirectory = Join-Path $rootDirectory 'server_dir' - + $null = New-Item $clientDirectory -ItemType directory -Force $null = New-Item $serverDirectory -ItemType directory -Force $null = New-Item $batchFilePath -ItemType file -Force $null = New-Item $outputFilePath -ItemType file -Force $null = New-Item $tempFilePath -ItemType file -Force -value "temp file data" $null = New-Item $tempUnicodeFilePath -ItemType file -Force -value "temp file data" - - $expectedOutputDelimiter = "#DL$" - - [Machine] $client = [Machine]::new([MachineRole]::Client) - [Machine] $server = [Machine]::new([MachineRole]::Server) - $client.SetupClient($server) - $server.SetupServer($client) - + + $server = $OpenSSHTestInfo["Target"] + $port = $OpenSSHTestInfo["Port"] + $ssouser = $OpenSSHTestInfo["SSOUser"] + $script:testId = 1 + $testData1 = @( @{ title = "put, ls for non-unicode file names" - logonstr = "$($server.localadminusername)@$($server.machinename)" - options = '-i $identifyfile' + logonstr = "$($ssouser)@$($server)" + options = '' commands = "put $tempFilePath $serverDirectory ls $serverDirectory" expectedoutput = (join-path $serverdirectory $tempFileName) - }, @{ title = "get, ls for non-unicode file names" - logonstr = "$($server.localadminusername)@$($server.machinename)" - options = '-i $identifyfile' + logonstr = "$($ssouser)@$($server)" + options = '' commands = "get $tempFilePath $clientDirectory ls $clientDirectory" expectedoutput = (join-path $clientDirectory $tempFileName) }, @{ title = "mput, ls for non-unicode file names" - logonstr = "$($server.localadminusername)@$($server.machinename)" - options = '-i $identifyfile' + logonstr = "$($ssouser)@$($server)" + options = '' commands = "mput $tempFilePath $serverDirectory ls $serverDirectory" expectedoutput = (join-path $serverdirectory $tempFileName) }, @{ title = "mget, ls for non-unicode file names" - logonstr = "$($server.localadminusername)@$($server.machinename)" - options = '-i $identifyfile' + logonstr = "$($ssouser)@$($server)" + options = '' commands = "mget $tempFilePath $clientDirectory ls $clientDirectory" expectedoutput = (join-path $clientDirectory $tempFileName) }, @{ title = "mkdir, cd, pwd for non-unicode directory names" - logonstr = "$($server.localadminusername)@$($server.machinename)" - options = '-i $identifyfile' + logonstr = "$($ssouser)@$($server)" + options = '' commands = "cd $serverdirectory mkdir server_test_dir cd server_test_dir @@ -78,8 +83,8 @@ Describe "SFTP Testcases" -Tags "CI" { }, @{ Title = "lmkdir, lcd, lpwd for non-unicode directory names" - LogonStr = "$($server.localAdminUserName)@$($server.MachineName)" - Options = '-i $identifyFile' + LogonStr = "$($ssouser)@$($server)" + Options = '' Commands = "lcd $clientDirectory lmkdir client_test_dir lcd client_test_dir @@ -88,40 +93,40 @@ Describe "SFTP Testcases" -Tags "CI" { }, @{ title = "put, ls for unicode file names" - logonstr = "$($server.localadminusername)@$($server.machinename)" - options = '-i $identifyfile' + logonstr = "$($ssouser)@$($server)" + options = '' commands = "put $tempUnicodeFilePath $serverDirectory ls $serverDirectory" expectedoutput = (join-path $serverdirectory $tempUnicodeFileName) }, @{ title = "get, ls for unicode file names" - logonstr = "$($server.localadminusername)@$($server.machinename)" - options = '-i $identifyfile' + logonstr = "$($ssouser)@$($server)" + options = '' commands = "get $tempUnicodeFilePath $clientDirectory ls $clientDirectory" expectedoutput = (join-path $clientDirectory $tempUnicodeFileName) }, @{ title = "mput, ls for unicode file names" - logonstr = "$($server.localadminusername)@$($server.machinename)" - options = '-i $identifyfile' + logonstr = "$($ssouser)@$($server)" + options = '' commands = "mput $tempUnicodeFilePath $serverDirectory ls $serverDirectory" expectedoutput = (join-path $serverdirectory $tempUnicodeFileName) }, @{ title = "mget, ls for unicode file names" - logonstr = "$($server.localadminusername)@$($server.machinename)" - options = '-i $identifyfile' + logonstr = "$($ssouser)@$($server)" + options = '' commands = "mget $tempUnicodeFilePath $clientDirectory ls $clientDirectory" expectedoutput = (join-path $clientDirectory $tempUnicodeFileName) }, @{ title = "mkdir, cd, pwd for unicode directory names" - logonstr = "$($server.localadminusername)@$($server.machinename)" - options = '-i $identifyfile' + logonstr = "$($ssouser)@$($server)" + options = '' commands = "cd $serverdirectory mkdir server_test_dir_язык cd server_test_dir_язык @@ -130,8 +135,8 @@ Describe "SFTP Testcases" -Tags "CI" { }, @{ Title = "lmkdir, lcd, lpwd for unicode directory names" - LogonStr = "$($server.localAdminUserName)@$($server.MachineName)" - Options = '-i $identifyFile' + LogonStr = "$($ssouser)@$($server)" + Options = '' Commands = "lcd $clientDirectory lmkdir client_test_dir_язык lcd client_test_dir_язык @@ -144,8 +149,8 @@ Describe "SFTP Testcases" -Tags "CI" { $testData2 = @( @{ title = "rm, rmdir, rename for unicode file, directory" - logonstr = "$($server.localadminusername)@$($server.machinename)" - options = '-i $identifyfile -b $batchFilePath' + logonstr = "$($ssouser)@$($server)" + options = '-b $batchFilePath' tmpFileName1 = $tempUnicodeFileName tmpFilePath1 = $tempUnicodeFilePath @@ -159,8 +164,8 @@ Describe "SFTP Testcases" -Tags "CI" { }, @{ title = "rm, rmdir, rename for non-unicode file, directory" - logonstr = "$($server.localadminusername)@$($server.machinename)" - options = '-i $identifyfile -b $batchFilePath' + logonstr = "$($ssouser)@$($server)" + options = '-b $batchFilePath' tmpFileName1 = $tempFileName tmpFilePath1 = $tempFilePath @@ -173,96 +178,110 @@ Describe "SFTP Testcases" -Tags "CI" { tmpDirectoryPath2 = (join-path $serverDirectory "test_dir_2") } ) + + # for the first time, delete the existing log files. + if ($OpenSSHTestInfo['DebugMode']) + { + Clear-Content "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\ssh-agent.log" -Force -ErrorAction ignore + Clear-Content "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\sshd.log" -Force -ErrorAction ignore + Clear-Content "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\sftp-server.log" -Force -ErrorAction ignore + } + + function CopyDebugLogs { + if($OpenSSHTestInfo["DebugMode"]) + { + Copy-Item "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\ssh-agent.log" "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\ssh-agent_$script:testId.log" -Force + Copy-Item "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\sshd.log" "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\sshd_$script:testId.log" -Force + Copy-Item "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\sftp-server.log" "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\sftp-server_$script:testId.log" -Force + + $script:testId++ + + # clear the ssh-agent, sshd logs so that next testcase will get fresh logs. + Clear-Content "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\ssh-agent.log" -Force -ErrorAction ignore + Clear-Content "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\sshd.log" -Force -ErrorAction ignore + Clear-Content "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\sftp-server.log" -Force -ErrorAction ignore + } + } } AfterAll { - $client.CleanupClient() - $server.CleanupServer() - } - - Context "Single signon" { - BeforeAll { - $Server.SecureHostKeys($server.PrivateHostKeyPaths) - $identifyFile = $client.clientPrivateKeyPaths[0] - .\ssh-add.exe $identifyFile #setup single signon - } - AfterAll { - $Server.CleanupHostKeys() - .\ssh-add.exe -D #cleanup single signon - + if(!$OpenSSHTestInfo["DebugMode"]) + { Get-Item $rootDirectory | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue } + } - BeforeEach { - Get-ChildItem $serverDirectory | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue - Get-ChildItem $clientDirectory | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue - Remove-Item $batchFilePath - Remove-Item $outputFilePath - } - - It '<Title>' -TestCases:$testData1 { - param([string]$Title, $LogonStr, $Options, $Commands, $ExpectedOutput, $SkipVerification = $false) - - Set-Content $batchFilePath -Encoding UTF8 -value $Commands - $str = $ExecutionContext.InvokeCommand.ExpandString(".\sftp $($Options) -b $batchFilePath $($LogonStr) > $outputFilePath") - $client.RunCmd($str) + BeforeEach { + Get-ChildItem $serverDirectory | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue + Get-ChildItem $clientDirectory | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue + Remove-Item $batchFilePath + Remove-Item $outputFilePath + } - #validate file content. - $($ExpectedOutput).split($expectedOutputDelimiter) | foreach { - Test-Path ($_) | Should be $true - } - } - - It '<Title>' -TestCases:$testData2 { - param([string]$Title, $LogonStr, $Options, $tmpFileName1, $tmpFilePath1, $tmpFileName2, $tmpFilePath2, $tmpDirectoryName1, $tmpDirectoryPath1, $tmpDirectoryName2, $tmpDirectoryPath2, $SkipVerification = $false) - - #rm (remove file) - $commands = "mkdir $tmpDirectoryPath1 - put $tmpFilePath1 $tmpDirectoryPath1 - ls $tmpDirectoryPath1" - Set-Content $batchFilePath -Encoding UTF8 -value $commands - $str = $ExecutionContext.InvokeCommand.ExpandString(".\sftp $($Options) $($LogonStr) > $outputFilePath") - $client.RunCmd($str) - Test-Path (join-path $tmpDirectoryPath1 $tmpFileName1) | Should be $true - - $commands = "rm $tmpDirectoryPath1\* - ls $tmpDirectoryPath1 - pwd - " - Set-Content $batchFilePath -Encoding UTF8 -value $commands - $str = $ExecutionContext.InvokeCommand.ExpandString(".\sftp $($Options) $($LogonStr) > $outputFilePath") - $client.RunCmd($str) - Test-Path (join-path $tmpDirectoryPath1 $tmpFileName1) | Should be $false - - #rename file - Remove-Item $outputFilePath - Copy-Item $tmpFilePath1 -destination $tmpDirectoryPath1 - $commands = "rename $tmpDirectoryPath1\$tmpFileName1 $tmpDirectoryPath1\$tmpFileName2 - ls $tmpDirectoryPath1 - pwd" - Set-Content $batchFilePath -Encoding UTF8 -value $commands - $str = $ExecutionContext.InvokeCommand.ExpandString(".\sftp $($Options) $($LogonStr) > $outputFilePath") - $client.RunCmd($str) - Test-Path (join-path $tmpDirectoryPath1 $tmpFileName2) | Should be $true - - #rename directory - Remove-Item $outputFilePath - $commands = "rm $tmpDirectoryPath1\* - rename $tmpDirectoryPath1 $tmpDirectoryPath2 - ls $serverDirectory" - Set-Content $batchFilePath -Encoding UTF8 -value $commands - $str = $ExecutionContext.InvokeCommand.ExpandString(".\sftp $($Options) $($LogonStr) > $outputFilePath") - $client.RunCmd($str) - Test-Path $tmpDirectoryPath2 | Should be $true - - #rmdir (remove directory) - Remove-Item $outputFilePath - $commands = "rmdir $tmpDirectoryPath2 - ls $serverDirectory" - Set-Content $batchFilePath -Encoding UTF8 -value $commands - $str = $ExecutionContext.InvokeCommand.ExpandString(".\sftp $($Options) $($LogonStr) > $outputFilePath") - $client.RunCmd($str) - Test-Path $tmpDirectoryPath2 | Should be $false - } + AfterEach { + CopyDebugLogs + } + + It '<Title>' -TestCases:$testData1 { + param([string]$Title, $LogonStr, $Options, $Commands, $ExpectedOutput) + + Set-Content $batchFilePath -Encoding UTF8 -value $Commands + $str = $ExecutionContext.InvokeCommand.ExpandString("sftp -P $port $($Options) -b $batchFilePath $($LogonStr) > $outputFilePath") + iex $str + + #validate file content. + Test-Path $ExpectedOutput | Should be $true + } + + It '<Title>' -TestCases:$testData2 { + param([string]$Title, $LogonStr, $Options, $tmpFileName1, $tmpFilePath1, $tmpFileName2, $tmpFilePath2, $tmpDirectoryName1, $tmpDirectoryPath1, $tmpDirectoryName2, $tmpDirectoryPath2) + + #rm (remove file) + $commands = "mkdir $tmpDirectoryPath1 + put $tmpFilePath1 $tmpDirectoryPath1 + ls $tmpDirectoryPath1" + Set-Content $batchFilePath -Encoding UTF8 -value $commands + $str = $ExecutionContext.InvokeCommand.ExpandString("sftp -P $port $($Options) $($LogonStr) > $outputFilePath") + iex $str + Test-Path (join-path $tmpDirectoryPath1 $tmpFileName1) | Should be $true + + $commands = "rm $tmpDirectoryPath1\* + ls $tmpDirectoryPath1 + pwd + " + Set-Content $batchFilePath -Encoding UTF8 -value $commands + $str = $ExecutionContext.InvokeCommand.ExpandString("sftp -P $port $($Options) $($LogonStr) > $outputFilePath") + iex $str + Test-Path (join-path $tmpDirectoryPath1 $tmpFileName1) | Should be $false + + #rename file + Remove-Item $outputFilePath + Copy-Item $tmpFilePath1 -destination $tmpDirectoryPath1 + $commands = "rename $tmpDirectoryPath1\$tmpFileName1 $tmpDirectoryPath1\$tmpFileName2 + ls $tmpDirectoryPath1 + pwd" + Set-Content $batchFilePath -Encoding UTF8 -value $commands + $str = $ExecutionContext.InvokeCommand.ExpandString("sftp -P $port $($Options) $($LogonStr) > $outputFilePath") + iex $str + Test-Path (join-path $tmpDirectoryPath1 $tmpFileName2) | Should be $true + + #rename directory + Remove-Item $outputFilePath + $commands = "rm $tmpDirectoryPath1\* + rename $tmpDirectoryPath1 $tmpDirectoryPath2 + ls $serverDirectory" + Set-Content $batchFilePath -Encoding UTF8 -value $commands + $str = $ExecutionContext.InvokeCommand.ExpandString("sftp -P $port $($Options) $($LogonStr) > $outputFilePath") + iex $str + Test-Path $tmpDirectoryPath2 | Should be $true + + #rmdir (remove directory) + Remove-Item $outputFilePath + $commands = "rmdir $tmpDirectoryPath2 + ls $serverDirectory" + Set-Content $batchFilePath -Encoding UTF8 -value $commands + $str = $ExecutionContext.InvokeCommand.ExpandString("sftp -P $port $($Options) $($LogonStr) > $outputFilePath") + iex $str + Test-Path $tmpDirectoryPath2 | Should be $false } } diff --git a/regress/pesterTests/SSH.Tests.ps1 b/regress/pesterTests/SSH.Tests.ps1 index 9c461b1..58cb7a6 100644 --- a/regress/pesterTests/SSH.Tests.ps1 +++ b/regress/pesterTests/SSH.Tests.ps1 @@ -1,8 +1,6 @@ -using module .\PlatformAbstractLayer.psm1 - -#covered -i -q -v -l -c -C +#covered -i -q -v -l -c -C #todo: -S -F -V -e -Describe "Tests for ssh command" -Tags "CI" { +Describe "Tests for ssh command" -Tags "Scenario" { BeforeAll { $fileName = "test.txt" $filePath = Join-Path ${TestDrive} $fileName diff --git a/regress/pesterTests/SSHDConfig.tests.ps1 b/regress/pesterTests/SSHDConfig.tests.ps1 index ad45ffc..10f884a 100644 --- a/regress/pesterTests/SSHDConfig.tests.ps1 +++ b/regress/pesterTests/SSHDConfig.tests.ps1 @@ -1,6 +1,4 @@ -using module .\PlatformAbstractLayer.psm1 - -Describe "Tests of sshd_config" -Tags "CI" { +Describe "Tests of sshd_config" -Tags "Scenario" { BeforeAll { $fileName = "test.txt" $filePath = Join-Path ${TestDrive} $fileName diff --git a/regress/pesterTests/SSHD_Config b/regress/pesterTests/SSHD_Config index 2bfa486..4bab2a8 100644 --- a/regress/pesterTests/SSHD_Config +++ b/regress/pesterTests/SSHD_Config @@ -10,7 +10,7 @@ # possible, but leave them commented. Uncommented options override the # default value. -#Port 22 +Port 47002 #AddressFamily any #ListenAddress 0.0.0.0 #ListenAddress :: @@ -21,9 +21,10 @@ # HostKey for protocol version 1 #HostKey /etc/ssh/ssh_host_key # HostKeys for protocol version 2 -#HostKey /etc/ssh/ssh_host_rsa_key -#HostKey /etc/ssh/ssh_host_dsa_key -#HostKey /etc/ssh/ssh_host_ecdsa_key +HostKey sshtest_hostkey_rsa +HostKey sshtest_hostkey_dsa +HostKey sshtest_hostkey_ecdsa +HostKey sshtest_hostkey_ed25519 # Lifetime and size of ephemeral version 1 server key #KeyRegenerationInterval 1h @@ -112,7 +113,7 @@ AuthorizedKeysFile .ssh/authorized_keys #Banner none # override default of no subsystems -Subsystem sftp sftp-server.exe +Subsystem sftp sftp-server.exe -l DEBUG3 # Example of overriding settings on a per-user basis #Match User anoncvs @@ -121,7 +122,7 @@ Subsystem sftp sftp-server.exe # ForceCommand cvs server PubkeyAcceptedKeyTypes ssh-ed25519* -DenyUsers denyuser1 deny*2 denyuse?3, -AllowUsers allowuser1 allowu*r2 allow?se?3 allowuser4 localuser1 localu*r2 loc?lu?er3 localadmin -DenyGroups denygroup1 denygr*p2 deny?rou?3 -AllowGroups allowgroup1 allowg*2 allowg?ou?3 Adm* \ No newline at end of file +#DenyUsers denyuser1 deny*2 denyuse?3, +#AllowUsers allowuser1 allowu*r2 allow?se?3 allowuser4 localuser1 localu*r2 loc?lu?er3 localadmin +#DenyGroups denygroup1 denygr*p2 deny?rou?3 +#AllowGroups allowgroup1 allowg*2 allowg?ou?3 Adm* \ No newline at end of file diff --git a/regress/pesterTests/known_hosts b/regress/pesterTests/known_hosts new file mode 100644 index 0000000..2fc8989 --- /dev/null +++ b/regress/pesterTests/known_hosts @@ -0,0 +1,4 @@ +[localhost]:47002 ssh-dss AAAAB3NzaC1kc3MAAACBAIyVGPwSzaCedtroufmFrwXGVPzYUMHPePvlduORG2+1VmLkP2Yw+U6MHRnaDyDriCulhnmwIueGxhH+t0HKbGK0j7XpGnwgmFOBIg5gJwQTDJ+gX+qC2ju55WB0Gkkwl+xktnAFSqmj8ttSzUBhh1ksh5A6oW+NKjwEVH8tQExFAAAAFQC0YldxCDQbTuDO04EVgA0OMpDIvwAAAIBXWRzpoyQWNoB18DGbY9zupGhfwuKGmnlj2mY0aYxY3qu1+9ciQOBrwYJlf4dEJbirwp2XmKzHZ6LFrkLQptVcD1wDkG/a/wMRvh+tbxlq45S3Eh0oNj1cobhUlFm9m5PM2HW1LccbOAEBUG/L4Vcj1Ag4n639H0fwDRL+rwOpjgAAAIBh/fSBidBGsQITgg45wwDszk7AAhngNm+jbiea8dbgYP6wpT6dJdg3pYwKT0V/PdXTSDi16kkoMkbUsMZyxyFJf/TtmCtBnon55yL9+H5dtcOBF8BXR7KzQX1E1n0eIL9jZ0Q4BspkB4LKQXhxRnrNJlv/oopxXua/GCMW17xxuA== sshtest_hostkey_dsa +[localhost]:47002 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHF2eWwgnaUSLNNN0ilxiT916uMa6lusMB31AxfkDGArh4xCWL0e3F/gRifRephM0cD2dSh8Ji6VnjkhvZptjEw= sshtest_hostkey_ecdsa +[localhost]:47002 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMtJMxwn+iJU0X4+EC7PSj/cfcMbdP6ahhodtXx+6RHv sshtest_hostkey_ed25519 +[localhost]:47002 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDU+NcQ5NuRutQJoZVjDmP/vE6IYZOaE59FTUjaoZkuPl4prdOPgqAnCwSy9XtnfzPm/oe62SyYIHgj8wRzhqjMU8g8aGqfv9ryF+hpNXZrFYXIdkdxnubzfb4e70RRRoTH8P5vuY8sAn0FIRlV/3EDkSKBFy2W3InMTO6l8gbkzzkgbn1GLvH06QJVdb2PcHksSn7dJBVHWASYi3TJWWu4muI+ZNfothujxAHqjKTJuJ9apDZIc0tnkPmlifRmolSUS4OAH2KWZ+5Gwaj7gsB8bk4QuA+QCT60OCcuzCcy4FBuXvvXkM9MBe/P2KZjVLAn86SriRtoE4RI+9R9S7DV sshtest_hostkey_rsa diff --git a/regress/pesterTests/sshtest_hostkey_dsa b/regress/pesterTests/sshtest_hostkey_dsa new file mode 100644 index 0000000..ec1ff73 --- /dev/null +++ b/regress/pesterTests/sshtest_hostkey_dsa @@ -0,0 +1,12 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBuwIBAAKBgQCMlRj8Es2gnnba6Ln5ha8FxlT82FDBz3j75XbjkRtvtVZi5D9m +MPlOjB0Z2g8g64grpYZ5sCLnhsYR/rdBymxitI+16Rp8IJhTgSIOYCcEEwyfoF/q +gto7ueVgdBpJMJfsZLZwBUqpo/LbUs1AYYdZLIeQOqFvjSo8BFR/LUBMRQIVALRi +V3EINBtO4M7TgRWADQ4ykMi/AoGAV1kc6aMkFjaAdfAxm2Pc7qRoX8Lihpp5Y9pm +NGmMWN6rtfvXIkDga8GCZX+HRCW4q8Kdl5isx2eixa5C0KbVXA9cA5Bv2v8DEb4f +rW8ZauOUtxIdKDY9XKG4VJRZvZuTzNh1tS3HGzgBAVBvy+FXI9QIOJ+t/R9H8A0S +/q8DqY4CgYBh/fSBidBGsQITgg45wwDszk7AAhngNm+jbiea8dbgYP6wpT6dJdg3 +pYwKT0V/PdXTSDi16kkoMkbUsMZyxyFJf/TtmCtBnon55yL9+H5dtcOBF8BXR7Kz +QX1E1n0eIL9jZ0Q4BspkB4LKQXhxRnrNJlv/oopxXua/GCMW17xxuAIVAIy08ce7 +877PESiaI4iDWj36uuWV +-----END DSA PRIVATE KEY----- diff --git a/regress/pesterTests/sshtest_hostkey_dsa.pub b/regress/pesterTests/sshtest_hostkey_dsa.pub new file mode 100644 index 0000000..ce5b1a3 --- /dev/null +++ b/regress/pesterTests/sshtest_hostkey_dsa.pub @@ -0,0 +1 @@ +ssh-dss AAAAB3NzaC1kc3MAAACBAIyVGPwSzaCedtroufmFrwXGVPzYUMHPePvlduORG2+1VmLkP2Yw+U6MHRnaDyDriCulhnmwIueGxhH+t0HKbGK0j7XpGnwgmFOBIg5gJwQTDJ+gX+qC2ju55WB0Gkkwl+xktnAFSqmj8ttSzUBhh1ksh5A6oW+NKjwEVH8tQExFAAAAFQC0YldxCDQbTuDO04EVgA0OMpDIvwAAAIBXWRzpoyQWNoB18DGbY9zupGhfwuKGmnlj2mY0aYxY3qu1+9ciQOBrwYJlf4dEJbirwp2XmKzHZ6LFrkLQptVcD1wDkG/a/wMRvh+tbxlq45S3Eh0oNj1cobhUlFm9m5PM2HW1LccbOAEBUG/L4Vcj1Ag4n639H0fwDRL+rwOpjgAAAIBh/fSBidBGsQITgg45wwDszk7AAhngNm+jbiea8dbgYP6wpT6dJdg3pYwKT0V/PdXTSDi16kkoMkbUsMZyxyFJf/TtmCtBnon55yL9+H5dtcOBF8BXR7KzQX1E1n0eIL9jZ0Q4BspkB4LKQXhxRnrNJlv/oopxXua/GCMW17xxuA== sshtest_hostkey_dsa diff --git a/regress/pesterTests/sshtest_hostkey_ecdsa b/regress/pesterTests/sshtest_hostkey_ecdsa new file mode 100644 index 0000000..04fa8fd --- /dev/null +++ b/regress/pesterTests/sshtest_hostkey_ecdsa @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEICAT5BC1AJpeOsRQaettNtqw6rzKlHDgtGvqnYZuU8YOoAoGCCqGSM49 +AwEHoUQDQgAEcXZ5bCCdpRIs003SKXGJP3Xq4xrqW6wwHfUDF+QMYCuHjEJYvR7c +X+BGJ9F6mEzRwPZ1KHwmLpWeOSG9mm2MTA== +-----END EC PRIVATE KEY----- diff --git a/regress/pesterTests/sshtest_hostkey_ecdsa.pub b/regress/pesterTests/sshtest_hostkey_ecdsa.pub new file mode 100644 index 0000000..f0fc02d --- /dev/null +++ b/regress/pesterTests/sshtest_hostkey_ecdsa.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHF2eWwgnaUSLNNN0ilxiT916uMa6lusMB31AxfkDGArh4xCWL0e3F/gRifRephM0cD2dSh8Ji6VnjkhvZptjEw= sshtest_hostkey_ecdsa diff --git a/regress/pesterTests/sshtest_hostkey_ed25519 b/regress/pesterTests/sshtest_hostkey_ed25519 new file mode 100644 index 0000000..e3635f4 --- /dev/null +++ b/regress/pesterTests/sshtest_hostkey_ed25519 @@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACDLSTMcJ/oiVNF+PhAuz0o/3H3DG3T+moYaHbV8fukR7wAAAKACW4cWAluH +FgAAAAtzc2gtZWQyNTUxOQAAACDLSTMcJ/oiVNF+PhAuz0o/3H3DG3T+moYaHbV8fukR7w +AAAEDIU6PKvxw+6hgpQmTOOFeUasWnsYU3gricJCNrEHu2FstJMxwn+iJU0X4+EC7PSj/c +fcMbdP6ahhodtXx+6RHvAAAAF3NzaHRlc3RfaG9zdGtleV9lZDI1NTE5AQIDBAUG +-----END OPENSSH PRIVATE KEY----- diff --git a/regress/pesterTests/sshtest_hostkey_ed25519.pub b/regress/pesterTests/sshtest_hostkey_ed25519.pub new file mode 100644 index 0000000..6e7e563 --- /dev/null +++ b/regress/pesterTests/sshtest_hostkey_ed25519.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMtJMxwn+iJU0X4+EC7PSj/cfcMbdP6ahhodtXx+6RHv sshtest_hostkey_ed25519 diff --git a/regress/pesterTests/sshtest_hostkey_rsa b/regress/pesterTests/sshtest_hostkey_rsa new file mode 100644 index 0000000..cfb42de --- /dev/null +++ b/regress/pesterTests/sshtest_hostkey_rsa @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEA1PjXEOTbkbrUCaGVYw5j/7xOiGGTmhOfRU1I2qGZLj5eKa3T +j4KgJwsEsvV7Z38z5v6HutksmCB4I/MEc4aozFPIPGhqn7/a8hfoaTV2axWFyHZH +cZ7m832+Hu9EUUaEx/D+b7mPLAJ9BSEZVf9xA5EigRctltyJzEzupfIG5M85IG59 +Ri7x9OkCVXW9j3B5LEp+3SQVR1gEmIt0yVlruJriPmTX6LYbo8QB6oykybifWqQ2 +SHNLZ5D5pYn0ZqJUlEuDgB9ilmfuRsGo+4LAfG5OELgPkAk+tDgnLswnMuBQbl77 +15DPTAXvz9imY1SwJ/Okq4kbaBOESPvUfUuw1QIDAQABAoIBAGdEafRVJGqbbulk +om0vsyl0A5h5x/pz/Uy7VtI8fWxA7aPEF8uEiWelHhgwlC/xLBeb3/CoEcmKJPc5 +hTUHXJ4HGhbAgsMHYoD1OsqZE9yEySQUxju/0zjKBgA2AKhwSz4wCw/dqCCs7DYq +gICEpiYWn+Z8eKyoL2ETBL0OiG01c4oZ8Qd1WrNPNAOA8uX2avCIawiGqfI5hRR2 +UIpmTNsh8SbA7hMqI47JlLvmfAdKOvug09f36Yhx63RuXWy0AHqz3HcTe4K4tzlP +M+DnKDgHQkx8R5j/Q9Dv6ZlKn85FatIWftjd9e4Zsjx2lCKXBFIyn3EM1aiCaRAS +iIFJh4ECgYEA6nBShG3z6bLbBNEWPq2xqmq6uJDD7dg6glK5alDDKwCmurfQYxyY +HD/1YcIlf+kC4qUCrREgYlheH3xRbzT0yomtci015iC8R8ZZgGNqZO52HxhQVWdN +i08vsJmUnrq0WFyXS0OysnPCEPLbHBoFVbJWEDTgKxLOwbYMEyp7IHECgYEA6I8Z +tRE3AMbdYvN8+hjq5fcrsRZvkbddYa3DLYImii09s84p82MEskFd+dcTs6ViX2Qn +wFgdASCi0FBblKca6ZxgwMHoEEiWgx6zndayeU2wDGWCbHlVXkpnCPb7O+YoMKhy +XtDDfVZ0n0Cu+W6dlbVxWyP0uQ8RrE25Po/QSKUCgYAGCrkFsrO7jSF54U2ade2D +P9bqFMkH4y+21hzzMXumKxEg9MXJGB6Pc9KGH3PJ9R5e6vPDtBJKlo5ub0zF+e5p +Hd07eRDPin5vtxvtZCKE0WR37q97U/s6oOLQwVSENrmZIWHAzdDYKoWQ3EFrWvxS +NhNjvYkdcxGjCmcLQ2gC8QKBgD4IFZpXmi1J3jmLqxVm2hk3Id9dlarvlyf72mjk +I3WN9bxlTIlQKyuFBhUjSm0Luz6oj3XdyvbHBsa7+IGhRSt0+9XOoyDcy9DzuoNq +hjaXA1N7LBvVDXFWNT+N6Zujm6rG86LY2pwvGHJ2JXYBDGWnfTILWDaYj2U/Yh8O +60bFAoGAVnm3EVlak5mbDpSpyzqnglVKgZ+mz+4ODcF+qK4415QtAua8Je8Frcje +3dYJtP5c5Xm+wE5Lmr+yZUAxup5oC5NAmtvLwK8DLPjfZIBtF7qBf08am8e8HnZw +PzFks7iwv86eqgvTwBdE6QmaBzvEPLSmSI93uRz3q/S+16j50Pk= +-----END RSA PRIVATE KEY----- diff --git a/regress/pesterTests/sshtest_hostkey_rsa.pub b/regress/pesterTests/sshtest_hostkey_rsa.pub new file mode 100644 index 0000000..2c56f32 --- /dev/null +++ b/regress/pesterTests/sshtest_hostkey_rsa.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDU+NcQ5NuRutQJoZVjDmP/vE6IYZOaE59FTUjaoZkuPl4prdOPgqAnCwSy9XtnfzPm/oe62SyYIHgj8wRzhqjMU8g8aGqfv9ryF+hpNXZrFYXIdkdxnubzfb4e70RRRoTH8P5vuY8sAn0FIRlV/3EDkSKBFy2W3InMTO6l8gbkzzkgbn1GLvH06QJVdb2PcHksSn7dJBVHWASYi3TJWWu4muI+ZNfothujxAHqjKTJuJ9apDZIc0tnkPmlifRmolSUS4OAH2KWZ+5Gwaj7gsB8bk4QuA+QCT60OCcuzCcy4FBuXvvXkM9MBe/P2KZjVLAn86SriRtoE4RI+9R9S7DV sshtest_hostkey_rsa diff --git a/regress/pesterTests/sshtest_userssokey_ed25519 b/regress/pesterTests/sshtest_userssokey_ed25519 new file mode 100644 index 0000000..086588e --- /dev/null +++ b/regress/pesterTests/sshtest_userssokey_ed25519 @@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACArxdmtP2DtTFvNp+4N4vlEP2tBmG7QtG4qfNUKlYmxRQAAAKAX+9lZF/vZ +WQAAAAtzc2gtZWQyNTUxOQAAACArxdmtP2DtTFvNp+4N4vlEP2tBmG7QtG4qfNUKlYmxRQ +AAAEBkZYPXRU9wu7OCcBia+eKvWOtDKpZRibjGQMTdBlCn5CvF2a0/YO1MW82n7g3i+UQ/ +a0GYbtC0bip81QqVibFFAAAAGnNzaHRlc3RfdXNlcnNzb2tleV9lZDI1NTE5AQID +-----END OPENSSH PRIVATE KEY----- diff --git a/regress/pesterTests/sshtest_userssokey_ed25519.pub b/regress/pesterTests/sshtest_userssokey_ed25519.pub new file mode 100644 index 0000000..1456a87 --- /dev/null +++ b/regress/pesterTests/sshtest_userssokey_ed25519.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICvF2a0/YO1MW82n7g3i+UQ/a0GYbtC0bip81QqVibFF sshtest_userssokey_ed25519 diff --git a/regress/unittests/Makefile b/regress/unittests/Makefile index e70b166..e975f6c 100644 --- a/regress/unittests/Makefile +++ b/regress/unittests/Makefile @@ -1,5 +1,6 @@ -# $OpenBSD: Makefile,v 1.7 2016/08/19 06:44:13 djm Exp $ -REGRESS_FAIL_EARLY= yes -SUBDIR= test_helper sshbuf sshkey bitmap kex hostkeys utf8 match +# $OpenBSD: Makefile,v 1.9 2017/03/14 01:20:29 dtucker Exp $ + +REGRESS_FAIL_EARLY?= yes +SUBDIR= test_helper sshbuf sshkey bitmap kex hostkeys utf8 match conversion .include <bsd.subdir.mk> diff --git a/regress/unittests/conversion/Makefile b/regress/unittests/conversion/Makefile new file mode 100644 index 0000000..cde97dc --- /dev/null +++ b/regress/unittests/conversion/Makefile @@ -0,0 +1,10 @@ +# $OpenBSD: Makefile,v 1.1 2017/03/14 01:20:29 dtucker Exp $ + +PROG=test_conversion +SRCS=tests.c +REGRESS_TARGETS=run-regress-${PROG} + +run-regress-${PROG}: ${PROG} + env ${TEST_ENV} ./${PROG} + +.include <bsd.regress.mk> diff --git a/regress/unittests/conversion/tests.c b/regress/unittests/conversion/tests.c new file mode 100644 index 0000000..6dd77ef --- /dev/null +++ b/regress/unittests/conversion/tests.c @@ -0,0 +1,51 @@ +/* $OpenBSD: tests.c,v 1.1 2017/03/14 01:20:29 dtucker Exp $ */ +/* + * Regress test for conversions + * + * Placed in the public domain + */ + +#include "includes.h" + +#include <sys/types.h> +#include <sys/param.h> +#include <stdio.h> +#ifdef HAVE_STDINT_H +#include <stdint.h> +#endif +#include <stdlib.h> +#include <string.h> + +#include "../test_helper/test_helper.h" + +#include "misc.h" + +void +tests(void) +{ + char buf[1024]; + + TEST_START("conversion_convtime"); + ASSERT_LONG_EQ(convtime("0"), 0); + ASSERT_LONG_EQ(convtime("1"), 1); + ASSERT_LONG_EQ(convtime("1S"), 1); + /* from the examples in the comment above the function */ + ASSERT_LONG_EQ(convtime("90m"), 5400); + ASSERT_LONG_EQ(convtime("1h30m"), 5400); + ASSERT_LONG_EQ(convtime("2d"), 172800); + ASSERT_LONG_EQ(convtime("1w"), 604800); + + /* negative time is not allowed */ + ASSERT_LONG_EQ(convtime("-7"), -1); + ASSERT_LONG_EQ(convtime("-9d"), -1); + + /* overflow */ + snprintf(buf, sizeof buf, "%llu", (unsigned long long)LONG_MAX + 1); + ASSERT_LONG_EQ(convtime(buf), -1); + + /* overflow with multiplier */ + snprintf(buf, sizeof buf, "%lluM", (unsigned long long)LONG_MAX/60 + 1); + ASSERT_LONG_EQ(convtime(buf), -1); + ASSERT_LONG_EQ(convtime("1000000000000000000000w"), -1); + TEST_DONE(); +} diff --git a/regress/unittests/test_helper/test_helper.c b/regress/unittests/test_helper/test_helper.c index 26ca26b..f855137 100644 --- a/regress/unittests/test_helper/test_helper.c +++ b/regress/unittests/test_helper/test_helper.c @@ -1,4 +1,4 @@ -/* $OpenBSD: test_helper.c,v 1.6 2015/03/03 20:42:49 djm Exp $ */ +/* $OpenBSD: test_helper.c,v 1.7 2017/03/14 01:10:07 dtucker Exp $ */ /* * Copyright (c) 2011 Damien Miller <djm@mindrot.org> * @@ -441,6 +441,17 @@ assert_u_int(const char *file, int line, const char *a1, const char *a2, test_die(); } +void +assert_long(const char *file, int line, const char *a1, const char *a2, + long aa1, long aa2, enum test_predicate pred) +{ + TEST_CHECK(aa1, aa2, pred); + test_header(file, line, a1, a2, "LONG", pred); + fprintf(stderr, "%12s = %ld / 0x%lx\n", a1, aa1, aa1); + fprintf(stderr, "%12s = %ld / 0x%lx\n", a2, aa2, aa2); + test_die(); +} + void assert_long_long(const char *file, int line, const char *a1, const char *a2, long long aa1, long long aa2, enum test_predicate pred) diff --git a/regress/unittests/test_helper/test_helper.h b/regress/unittests/test_helper/test_helper.h index 1d9c669..615b783 100644 --- a/regress/unittests/test_helper/test_helper.h +++ b/regress/unittests/test_helper/test_helper.h @@ -1,4 +1,4 @@ -/* $OpenBSD: test_helper.h,v 1.6 2015/01/18 19:52:44 djm Exp $ */ +/* $OpenBSD: test_helper.h,v 1.7 2017/03/14 01:10:07 dtucker Exp $ */ /* * Copyright (c) 2011 Damien Miller <djm@mindrot.org> * @@ -67,6 +67,9 @@ void assert_size_t(const char *file, int line, void assert_u_int(const char *file, int line, const char *a1, const char *a2, u_int aa1, u_int aa2, enum test_predicate pred); +void assert_long(const char *file, int line, + const char *a1, const char *a2, + long aa1, long aa2, enum test_predicate pred); void assert_long_long(const char *file, int line, const char *a1, const char *a2, long long aa1, long long aa2, enum test_predicate pred); @@ -110,6 +113,8 @@ void assert_u64(const char *file, int line, assert_size_t(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_EQ) #define ASSERT_U_INT_EQ(a1, a2) \ assert_u_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_EQ) +#define ASSERT_LONG_EQ(a1, a2) \ + assert_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_EQ) #define ASSERT_LONG_LONG_EQ(a1, a2) \ assert_long_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_EQ) #define ASSERT_CHAR_EQ(a1, a2) \ @@ -139,6 +144,8 @@ void assert_u64(const char *file, int line, assert_size_t(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_NE) #define ASSERT_U_INT_NE(a1, a2) \ assert_u_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_NE) +#define ASSERT_LONG_NE(a1, a2) \ + assert_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_NE) #define ASSERT_LONG_LONG_NE(a1, a2) \ assert_long_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_NE) #define ASSERT_CHAR_NE(a1, a2) \ @@ -166,6 +173,8 @@ void assert_u64(const char *file, int line, assert_size_t(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LT) #define ASSERT_U_INT_LT(a1, a2) \ assert_u_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LT) +#define ASSERT_LONG_LT(a1, a2) \ + assert_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LT) #define ASSERT_LONG_LONG_LT(a1, a2) \ assert_long_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LT) #define ASSERT_CHAR_LT(a1, a2) \ @@ -193,6 +202,8 @@ void assert_u64(const char *file, int line, assert_size_t(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LE) #define ASSERT_U_INT_LE(a1, a2) \ assert_u_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LE) +#define ASSERT_LONG_LE(a1, a2) \ + assert_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LE) #define ASSERT_LONG_LONG_LE(a1, a2) \ assert_long_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LE) #define ASSERT_CHAR_LE(a1, a2) \ @@ -220,6 +231,8 @@ void assert_u64(const char *file, int line, assert_size_t(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GT) #define ASSERT_U_INT_GT(a1, a2) \ assert_u_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GT) +#define ASSERT_LONG_GT(a1, a2) \ + assert_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GT) #define ASSERT_LONG_LONG_GT(a1, a2) \ assert_long_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GT) #define ASSERT_CHAR_GT(a1, a2) \ @@ -247,6 +260,8 @@ void assert_u64(const char *file, int line, assert_size_t(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE) #define ASSERT_U_INT_GE(a1, a2) \ assert_u_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE) +#define ASSERT_LONG_GE(a1, a2) \ + assert_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE) #define ASSERT_LONG_LONG_GE(a1, a2) \ assert_long_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE) #define ASSERT_CHAR_GE(a1, a2) \ diff --git a/regress/unittests/utf8/tests.c b/regress/unittests/utf8/tests.c index 733fe60..f0bbca5 100644 --- a/regress/unittests/utf8/tests.c +++ b/regress/unittests/utf8/tests.c @@ -56,11 +56,6 @@ tests(void) { char *loc; -#ifdef WINDOWS - TEST_START("not applicable to Windows yet"); - TEST_DONE(); - return; -#endif TEST_START("utf8_setlocale"); loc = setlocale(LC_CTYPE, "en_US.UTF-8"); ASSERT_PTR_NE(loc, NULL); diff --git a/sandbox-seccomp-filter.c b/sandbox-seccomp-filter.c index 2e1ed2c..2831e9d 100644 --- a/sandbox-seccomp-filter.c +++ b/sandbox-seccomp-filter.c @@ -50,6 +50,9 @@ #include <elf.h> #include <asm/unistd.h> +#ifdef __s390__ +#include <asm/zcrypt.h> +#endif #include <errno.h> #include <signal.h> @@ -73,19 +76,35 @@ # define SECCOMP_FILTER_FAIL SECCOMP_RET_TRAP #endif /* SANDBOX_SECCOMP_FILTER_DEBUG */ +#if __BYTE_ORDER == __LITTLE_ENDIAN +# define ARG_LO_OFFSET 0 +# define ARG_HI_OFFSET sizeof(uint32_t) +#elif __BYTE_ORDER == __BIG_ENDIAN +# define ARG_LO_OFFSET sizeof(uint32_t) +# define ARG_HI_OFFSET 0 +#else +#error "Unknown endianness" +#endif + /* Simple helpers to avoid manual errors (but larger BPF programs). */ #define SC_DENY(_nr, _errno) \ - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_ ## _nr, 0, 1), \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (_nr), 0, 1), \ BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ERRNO|(_errno)) #define SC_ALLOW(_nr) \ - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_ ## _nr, 0, 1), \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (_nr), 0, 1), \ BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) #define SC_ALLOW_ARG(_nr, _arg_nr, _arg_val) \ - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_ ## _nr, 0, 4), \ - /* load first syscall argument */ \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (_nr), 0, 6), \ + /* load and test first syscall argument, low word */ \ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \ - offsetof(struct seccomp_data, args[(_arg_nr)])), \ - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (_arg_val), 0, 1), \ + offsetof(struct seccomp_data, args[(_arg_nr)]) + ARG_LO_OFFSET), \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, \ + ((_arg_val) & 0xFFFFFFFF), 0, 3), \ + /* load and test first syscall argument, high word */ \ + BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \ + offsetof(struct seccomp_data, args[(_arg_nr)]) + ARG_HI_OFFSET), \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, \ + (((uint32_t)((uint64_t)(_arg_val) >> 32)) & 0xFFFFFFFF), 0, 1), \ BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), \ /* reload syscall number; all rules expect it in accumulator */ \ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \ @@ -104,108 +123,122 @@ static const struct sock_filter preauth_insns[] = { /* Syscalls to non-fatally deny */ #ifdef __NR_lstat - SC_DENY(lstat, EACCES), + SC_DENY(__NR_lstat, EACCES), #endif #ifdef __NR_lstat64 - SC_DENY(lstat64, EACCES), + SC_DENY(__NR_lstat64, EACCES), #endif #ifdef __NR_fstat - SC_DENY(fstat, EACCES), + SC_DENY(__NR_fstat, EACCES), #endif #ifdef __NR_fstat64 - SC_DENY(fstat64, EACCES), + SC_DENY(__NR_fstat64, EACCES), #endif #ifdef __NR_open - SC_DENY(open, EACCES), + SC_DENY(__NR_open, EACCES), #endif #ifdef __NR_openat - SC_DENY(openat, EACCES), + SC_DENY(__NR_openat, EACCES), #endif #ifdef __NR_newfstatat - SC_DENY(newfstatat, EACCES), + SC_DENY(__NR_newfstatat, EACCES), #endif #ifdef __NR_stat - SC_DENY(stat, EACCES), + SC_DENY(__NR_stat, EACCES), #endif #ifdef __NR_stat64 - SC_DENY(stat64, EACCES), + SC_DENY(__NR_stat64, EACCES), #endif /* Syscalls to permit */ #ifdef __NR_brk - SC_ALLOW(brk), + SC_ALLOW(__NR_brk), #endif #ifdef __NR_clock_gettime - SC_ALLOW(clock_gettime), + SC_ALLOW(__NR_clock_gettime), #endif #ifdef __NR_close - SC_ALLOW(close), + SC_ALLOW(__NR_close), #endif #ifdef __NR_exit - SC_ALLOW(exit), + SC_ALLOW(__NR_exit), #endif #ifdef __NR_exit_group - SC_ALLOW(exit_group), + SC_ALLOW(__NR_exit_group), #endif #ifdef __NR_getpgid - SC_ALLOW(getpgid), + SC_ALLOW(__NR_getpgid), #endif #ifdef __NR_getpid - SC_ALLOW(getpid), + SC_ALLOW(__NR_getpid), #endif #ifdef __NR_getrandom - SC_ALLOW(getrandom), + SC_ALLOW(__NR_getrandom), #endif #ifdef __NR_gettimeofday - SC_ALLOW(gettimeofday), + SC_ALLOW(__NR_gettimeofday), #endif #ifdef __NR_madvise - SC_ALLOW(madvise), + SC_ALLOW(__NR_madvise), #endif #ifdef __NR_mmap - SC_ALLOW(mmap), + SC_ALLOW(__NR_mmap), #endif #ifdef __NR_mmap2 - SC_ALLOW(mmap2), + SC_ALLOW(__NR_mmap2), #endif #ifdef __NR_mremap - SC_ALLOW(mremap), + SC_ALLOW(__NR_mremap), #endif #ifdef __NR_munmap - SC_ALLOW(munmap), + SC_ALLOW(__NR_munmap), #endif #ifdef __NR__newselect - SC_ALLOW(_newselect), + SC_ALLOW(__NR__newselect), #endif #ifdef __NR_poll - SC_ALLOW(poll), + SC_ALLOW(__NR_poll), #endif #ifdef __NR_pselect6 - SC_ALLOW(pselect6), + SC_ALLOW(__NR_pselect6), #endif #ifdef __NR_read - SC_ALLOW(read), + SC_ALLOW(__NR_read), #endif #ifdef __NR_rt_sigprocmask - SC_ALLOW(rt_sigprocmask), + SC_ALLOW(__NR_rt_sigprocmask), #endif #ifdef __NR_select - SC_ALLOW(select), + SC_ALLOW(__NR_select), #endif #ifdef __NR_shutdown - SC_ALLOW(shutdown), + SC_ALLOW(__NR_shutdown), #endif #ifdef __NR_sigprocmask - SC_ALLOW(sigprocmask), + SC_ALLOW(__NR_sigprocmask), #endif #ifdef __NR_time - SC_ALLOW(time), + SC_ALLOW(__NR_time), #endif #ifdef __NR_write - SC_ALLOW(write), + SC_ALLOW(__NR_write), #endif #ifdef __NR_socketcall - SC_ALLOW_ARG(socketcall, 0, SYS_SHUTDOWN), + SC_ALLOW_ARG(__NR_socketcall, 0, SYS_SHUTDOWN), +#endif +#if defined(__NR_ioctl) && defined(__s390__) + /* Allow ioctls for ICA crypto card on s390 */ + SC_ALLOW_ARG(__NR_ioctl, 1, Z90STAT_STATUS_MASK), + SC_ALLOW_ARG(__NR_ioctl, 1, ICARSAMODEXPO), + SC_ALLOW_ARG(__NR_ioctl, 1, ICARSACRT), +#endif +#if defined(__x86_64__) && defined(__ILP32__) && defined(__X32_SYSCALL_BIT) + /* + * On Linux x32, the clock_gettime VDSO falls back to the + * x86-64 syscall under some circumstances, e.g. + * https://bugs.debian.org/849923 + */ + SC_ALLOW(__NR_clock_gettime & ~__X32_SYSCALL_BIT), #endif /* Default deny */ diff --git a/scp.c b/scp.c index f6b9bc2..96d22cb 100644 --- a/scp.c +++ b/scp.c @@ -292,29 +292,11 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout) addargs(&args, "%s", host); addargs(&args, "%s", cmd); - { - char* full_cmd; - size_t cmdlen = 0; - char** list = args.list; + fcntl(pout[0], F_SETFD, FD_CLOEXEC); + fcntl(pin[1], F_SETFD, FD_CLOEXEC); - cmdlen = 1; /* null term */ - while (*list) - cmdlen += strlen(*list++) + 1; + do_cmd_pid = spawn_child(args.list[0], args.list + 1, pin[0], pout[1], STDERR_FILENO, 0); - full_cmd = xmalloc(cmdlen); - full_cmd[0] = '\0'; - list = args.list; - while (*list) { - strcat(full_cmd, *list++); - strcat(full_cmd, " "); - } - - fcntl(pout[0], F_SETFD, FD_CLOEXEC); - fcntl(pin[1], F_SETFD, FD_CLOEXEC); - - do_cmd_pid = spawn_child(full_cmd, pin[0], pout[1], STDERR_FILENO, 0); - free(full_cmd); - } #else /* !WINDOWS */ do_cmd_pid = fork(); #endif /* !WINDOWS */ @@ -382,26 +364,8 @@ do_cmd2(char *host, char *remuser, char *cmd, int fdin, int fdout) addargs(&args, "%s", host); addargs(&args, "%s", cmd); - { - char* full_cmd; - size_t cmdlen = 0; - char** list = args.list; - - cmdlen = 1; /* null term */ - while (*list) - cmdlen += strlen(*list++) + 1; - - full_cmd = xmalloc(cmdlen); - full_cmd[0] = '\0'; - list = args.list; - while (*list) { - strcat(full_cmd, *list++); - strcat(full_cmd, " "); - } - - pid = spawn_child(full_cmd, fdin, fdout, STDERR_FILENO, 0); - free(full_cmd); - } + pid = spawn_child(args.list[0], args.list + 1, fdin, fdout, STDERR_FILENO, 0); + #else /* !WINDOWS */ pid = fork(); #endif /* !WINDOWS */ @@ -1512,4 +1476,3 @@ lostconn(int signo) else exit(1); } - diff --git a/servconf.c b/servconf.c index f9910e9..243a960 100644 --- a/servconf.c +++ b/servconf.c @@ -1,5 +1,5 @@ -/* $OpenBSD: servconf.c,v 1.305 2017/03/10 04:11:00 dtucker Exp $ */ +/* $OpenBSD: servconf.c,v 1.306 2017/03/14 07:19:07 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * All rights reserved @@ -535,7 +535,7 @@ static struct { { "clientalivecountmax", sClientAliveCountMax, SSHCFG_ALL }, { "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_ALL }, { "authorizedkeysfile2", sDeprecated, SSHCFG_ALL }, - { "useprivilegeseparation", sUsePrivilegeSeparation, SSHCFG_GLOBAL}, + { "useprivilegeseparation", sDeprecated, SSHCFG_GLOBAL}, { "acceptenv", sAcceptEnv, SSHCFG_ALL }, { "permittunnel", sPermitTunnel, SSHCFG_ALL }, { "permittty", sPermitTTY, SSHCFG_ALL }, @@ -1379,11 +1379,6 @@ process_server_config_line(ServerOptions *options, char *line, intptr = &options->disable_forwarding; goto parse_flag; - case sUsePrivilegeSeparation: - intptr = &use_privsep; - multistate_ptr = multistate_privsep; - goto parse_multistate; - case sAllowUsers: while ((arg = strdelim(&cp)) && *arg != '\0') { if (options->num_allow_users >= MAX_ALLOW_USERS) @@ -2112,8 +2107,6 @@ fmt_intarg(ServerOpCodes code, int val) return fmt_multistate_int(val, multistate_gatewayports); case sCompression: return fmt_multistate_int(val, multistate_compression); - case sUsePrivilegeSeparation: - return fmt_multistate_int(val, multistate_privsep); case sAllowTcpForwarding: return fmt_multistate_int(val, multistate_tcpfwd); case sAllowStreamLocalForwarding: @@ -2289,7 +2282,6 @@ dump_config(ServerOptions *o) dump_cfg_fmtint(sDisableForwarding, o->disable_forwarding); dump_cfg_fmtint(sAllowStreamLocalForwarding, o->allow_streamlocal_forwarding); dump_cfg_fmtint(sStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink); - dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep); dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash); /* string arguments */ diff --git a/session.c b/session.c index 97426ec..523acf4 100644 --- a/session.c +++ b/session.c @@ -183,7 +183,7 @@ static int auth_input_request_forwarding(struct passwd * pw) { #ifdef WINDOWS - packet_send_debug("Agent forwarding not supported yet in Windows"); + packet_send_debug("Agent forwarding not supported in Windows yet"); return 0; #else /* !WINDOWS */ Channel *nc; @@ -2377,9 +2377,9 @@ static int session_env_req(Session *s) { char *name, *val; - u_int name_chars, val_len, i; + u_int name_len, val_len, i; - name = packet_get_cstring(&name_chars); + name = packet_get_cstring(&name_len); val = packet_get_cstring(&val_len); packet_check_eom(); diff --git a/sftp-client.c b/sftp-client.c index d47be0e..a6e8322 100644 --- a/sftp-client.c +++ b/sftp-client.c @@ -67,6 +67,13 @@ extern int showprogress; /* Maximum depth to descend in directory trees */ #define MAX_DIR_DEPTH 64 +/* Directory separator characters */ +#ifdef HAVE_CYGWIN +# define SFTP_DIRECTORY_CHARS "/\\" +#else /* HAVE_CYGWIN */ +# define SFTP_DIRECTORY_CHARS "/" +#endif /* HAVE_CYGWIN */ + struct sftp_conn { int fd_in; int fd_out; @@ -619,7 +626,7 @@ do_lsreaddir(struct sftp_conn *conn, const char *path, int print_flag, * These can be used to attack recursive ops * (e.g. send '../../../../etc/passwd') */ - if (strchr(filename, '/') != NULL) { + if (strpbrk(filename, SFTP_DIRECTORY_CHARS) != NULL) { error("Server sent suspect path \"%s\" " "during readdir of \"%s\"", filename, path); } else if (dir) { diff --git a/sftp.c b/sftp.c index 5baaa48..5260ddc 100644 --- a/sftp.c +++ b/sftp.c @@ -2163,12 +2163,11 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2) free(dir); } - interactive = !batchmode && isatty(STDIN_FILENO); - err = 0; - setvbuf(stdout, NULL, _IOLBF, 0); setvbuf(infile, NULL, _IOLBF, 0); + interactive = !batchmode && isatty(STDIN_FILENO); + err = 0; for (;;) { char *cp; @@ -2256,32 +2255,11 @@ connect_to_server(char *path, char **args, int *in, int *out) #ifdef WINDOWS /* fork replacement on Windows */ - { - size_t cmdlen = 0; - int i = 0; - char* full_cmd; - - cmdlen = strlen(path) + 1; - for (i = 1; args[i]; i++) - cmdlen += strlen(args[i]) + 1 + 2; - - full_cmd = xmalloc(cmdlen); - full_cmd[0] = '\0'; - strcat(full_cmd, path); - for (i = 1; args[i]; i++) { - strcat(full_cmd, " \""); - strcat(full_cmd, args[i]); - strcat(full_cmd, "\""); - } - - /* 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); - } + /* disable inheritance on local pipe ends*/ + fcntl(pout[1], F_SETFD, FD_CLOEXEC); + fcntl(pin[0], F_SETFD, FD_CLOEXEC); + sshpid = spawn_child(path, args + 1, c_in, c_out, STDERR_FILENO, 0); if (sshpid == -1) #else /* !WINDOWS */ if ((sshpid = fork()) == -1) diff --git a/ssh-add.c b/ssh-add.c index a4b5918..fb9a53e 100644 --- a/ssh-add.c +++ b/ssh-add.c @@ -492,12 +492,7 @@ main(int argc, char **argv) OpenSSL_add_all_algorithms(); #endif -#ifdef WINDOWS - /* Min buffer size allowed in Windows is 2*/ - setvbuf(stdout, NULL, _IOLBF, 2); -#else setvbuf(stdout, NULL, _IOLBF, 0); -#endif /* First, get a connection to the authentication agent. */ switch (r = ssh_get_authentication_socket(&agent_fd)) { diff --git a/ssh-agent.c b/ssh-agent.c index 1320cda..b987562 100644 --- a/ssh-agent.c +++ b/ssh-agent.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-agent.c,v 1.216 2017/01/04 02:21:43 djm Exp $ */ +/* $OpenBSD: ssh-agent.c,v 1.218 2017/03/15 03:52:30 deraadt Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -821,7 +821,7 @@ send: static void process_remove_smartcard_key(SocketEntry *e) { - char *provider = NULL, *pin = NULL; + char *provider = NULL, *pin = NULL, canonical_provider[PATH_MAX]; int r, version, success = 0; Identity *id, *nxt; Idtab *tab; @@ -831,6 +831,13 @@ process_remove_smartcard_key(SocketEntry *e) fatal("%s: buffer error: %s", __func__, ssh_err(r)); free(pin); + if (realpath(provider, canonical_provider) == NULL) { + verbose("failed PKCS#11 add of \"%.100s\": realpath: %s", + provider, strerror(errno)); + goto send; + } + + debug("%s: remove %.100s", __func__, canonical_provider); for (version = 1; version < 3; version++) { tab = idtab_lookup(version); for (id = TAILQ_FIRST(&tab->idlist); id; id = nxt) { @@ -838,18 +845,19 @@ process_remove_smartcard_key(SocketEntry *e) /* Skip file--based keys */ if (id->provider == NULL) continue; - if (!strcmp(provider, id->provider)) { + if (!strcmp(canonical_provider, id->provider)) { TAILQ_REMOVE(&tab->idlist, id, next); free_identity(id); tab->nentries--; } } } - if (pkcs11_del_provider(provider) == 0) + if (pkcs11_del_provider(canonical_provider) == 0) success = 1; else error("process_remove_smartcard_key:" " pkcs11_del_provider failed"); +send: free(provider); send_status(e, success); } diff --git a/sshconnect2.c b/sshconnect2.c index a671ffa..28e5a02 100644 --- a/sshconnect2.c +++ b/sshconnect2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshconnect2.c,v 1.254 2017/02/03 02:56:00 dtucker Exp $ */ +/* $OpenBSD: sshconnect2.c,v 1.255 2017/03/11 23:40:26 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2008 Damien Miller. All rights reserved. @@ -1001,11 +1001,11 @@ input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt) } static const char * -identity_sign_encode(struct identity *id) +key_sign_encode(const struct sshkey *key) { struct ssh *ssh = active_state; - if (id->key->type == KEY_RSA) { + if (key->type == KEY_RSA) { switch (ssh->kex->rsa_sha2) { case 256: return "rsa-sha2-256"; @@ -1013,7 +1013,7 @@ identity_sign_encode(struct identity *id) return "rsa-sha2-512"; } } - return key_ssh_name(id->key); + return key_ssh_name(key); } static int @@ -1022,30 +1022,49 @@ identity_sign(struct identity *id, u_char **sigp, size_t *lenp, { Key *prv; int ret; - const char *alg; - - alg = identity_sign_encode(id); /* the agent supports this key */ - if (id->agent_fd != -1) + if (id->key != NULL && id->agent_fd != -1) return ssh_agent_sign(id->agent_fd, id->key, sigp, lenp, - data, datalen, alg, compat); + data, datalen, key_sign_encode(id->key), compat); /* * we have already loaded the private key or * the private key is stored in external hardware */ - if (id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT)) - return (sshkey_sign(id->key, sigp, lenp, data, datalen, alg, - compat)); + if (id->key != NULL && + (id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT))) + return (sshkey_sign(id->key, sigp, lenp, data, datalen, + key_sign_encode(id->key), compat)); + /* load the private key from the file */ if ((prv = load_identity_file(id)) == NULL) return SSH_ERR_KEY_NOT_FOUND; - ret = sshkey_sign(prv, sigp, lenp, data, datalen, alg, compat); + ret = sshkey_sign(prv, sigp, lenp, data, datalen, + key_sign_encode(prv), compat); sshkey_free(prv); return (ret); } +static int +id_filename_matches(Identity *id, Identity *private_id) +{ + const char *suffixes[] = { ".pub", "-cert.pub", NULL }; + size_t len = strlen(id->filename), plen = strlen(private_id->filename); + size_t i, slen; + + if (strcmp(id->filename, private_id->filename) == 0) + return 1; + for (i = 0; suffixes[i]; i++) { + slen = strlen(suffixes[i]); + if (len > slen && plen == len - slen && + strcmp(id->filename + (len - slen), suffixes[i]) == 0 && + memcmp(id->filename, private_id->filename, plen) == 0) + return 1; + } + return 0; +} + static int sign_and_send_pubkey(Authctxt *authctxt, Identity *id) { @@ -1088,7 +1107,7 @@ sign_and_send_pubkey(Authctxt *authctxt, Identity *id) } else { buffer_put_cstring(&b, authctxt->method->name); buffer_put_char(&b, have_sig); - buffer_put_cstring(&b, identity_sign_encode(id)); + buffer_put_cstring(&b, key_sign_encode(id->key)); } buffer_put_string(&b, blob, bloblen); @@ -1108,6 +1127,24 @@ sign_and_send_pubkey(Authctxt *authctxt, Identity *id) break; } } + /* + * Exact key matches are preferred, but also allow + * filename matches for non-PKCS#11/agent keys that + * didn't load public keys. This supports the case + * of keeping just a private key file and public + * certificate on disk. + */ + if (!matched && !id->isprivate && id->agent_fd == -1 && + (id->key->flags & SSHKEY_FLAG_EXT) == 0) { + TAILQ_FOREACH(private_id, &authctxt->keys, next) { + if (private_id->key == NULL && + id_filename_matches(id, private_id)) { + id = private_id; + matched = 1; + break; + } + } + } if (matched) { debug2("%s: using private key \"%s\"%s for " "certificate", __func__, id->filename, @@ -1186,7 +1223,7 @@ send_pubkey_test(Authctxt *authctxt, Identity *id) packet_put_cstring(authctxt->method->name); packet_put_char(have_sig); if (!(datafellows & SSH_BUG_PKAUTH)) - packet_put_cstring(identity_sign_encode(id)); + packet_put_cstring(key_sign_encode(id->key)); packet_put_string(blob, bloblen); free(blob); packet_send(); diff --git a/sshd.c b/sshd.c index 226c4e4..8f80bb5 100644 --- a/sshd.c +++ b/sshd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd.c,v 1.483 2017/02/24 03:16:34 djm Exp $ */ +/* $OpenBSD: sshd.c,v 1.485 2017/03/15 03:52:30 deraadt Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -1317,7 +1317,7 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s) continue; } - pid = spawn_child(path_utf8, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO, CREATE_NEW_PROCESS_GROUP); + pid = spawn_child(path_utf8, NULL, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO, CREATE_NEW_PROCESS_GROUP); free(path_utf8); close(*newsock); } @@ -1747,14 +1747,23 @@ main(int ac, char **av) error("Could not connect to agent \"%s\": %s", options.host_key_agent, ssh_err(r)); } -#ifdef WINDOWS /* Windows version always needs and has agent running */ +#ifdef WINDOWS /* Windows version always needs and has agent running */ have_agent = 1; -#endif +#endif for (i = 0; i < options.num_host_key_files; i++) { if (options.host_key_files[i] == NULL) continue; key = key_load_private(options.host_key_files[i], "", NULL); pubkey = key_load_public(options.host_key_files[i], NULL); + + if ((pubkey != NULL && pubkey->type == KEY_RSA1) || + (key != NULL && key->type == KEY_RSA1)) { + verbose("Ignoring RSA1 key %s", + options.host_key_files[i]); + key_free(key); + key_free(pubkey); + continue; + } if (pubkey == NULL && key != NULL) pubkey = key_demote(key); sensitive_data.host_keys[i] = key; diff --git a/sshd_config b/sshd_config index 9f09e4a..4eb2e02 100644 --- a/sshd_config +++ b/sshd_config @@ -1,4 +1,4 @@ -# $OpenBSD: sshd_config,v 1.100 2016/08/15 12:32:04 naddy Exp $ +# $OpenBSD: sshd_config,v 1.101 2017/03/14 07:19:07 djm Exp $ # This is the sshd server system-wide configuration file. See # sshd_config(5) for more information. @@ -93,7 +93,6 @@ AuthorizedKeysFile .ssh/authorized_keys #PrintLastLog yes #TCPKeepAlive yes #UseLogin no -#UsePrivilegeSeparation sandbox #PermitUserEnvironment no #Compression delayed #ClientAliveInterval 0 diff --git a/sshd_config.5 b/sshd_config.5 index 454e46e..ac6ccc7 100644 --- a/sshd_config.5 +++ b/sshd_config.5 @@ -33,8 +33,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd_config.5,v 1.242 2017/02/03 23:01:19 djm Exp $ -.Dd $Mdocdate: February 3 2017 $ +.\" $OpenBSD: sshd_config.5,v 1.243 2017/03/14 07:19:07 djm Exp $ +.Dd $Mdocdate: March 14 2017 $ .Dt SSHD_CONFIG 5 .Os .Sh NAME @@ -1494,28 +1494,6 @@ is enabled, you will not be able to run as a non-root user. The default is .Cm no . -.It Cm UsePrivilegeSeparation -Specifies whether -.Xr sshd 8 -separates privileges by creating an unprivileged child process -to deal with incoming network traffic. -After successful authentication, another process will be created that has -the privilege of the authenticated user. -The goal of privilege separation is to prevent privilege -escalation by containing any corruption within the unprivileged processes. -The argument must be -.Cm yes , -.Cm no , -or -.Cm sandbox . -If -.Cm UsePrivilegeSeparation -is set to -.Cm sandbox -then the pre-authentication unprivileged process is subject to additional -restrictions. -The default is -.Cm sandbox . .It Cm VersionAddendum Optionally specifies additional text to append to the SSH protocol banner sent by the server upon connection. diff --git a/sshpty.c b/sshpty.c index 150223c..fe2fb5a 100644 --- a/sshpty.c +++ b/sshpty.c @@ -53,57 +53,6 @@ # endif #endif -#ifdef WINDOWS -/* - * Windows versions of pty_*. Some of them are NO-OPs and should go - * away when pty logic is refactored and abstracted out - * - */ -int -pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, size_t namebuflen) -{ - /* - * Simple console screen implementation in Win32 to give a - * Unix like pty for interactive sessions - */ - *ttyfd = 0; - *ptyfd = 0; - strlcpy(namebuf, "console", namebuflen); - return 1; -} - -void -pty_release(const char *tty) { - /* NO-OP */ -} - -void -pty_make_controlling_tty(int *ttyfd, const char *tty) { - /* NO-OP */ -} - -void -pty_change_window_size(int ptyfd, u_int row, u_int col, - u_int xpixel, u_int ypixel) { - COORD coord; - coord.X = col; - coord.Y = 9999; - SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coord); -} - - -void -pty_setowner(struct passwd *pw, const char *tty) { - /* NO-OP */ -} - -void -disconnect_controlling_tty(void) { - /* NO-OP */ -} - -#else - /* * Allocates and opens a pty. Returns 0 if no pty could be allocated, or * nonzero if a pty was successfully allocated. On success, open file @@ -303,4 +252,3 @@ disconnect_controlling_tty(void) } #endif /* TIOCNOTTY */ } -#endif diff --git a/sshtty.c b/sshtty.c index 5825c85..d214ce3 100644 --- a/sshtty.c +++ b/sshtty.c @@ -47,37 +47,6 @@ static struct termios _saved_tio; static int _in_raw_mode = 0; -#ifdef WINDOWS -/* - * TTY raw mode routines for Windows - */ - -int ConEnterRawMode(DWORD OutputHandle, BOOL fSmartInit); -int ConExitRawMode(void); - -struct termios term_settings; - -/* - * TODO - clean this up for Windows, ConInit should return previous terminal - * settings that need to be stored in term_settings - */ - -struct termios * - get_saved_tio(void) { - memset(&term_settings, 0, sizeof(term_settings)); - return &term_settings; -} - -void -leave_raw_mode(int quiet) { - ConExitRawMode(); -} - -void -enter_raw_mode(int quiet) { - ConEnterRawMode(STD_OUTPUT_HANDLE, TRUE); -} -#else /* !WINDOWS */ struct termios * get_saved_tio(void) { @@ -125,4 +94,3 @@ enter_raw_mode(int quiet) } else _in_raw_mode = 1; } -#endif /* !WINDOWS */ \ No newline at end of file diff --git a/utf8.c b/utf8.c index 6fb05bb..dead79b 100644 --- a/utf8.c +++ b/utf8.c @@ -61,7 +61,7 @@ dangerous_locale(void) { loc = nl_langinfo(CODESET); return strcmp(loc, "US-ASCII") != 0 && strcmp(loc, "UTF-8") != 0 && - strcmp(loc, "ANSI_X3.4-1968") != 0; + strcmp(loc, "ANSI_X3.4-1968") != 0 && strcmp(loc, "646") != 0; } static int @@ -332,4 +332,3 @@ msetlocale(void) /* We can handle this locale */ setlocale(LC_CTYPE, ""); } - diff --git a/version.h b/version.h index 269ebcd..c86e209 100644 --- a/version.h +++ b/version.h @@ -1,6 +1,6 @@ -/* $OpenBSD: version.h,v 1.78 2016/12/19 04:55:51 djm Exp $ */ +/* $OpenBSD: version.h,v 1.79 2017/03/20 01:18:59 djm Exp $ */ -#define SSH_VERSION "OpenSSH_7.4" +#define SSH_VERSION "OpenSSH_7.5" #define SSH_PORTABLE "p1" #define SSH_RELEASE SSH_VERSION SSH_PORTABLE