Fix tilde expand for Windows paths with backslashes (#768)

* add backslash support for Windows paths

* add pester tests for tilde_expand

* fix typo
This commit is contained in:
Tess Gauthier 2025-01-06 14:11:58 -05:00 committed by GitHub
parent 0c3137f621
commit cdcc8d34d8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 47 additions and 26 deletions

9
misc.c
View File

@ -1261,6 +1261,15 @@ tilde_expand(const char *filename, uid_t uid, char **retp)
path = NULL; /* ~/ */ path = NULL; /* ~/ */
else else
path = copy; /* ~/path */ path = copy; /* ~/path */
#ifdef WINDOWS
// also need to account for backward slashes on Windows
} else if (*copy == '\\') {
copy += strspn(copy, "\\");
if (*copy == '\0')
path = NULL; /* ~\ */
else
path = copy; /* ~\path */
#endif /* WINDOWS */
} else { } else {
user = copy; user = copy;
if ((path = strchr(copy, '/')) != NULL) { if ((path = strchr(copy, '/')) != NULL) {

View File

@ -5,9 +5,9 @@ Import-Module $PSScriptRoot\CommonUtils.psm1 -Force
$tC = 1 $tC = 1
$tI = 0 $tI = 0
$suite = "sshclient" $suite = "sshclient"
Describe "E2E scenarios for ssh client" -Tags "CI" { Describe "E2E scenarios for ssh client" -Tags "CI" {
BeforeAll { BeforeAll {
if($OpenSSHTestInfo -eq $null) if($OpenSSHTestInfo -eq $null)
{ {
Throw "`$OpenSSHTestInfo is null. Please run Set-OpenSSHTestEnvironment to set test environments." Throw "`$OpenSSHTestInfo is null. Please run Set-OpenSSHTestEnvironment to set test environments."
@ -27,12 +27,12 @@ Describe "E2E scenarios for ssh client" -Tags "CI" {
$accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($ssouser, $rights, "ContainerInherit,Objectinherit", "None", "Allow") $accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($ssouser, $rights, "ContainerInherit,Objectinherit", "None", "Allow")
$acl.SetAccessRule($accessRule) $acl.SetAccessRule($accessRule)
Set-Acl -Path $testDir -AclObject $acl Set-Acl -Path $testDir -AclObject $acl
#skip on ps 2 becase non-interactive cmd require a ENTER before it returns on ps2 #skip on ps 2 because non-interactive cmd require a ENTER before it returns on ps2
$skip = $IsWindows -and ($PSVersionTable.PSVersion.Major -le 2) $skip = $IsWindows -and ($PSVersionTable.PSVersion.Major -le 2)
<#$testData = @( <#$testData = @(
@{ @{
Title = 'Simple logon no option'; Title = 'Simple logon no option';
LogonStr = "$($server.localAdminUserName)@$($server.MachineName)" LogonStr = "$($server.localAdminUserName)@$($server.MachineName)"
Options = "" Options = ""
}, },
@ -42,7 +42,7 @@ Describe "E2E scenarios for ssh client" -Tags "CI" {
Options = "-C -l $($server.localAdminUserName)" Options = "-C -l $($server.localAdminUserName)"
} }
) )
$testData1 = @( $testData1 = @(
@{ @{
Title = "logon using -i -q option" Title = "logon using -i -q option"
@ -84,7 +84,7 @@ Describe "E2E scenarios for ssh client" -Tags "CI" {
[string] $default_shell_path, [string] $default_shell_path,
[string] $default_shell_cmd_option_val = $null [string] $default_shell_cmd_option_val = $null
) )
if (!(Test-Path $dfltShellRegPath)) { if (!(Test-Path $dfltShellRegPath)) {
New-Item -Path $dfltShellRegPath -Force | Out-Null New-Item -Path $dfltShellRegPath -Force | Out-Null
} }
@ -99,12 +99,12 @@ Describe "E2E scenarios for ssh client" -Tags "CI" {
$stderrFile=Join-Path $testDir "$tC.$tI.stderr.txt" $stderrFile=Join-Path $testDir "$tC.$tI.stderr.txt"
$stdoutFile=Join-Path $testDir "$tC.$tI.stdout.txt" $stdoutFile=Join-Path $testDir "$tC.$tI.stdout.txt"
$logFile = Join-Path $testDir "$tC.$tI.log.txt" $logFile = Join-Path $testDir "$tC.$tI.log.txt"
} }
AfterEach {$tI++;} AfterEach {$tI++;}
Context "$tC - Basic Scenarios" { Context "$tC - Basic Scenarios" {
BeforeAll {$tI=1} BeforeAll {$tI=1}
AfterAll{$tC++} AfterAll{$tC++}
@ -117,13 +117,13 @@ Describe "E2E scenarios for ssh client" -Tags "CI" {
iex "cmd /c `"ssh -? 2> $stderrFile`"" iex "cmd /c `"ssh -? 2> $stderrFile`""
$stderrFile | Should Contain "usage: ssh" $stderrFile | Should Contain "usage: ssh"
} }
It "$tC.$tI - remote echo command" { It "$tC.$tI - remote echo command" {
iex "$sshDefaultCmd echo 1234" | Should Be "1234" iex "$sshDefaultCmd echo 1234" | Should Be "1234"
} }
} }
Context "$tC - exit code (exit-status.sh)" { Context "$tC - exit code (exit-status.sh)" {
BeforeAll {$tI=1} BeforeAll {$tI=1}
AfterAll{$tC++} AfterAll{$tC++}
@ -132,12 +132,12 @@ Describe "E2E scenarios for ssh client" -Tags "CI" {
foreach ($i in (0,1,4,5,44)) { foreach ($i in (0,1,4,5,44)) {
ssh -p $port $ssouser@$server exit $i ssh -p $port $ssouser@$server exit $i
$LASTEXITCODE | Should Be $i $LASTEXITCODE | Should Be $i
} }
} }
} }
Context "$tC - Redirection Scenarios" { Context "$tC - Redirection Scenarios" {
BeforeAll {$tI=1} BeforeAll {$tI=1}
AfterAll{$tC++} AfterAll{$tC++}
@ -192,7 +192,7 @@ Describe "E2E scenarios for ssh client" -Tags "CI" {
} }
} }
Context "$tC - configure powershell default shell Scenarios" { Context "$tC - configure powershell default shell Scenarios" {
BeforeAll { BeforeAll {
$tI=1 $tI=1
@ -205,13 +205,13 @@ Describe "E2E scenarios for ssh client" -Tags "CI" {
$tC++ $tC++
Remove-ItemProperty -Path $dfltShellRegPath -Name $dfltShellRegKeyName -ErrorAction SilentlyContinue Remove-ItemProperty -Path $dfltShellRegPath -Name $dfltShellRegKeyName -ErrorAction SilentlyContinue
Remove-ItemProperty -Path $dfltShellRegPath -Name $dfltShellCmdOptionRegKeyName -ErrorAction SilentlyContinue Remove-ItemProperty -Path $dfltShellRegPath -Name $dfltShellCmdOptionRegKeyName -ErrorAction SilentlyContinue
} }
It "$tC.$tI - basic powershell" -skip:$skip { It "$tC.$tI - basic powershell" -skip:$skip {
$o = ssh test_target Write-Output 1234 $o = ssh test_target Write-Output 1234
$o | Should Be "1234" $o | Should Be "1234"
} }
It "$tC.$tI - basic in powershell cmdlet" -skip:$skip { It "$tC.$tI - basic in powershell cmdlet" -skip:$skip {
$o = ssh test_target "cd `$env:ProgramFiles;pwd" $o = ssh test_target "cd `$env:ProgramFiles;pwd"
$LASTEXITCODE | Should Be 0 $LASTEXITCODE | Should Be 0
@ -240,7 +240,7 @@ Describe "E2E scenarios for ssh client" -Tags "CI" {
It "$tC.$tI - single quotes in powershell cmdlet" -skip:$skip { It "$tC.$tI - single quotes in powershell cmdlet" -skip:$skip {
# actual command line ssh target echo '$env:computername' # actual command line ssh target echo '$env:computername'
$o = ssh test_target "echo '`$env:computername'" $o = ssh test_target "echo '`$env:computername'"
$LASTEXITCODE | Should Be 0 $LASTEXITCODE | Should Be 0
$o | Should Be `$env:computername $o | Should Be `$env:computername
} }
} }
@ -257,9 +257,9 @@ Describe "E2E scenarios for ssh client" -Tags "CI" {
Remove-ItemProperty -Path $dfltShellRegPath -Name $dfltShellRegKeyName -ErrorAction SilentlyContinue Remove-ItemProperty -Path $dfltShellRegPath -Name $dfltShellRegKeyName -ErrorAction SilentlyContinue
Remove-ItemProperty -Path $dfltShellRegPath -Name $dfltShellCmdOptionRegKeyName -ErrorAction SilentlyContinue Remove-ItemProperty -Path $dfltShellRegPath -Name $dfltShellCmdOptionRegKeyName -ErrorAction SilentlyContinue
} }
It "$tC.$tI - default shell as cmd" -skip:$skip { It "$tC.$tI - default shell as cmd" -skip:$skip {
$o = ssh test_target where cmd $o = ssh test_target where cmd
$o | Should Contain "cmd" $o | Should Contain "cmd"
} }
It "$tC.$tI - cmd as default shell and double quotes in cmdline" { It "$tC.$tI - cmd as default shell and double quotes in cmdline" {
# actual command line ssh target echo "hello" # actual command line ssh target echo "hello"
@ -269,7 +269,7 @@ Describe "E2E scenarios for ssh client" -Tags "CI" {
It "$tC.$tI - single quotes in powershell cmdlet" -skip:$skip { It "$tC.$tI - single quotes in powershell cmdlet" -skip:$skip {
# actual command line ssh target echo '$env:computername' # actual command line ssh target echo '$env:computername'
$o = ssh test_target "echo 'hello'" $o = ssh test_target "echo 'hello'"
$LASTEXITCODE | Should Be 0 $LASTEXITCODE | Should Be 0
$o | Should Be "'hello'" $o | Should Be "'hello'"
} }
} }
@ -290,15 +290,15 @@ Describe "E2E scenarios for ssh client" -Tags "CI" {
$o | Should Be "`"hello`"" $o | Should Be "`"hello`""
} }
} }
Context "$tC - cmdline parameters" { Context "$tC - cmdline parameters" {
BeforeAll {$tI=1} BeforeAll {$tI=1}
AfterAll{$tC++} AfterAll{$tC++}
It "$tC.$tI - verbose to file (-v -E)" { It "$tC.$tI - verbose to file (-v -E)" {
$o = ssh -v -E $logFile test_target echo 1234 $o = ssh -v -E $logFile test_target echo 1234
$o | Should Be "1234" $o | Should Be "1234"
#TODO - checks below are very inefficient (time taking). #TODO - checks below are very inefficient (time taking).
$logFile | Should Contain "OpenSSH_" $logFile | Should Contain "OpenSSH_"
$logFile | Should Contain "Exit Status 0" $logFile | Should Contain "Exit Status 0"
} }
@ -333,11 +333,11 @@ Describe "E2E scenarios for ssh client" -Tags "CI" {
" Port $port" | Add-Content $goodConfigFile " Port $port" | Add-Content $goodConfigFile
" User $ssouser" | Add-Content $goodConfigFile " User $ssouser" | Add-Content $goodConfigFile
$o = ssh -F $goodConfigFile myhost echo 1234 $o = ssh -F $goodConfigFile myhost echo 1234
$o | Should Be "1234" $o | Should Be "1234"
} }
It "$tC.$tI - IP options - (-4) (-6)" { It "$tC.$tI - IP options - (-4) (-6)" {
# TODO - this test assumes target is localhost. # TODO - this test assumes target is localhost.
# make it work independent of target # make it work independent of target
#-4 #-4
$o = ssh -4 -v -E $logFile test_target echo 1234 $o = ssh -4 -v -E $logFile test_target echo 1234
@ -346,11 +346,23 @@ Describe "E2E scenarios for ssh client" -Tags "CI" {
#-4 #-4
$o = ssh -6 -v -E $logFile test_target echo 1234 $o = ssh -6 -v -E $logFile test_target echo 1234
$o | Should Be "1234" $o | Should Be "1234"
$logFile | Should Contain "[::1]" $logFile | Should Contain "[::1]"
}
It "$tC.$tI - tilde expand for path with forward slash" {
$o = ssh -v -i ~/test/key/path -E $logFile test_target echo 1234
$o | Should Be "1234"
$logFile | Should Not Contain "tilde_expand: No such user"
}
It "$tC.$tI - tilde expand for path with backslash" {
$o = ssh -v -i ~\test\key\path -E $logFile test_target echo 1234
$o | Should Be "1234"
$logFile | Should Not Contain "tilde_expand: No such user"
} }
It "$tC.$tI - auto populate known hosts" { It "$tC.$tI - auto populate known hosts" {
$kh = Join-Path $testDir "$tC.$tI.known_hosts" $kh = Join-Path $testDir "$tC.$tI.known_hosts"
$nul | Set-Content $kh $nul | Set-Content $kh
# doing via cmd to intercept and drain stderr output # doing via cmd to intercept and drain stderr output