diff --git a/appveyor.yml b/appveyor.yml
index d18cc0a..c713ebf 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,40 +1,39 @@
-version: 0.0.16.0.{build}
+version: 0.0.17.0.{build}
image: Visual Studio 2015
branches:
only:
- latestw_all
- - latestw_all_openssl
init:
- ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
build_script:
- ps: |
- Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppveyorHelper.psm1 -DisableNameChecking
+ Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppveyorHelper.psm1
Invoke-AppVeyorBuild
after_build:
- ps: |
- Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppveyorHelper.psm1 -DisableNameChecking
+ Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppveyorHelper.psm1
Install-OpenSSH
before_test:
- ps: |
- Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppveyorHelper.psm1 -DisableNameChecking
- Setup-OpenSSHTestEnvironment -Quiet
+ Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppveyorHelper.psm1
+ Set-OpenSSHTestEnvironment -Confirm:$false
test_script:
- ps: |
- Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppveyorHelper.psm1 -DisableNameChecking
- Run-OpenSSHTests
+ Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppveyorHelper.psm1
+ Invoke-OpenSSHTests
after_test:
- ps: |
- Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppveyorHelper.psm1 -DisableNameChecking
- Upload-OpenSSHTestResults
+ Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppveyorHelper.psm1
+ Publish-OpenSSHTestResults
on_finish:
- ps: |
- Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppveyorHelper.psm1 -DisableNameChecking
+ Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppveyorHelper.psm1
Publish-Artifact
\ No newline at end of file
diff --git a/auth-passwd.c b/auth-passwd.c
index cfb829c..8804dc4 100644
--- a/auth-passwd.c
+++ b/auth-passwd.c
@@ -226,38 +226,45 @@ sys_auth_passwd(Authctxt *authctxt, const char *password)
#elif defined(WINDOWS)
/*
-* Authenticate on Windows - Pass credentials to ssh-agent and retrieve token
-* upon successful authentication
-* TODO - password is sent in plain text over IPC. Consider implications.
+* Authenticate on Windows - Call LogonUser and retrieve user token
*/
int sys_auth_passwd(Authctxt *authctxt, const char *password)
{
- struct sshbuf *msg = NULL;
- size_t blen = 0;
- DWORD token = 0;
- extern int auth_sock;
+ wchar_t *user_utf16 = NULL, *udom_utf16 = NULL, *pwd_utf16 = NULL, *tmp;
+ HANDLE token = NULL;
int r = 0;
- int ssh_request_reply(int, struct sshbuf *, struct sshbuf *);
- msg = sshbuf_new();
- if (!msg)
- fatal("%s: out of memory", __func__);
-
- if (sshbuf_put_u8(msg, SSH_AGENT_AUTHENTICATE) != 0 ||
- sshbuf_put_cstring(msg, PASSWD_AUTH_REQUEST) != 0 ||
- sshbuf_put_cstring(msg, authctxt->pw->pw_name) != 0 ||
- sshbuf_put_cstring(msg, password) != 0 ||
- ssh_request_reply(auth_sock, msg, msg) != 0 ||
- sshbuf_get_u32(msg, &token) != 0) {
- debug("auth agent did not authorize client %s", authctxt->user);
- r = 0;
+ if ((user_utf16 = utf8_to_utf16(authctxt->pw->pw_name)) == NULL ||
+ (pwd_utf16 = utf8_to_utf16(password)) == NULL) {
+ fatal("out of memory");
goto done;
}
- authctxt->methoddata = (void*)(INT_PTR)token;
+
+ if ((tmp = wcschr(user_utf16, L'@')) != NULL) {
+ udom_utf16 = tmp + 1;
+ *tmp = L'\0';
+ }
+
+ if (LogonUserW(user_utf16, udom_utf16, pwd_utf16, LOGON32_LOGON_NETWORK_CLEARTEXT,
+ LOGON32_PROVIDER_DEFAULT, &token) == FALSE) {
+ if (GetLastError() == ERROR_PASSWORD_MUST_CHANGE)
+ /*
+ * TODO - need to add support to force password change
+ * by sending back SSH_MSG_USERAUTH_PASSWD_CHANGEREQ
+ */
+ error("password for user %s has expired", authctxt->pw->pw_name);
+ else
+ debug("failed to logon user: %ls domain: %ls error:%d", user_utf16, udom_utf16, GetLastError());
+ goto done;
+ }
+
+ authctxt->auth_token = (void*)(INT_PTR)token;
r = 1;
done:
- if (msg)
- sshbuf_free(msg);
+ if (user_utf16)
+ free(user_utf16);
+ if (pwd_utf16)
+ SecureZeroMemory(pwd_utf16, sizeof(wchar_t) * wcslen(pwd_utf16));
return r;
}
#endif /* WINDOWS */
diff --git a/auth.c b/auth.c
index 9084958..2f18cf8 100644
--- a/auth.c
+++ b/auth.c
@@ -405,6 +405,13 @@ expand_authorized_keys(const char *filename, struct passwd *pw)
file = percent_expand(filename, "h", pw->pw_dir,
"u", pw->pw_name, (char *)NULL);
+#ifdef WINDOWS
+ /* Return if the path is absolute. If not, prepend the '%h\\' */
+ if ((strlen(file) > 1) && (file[1] == ':'))
+ return (file);
+
+ i = snprintf(ret, sizeof(ret), "%s\\%s", pw->pw_dir, file);
+#else
/*
* Ensure that filename starts anchored. If not, be backward
* compatible and prepend the '%h/'
@@ -413,6 +420,8 @@ expand_authorized_keys(const char *filename, struct passwd *pw)
return (file);
i = snprintf(ret, sizeof(ret), "%s/%s", pw->pw_dir, file);
+#endif // WINDOWS
+
if (i < 0 || (size_t)i >= sizeof(ret))
fatal("expand_authorized_keys: path too long");
free(file);
diff --git a/auth.h b/auth.h
index 6779354..a5cd750 100644
--- a/auth.h
+++ b/auth.h
@@ -78,7 +78,9 @@ struct Authctxt {
#endif
Buffer *loginmsg;
void *methoddata;
-
+#ifdef WINDOWS
+ void *auth_token;
+#endif
struct sshkey **prev_userkeys;
u_int nprev_userkeys;
};
diff --git a/auth2-pubkey.c b/auth2-pubkey.c
index 084cbf0..db44036 100644
--- a/auth2-pubkey.c
+++ b/auth2-pubkey.c
@@ -200,54 +200,14 @@ userauth_pubkey(struct ssh *ssh)
/* test for correct signature */
authenticated = 0;
-#ifdef WINDOWS
- /* Pass key challenge material to ssh-agent to retrieve token upon successful authentication */
- {
- struct sshbuf *msg = NULL;
- u_char *blob = NULL;
- size_t blen = 0;
- DWORD token = 0;
- extern int auth_sock;
- int r = 0;
- int ssh_request_reply(int , struct sshbuf *, struct sshbuf *);
-
- while (1) {
- msg = sshbuf_new();
- if (!msg)
- fatal("%s: out of memory", __func__);
- if ((r = sshbuf_put_u8(msg, SSH_AGENT_AUTHENTICATE)) != 0 ||
- (r = sshbuf_put_cstring(msg, PUBKEY_AUTH_REQUEST)) != 0 ||
- (r = sshkey_to_blob(key, &blob, &blen)) != 0 ||
- (r = sshbuf_put_string(msg, blob, blen)) != 0 ||
- (r = sshbuf_put_cstring(msg, authctxt->pw->pw_name)) != 0 ||
- (r = sshbuf_put_string(msg, sig, slen)) != 0 ||
- (r = sshbuf_put_string(msg, sshbuf_ptr(b), sshbuf_len(b))) != 0 ||
- (r = ssh_request_reply(auth_sock, msg, msg)) != 0 ||
- (r = sshbuf_get_u32(msg, &token)) != 0) {
- debug("auth agent did not authorize client %s", authctxt->user);
- break;
- }
-
- debug3("auth agent authenticated %s", authctxt->user);
- break;
-
- }
- if (blob)
- free(blob);
- if (msg)
- sshbuf_free(msg);
-
- if (token) {
- authenticated = 1;
- authctxt->methoddata = (void*)(INT_PTR)token;
- }
-
- }
-
-#else /* !WINDOWS */
if (PRIVSEP(user_key_allowed(authctxt->pw, key, 1)) &&
+#ifdef WINDOWS
+ (authctxt->auth_token = mm_auth_pubkey(authctxt->pw->pw_name,
+ key, sig, slen, b)) != NULL) {
+#else
PRIVSEP(sshkey_verify(key, sig, slen, sshbuf_ptr(b),
sshbuf_len(b), ssh->compat)) == 0) {
+#endif
authenticated = 1;
/* Record the successful key to prevent reuse */
auth2_record_userkey(authctxt, key);
@@ -255,7 +215,6 @@ userauth_pubkey(struct ssh *ssh)
}
sshbuf_free(b);
free(sig);
-#endif /* !WINDOWS */
} else {
debug("%s: test whether pkalg/pkblob are acceptable for %s %s",
diff --git a/authfd.h b/authfd.h
index a9874e1..5804f18 100644
--- a/authfd.h
+++ b/authfd.h
@@ -43,6 +43,7 @@ int ssh_agent_sign(int sock, struct sshkey *key,
const u_char *data, size_t datalen, const char *alg, u_int compat);
/* Messages for the authentication agent connection. */
+/* Message Id 0 is reserved */
#define SSH_AGENTC_REQUEST_RSA_IDENTITIES 1
#define SSH_AGENT_RSA_IDENTITIES_ANSWER 2
#define SSH_AGENTC_RSA_CHALLENGE 3
@@ -88,12 +89,4 @@ int ssh_agent_sign(int sock, struct sshkey *key,
#define SSH_AGENT_RSA_SHA2_256 0x02
#define SSH_AGENT_RSA_SHA2_512 0x04
-/*
-* Following are used in Windows implementation
-* ssh-agent in Windows also serves user authentication
-*/
-#define SSH_AGENT_AUTHENTICATE 200
-#define PUBKEY_AUTH_REQUEST "pubkey"
-#define PASSWD_AUTH_REQUEST "password"
-
#endif /* AUTHFD_H */
diff --git a/contrib/win32/openssh/AppveyorHelper.psm1 b/contrib/win32/openssh/AppveyorHelper.psm1
index 7a851a2..b20fbd0 100644
--- a/contrib/win32/openssh/AppveyorHelper.psm1
+++ b/contrib/win32/openssh/AppveyorHelper.psm1
@@ -1,12 +1,14 @@
$ErrorActionPreference = 'Stop'
-Import-Module $PSScriptRoot\OpenSSHCommonUtils.psm1 -Force -DisableNameChecking
-Import-Module $PSScriptRoot\OpenSSHBuildHelper.psm1 -Force -DisableNameChecking
-Import-Module $PSScriptRoot\OpenSSHTestHelper.psm1 -Force -DisableNameChecking
+Set-StrictMode -Version 2.0
+If ($PSVersiontable.PSVersion.Major -le 2) {$PSScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path}
+Import-Module $PSScriptRoot\OpenSSHCommonUtils.psm1 -Force
+Import-Module $PSScriptRoot\OpenSSHBuildHelper.psm1 -Force
+Import-Module $PSScriptRoot\OpenSSHTestHelper.psm1 -Force
$repoRoot = Get-RepositoryRoot
$script:messageFile = join-path $repoRoot.FullName "BuildMessage.log"
-# Sets a build variable
+# Write the build message
Function Write-BuildMessage
{
param(
@@ -77,12 +79,11 @@ function Invoke-AppVeyorFull
{
$env:APPVEYOR_SCHEDULED_BUILD = 'True'
}
- try {
- Set-OpenSSHTestParams
+ try {
Invoke-AppVeyorBuild
Install-OpenSSH
- Setup-OpenSSHTestEnvironment
- Run-OpenSSHTests
+ Set-OpenSSHTestEnvironment -confirm:$false
+ Invoke-OpenSSHTests
Publish-Artifact
}
finally {
@@ -97,8 +98,8 @@ function Invoke-AppVeyorFull
function Invoke-AppVeyorBuild
{
Set-BuildVariable TestPassed True
- Build-OpenSSH -Configuration Release -NativeHostArch x64
- Build-OpenSSH -Configuration Debug -NativeHostArch x86
+ Start-OpenSSHBuild -Configuration Release -NativeHostArch x64
+ Start-OpenSSHBuild -Configuration Release -NativeHostArch x86
Write-BuildMessage -Message "OpenSSH binaries build success!" -Category Information
}
@@ -136,6 +137,100 @@ function Add-BuildLog
}
}
+<#
+ .Synopsis
+ Deploy all required files to a location and install the binaries
+#>
+function Install-OpenSSH
+{
+ [CmdletBinding()]
+ param
+ (
+ [ValidateSet('Debug', 'Release')]
+ [string]$Configuration = "Release",
+
+ [ValidateSet('x86', 'x64', '')]
+ [string]$NativeHostArch = "",
+
+ [string]$OpenSSHDir = "$env:SystemDrive\OpenSSH"
+ )
+
+ if ($NativeHostArch -eq "")
+ {
+ $NativeHostArch = 'x64'
+ if ($env:PROCESSOR_ARCHITECTURE -eq 'x86') {
+ $NativeHostArch = 'x86'
+ }
+ }
+
+ Start-OpenSSHPackage -NativeHostArch $NativeHostArch -Configuration $Configuration -DestinationPath $OpenSSHDir
+
+ Push-Location $OpenSSHDir
+ & "$OpenSSHDir\install-sshd.ps1"
+ & "$OpenSSHDir\ssh-keygen.exe" -A
+ & "$OpenSSHDir\FixHostFilePermissions.ps1" -Confirm:$false
+
+ #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
+
+ Pop-Location
+ Write-BuildMessage -Message "OpenSSH installed!" -Category Information
+}
+
+<#
+ .Synopsis
+ uninstalled sshd
+#>
+function UnInstall-OpenSSH
+{
+ [CmdletBinding()]
+ param
+ (
+ [string]$OpenSSHDir = "$env:SystemDrive\OpenSSH"
+ )
+
+ if (-not (Test-Path $OpenSSHDir -PathType Container))
+ {
+ return
+ }
+
+ Push-Location $OpenSSHDir
+ if((Get-Service ssh-agent -ErrorAction SilentlyContinue) -ne $null) {
+ Stop-Service ssh-agent -Force
+ }
+ & "$OpenSSHDir\uninstall-sshd.ps1"
+
+ $machinePath = [Environment]::GetEnvironmentVariable('Path', 'MACHINE')
+ $newMachineEnvironmentPath = $machinePath
+ if ($machinePath.ToLower().Contains($OpenSSHDir.ToLower()))
+ {
+ $newMachineEnvironmentPath = $newMachineEnvironmentPath.Replace("$OpenSSHDir;", '')
+ $env:Path = $env:Path.Replace("$OpenSSHDir;", '')
+ }
+
+ if ($newMachineEnvironmentPath -ne $machinePath)
+ {
+ [Environment]::SetEnvironmentVariable('Path', $newMachineEnvironmentPath, 'MACHINE')
+ }
+
+ Pop-Location
+ Remove-Item -Path $OpenSSHDir -Recurse -Force -ErrorAction SilentlyContinue
+}
+
<#
.Synopsis
Publishes package build artifacts.
@@ -170,11 +265,11 @@ function Add-Artifact
function Publish-Artifact
{
Write-Host -ForegroundColor Yellow "Publishing project artifacts"
- [System.Collections.ArrayList] $artifacts = [System.Collections.ArrayList]::new()
+ [System.Collections.ArrayList] $artifacts = new-object System.Collections.ArrayList
# Get the build.log file for each build configuration
Add-BuildLog -artifacts $artifacts -buildLog (Get-BuildLogFile -root $repoRoot.FullName -Configuration Release -NativeHostArch x64)
- Add-BuildLog -artifacts $artifacts -buildLog (Get-BuildLogFile -root $repoRoot.FullName -Configuration Debug -NativeHostArch x86)
+ Add-BuildLog -artifacts $artifacts -buildLog (Get-BuildLogFile -root $repoRoot.FullName -Configuration Release -NativeHostArch x86)
if($Global:OpenSSHTestInfo)
{
@@ -186,7 +281,6 @@ function Publish-Artifact
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
}
}
@@ -195,10 +289,10 @@ function Publish-Artifact
.Synopsis
Runs the tests for this repo
#>
-function Run-OpenSSHTests
+function Invoke-OpenSSHTests
{
Write-Host "Start running unit tests"
- $unitTestFailed = Run-OpenSSHUnitTest
+ $unitTestFailed = Invoke-OpenSSHUnitTest
if($unitTestFailed)
{
@@ -212,14 +306,14 @@ function Run-OpenSSHTests
Write-BuildMessage -Message "All Unit tests passed!" -Category Information
}
# Run all E2E tests.
- Run-OpenSSHE2ETest
+ Invoke-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"])
+ $xml = [xml](Get-Content $OpenSSHTestInfo["E2ETestResultsFile"] | out-string)
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"])."
@@ -239,7 +333,7 @@ function Run-OpenSSHTests
.Synopsis
upload OpenSSH pester test results.
#>
-function Upload-OpenSSHTestResults
+function Publish-OpenSSHTestResults
{
if ($env:APPVEYOR_JOB_ID)
{
diff --git a/contrib/win32/openssh/FixHostFilePermissions.ps1 b/contrib/win32/openssh/FixHostFilePermissions.ps1
index e15e16f..fbff664 100644
--- a/contrib/win32/openssh/FixHostFilePermissions.ps1
+++ b/contrib/win32/openssh/FixHostFilePermissions.ps1
@@ -1,7 +1,7 @@
[CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact="High")]
param ()
Set-StrictMode -Version 2.0
-If (!(Test-Path variable:PSScriptRoot)) {$PSScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Definition}
+If ($PSVersiontable.PSVersion.Major -le 2) {$PSScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path}
Import-Module $PSScriptRoot\OpenSSHUtils -Force
#check sshd config file
diff --git a/contrib/win32/openssh/FixUserFilePermissions.ps1 b/contrib/win32/openssh/FixUserFilePermissions.ps1
index 93e6468..b6259b3 100644
--- a/contrib/win32/openssh/FixUserFilePermissions.ps1
+++ b/contrib/win32/openssh/FixUserFilePermissions.ps1
@@ -1,7 +1,7 @@
[CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact="High")]
param ()
Set-StrictMode -Version 2.0
-If (!(Test-Path variable:PSScriptRoot)) {$PSScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Definition}
+If ($PSVersiontable.PSVersion.Major -le 2) {$PSScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path}
Import-Module $PSScriptRoot\OpenSSHUtils -Force
diff --git a/contrib/win32/openssh/OpenSSHBuildHelper.psm1 b/contrib/win32/openssh/OpenSSHBuildHelper.psm1
index dca5521..2d43390 100644
--- a/contrib/win32/openssh/OpenSSHBuildHelper.psm1
+++ b/contrib/win32/openssh/OpenSSHBuildHelper.psm1
@@ -1,7 +1,7 @@
-Set-StrictMode -Version Latest
+Set-StrictMode -Version 2.0
+If ($PSVersiontable.PSVersion.Major -le 2) {$PSScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path}
+Import-Module $PSScriptRoot\OpenSSHCommonUtils.psm1 -Force
-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
@@ -83,7 +83,7 @@ function Write-BuildMsg
[switch] $Silent
)
- if ($AsVerbose)
+ if($PSBoundParameters.ContainsKey("AsVerbose"))
{
if ($script:Verbose)
{
@@ -96,17 +96,24 @@ function Write-BuildMsg
return
}
- if ($AsInfo)
+ if($PSBoundParameters.ContainsKey("AsInfo"))
{
Write-Log -Message "INFO: $message"
if (-not $Silent)
{
- Write-Information -MessageData $message -InformationAction Continue
+ if(Get-Command "Write-Information" -ErrorAction SilentlyContinue )
+ {
+ Write-Information -MessageData $message -InformationAction Continue
+ }
+ else
+ {
+ Write-Verbose -Message $message -Verbose
+ }
}
return
}
- if ($AsWarning)
+ if($PSBoundParameters.ContainsKey("AsWarning"))
{
Write-Log -Message "WARNING: $message"
if (-not $Silent)
@@ -116,7 +123,7 @@ function Write-BuildMsg
return
}
- if ($AsError)
+ if($PSBoundParameters.ContainsKey("AsError"))
{
Write-Log -Message "ERROR: $message"
if (-not $Silent)
@@ -137,8 +144,6 @@ function Write-BuildMsg
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')
@@ -146,7 +151,7 @@ function Start-OpenSSHBootstrap
# Install chocolatey
$chocolateyPath = "$env:AllUsersProfile\chocolatey\bin"
- if(Get-Command "choco" -ErrorAction SilentlyContinue)
+ if(Get-Command choco -ErrorAction SilentlyContinue)
{
Write-BuildMsg -AsVerbose -Message "Chocolatey is already installed. Skipping installation." -Silent:$silent
}
@@ -156,20 +161,38 @@ function Start-OpenSSHBootstrap
Invoke-Expression ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1')) 2>&1 >> $script:BuildLogFile
}
+ if (-not ($machinePath.ToLower().Contains($chocolateyPath.ToLower())))
+ {
+ Write-BuildMsg -AsVerbose -Message "Adding $chocolateyPath to Path environment variable" -Silent:$silent
+ $newMachineEnvironmentPath = "$chocolateyPath;$newMachineEnvironmentPath"
+ if(-not ($env:Path.ToLower().Contains($chocolateyPath.ToLower())))
+ {
+ $env:Path = "$chocolateyPath;$env:Path"
+ }
+ }
+ else
+ {
+ Write-BuildMsg -AsVerbose -Message "$chocolateyPath already present in Path environment variable" -Silent:$silent
+ }
+
# 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"
+ if(-not ($env:Path.ToLower().Contains($gitCmdPath.ToLower())))
+ {
+ $env:Path = "$gitCmdPath;$env:Path"
+ }
}
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 = "${env:ProgramFiles(x86)}\MSBuild\14.0\bin"
+ if($env:PROCESSOR_ARCHITECTURE -ieq "AMD64")
{
$nativeMSBuildPath += "\amd64"
}
@@ -178,12 +201,15 @@ function Start-OpenSSHBootstrap
{
Write-BuildMsg -AsVerbose -Message "Adding $nativeMSBuildPath to Path environment variable" -Silent:$silent
$newMachineEnvironmentPath += ";$nativeMSBuildPath"
- $env:Path += ";$nativeMSBuildPath"
+ if(-not ($env:Path.ToLower().Contains($nativeMSBuildPath.ToLower())))
+ {
+ $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)
@@ -191,42 +217,53 @@ function Start-OpenSSHBootstrap
[Environment]::SetEnvironmentVariable('Path', $newMachineEnvironmentPath, 'MACHINE')
}
- # 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)
+ $VCTargetsPath = "${env:ProgramFiles(x86)}\MSBuild\Microsoft.Cpp\v4.0\V140"
+ if([Environment]::GetEnvironmentVariable('VCTargetsPath', 'MACHINE') -eq $null)
{
- 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
+ [Environment]::SetEnvironmentVariable('VCTargetsPath', $VCTargetsPath, 'MACHINE')
}
- else
+ if ($env:VCTargetsPath -eq $null)
{
- Write-BuildMsg -AsVerbose -Message "$packageName present. Skipping installation." -Silent:$silent
+ $env:VCTargetsPath = $VCTargetsPath
}
- # Install Windows 8.1 SDK
- $packageName = "windows-sdk-8.1"
+ $vcVars = "${env:ProgramFiles(x86)}\Microsoft Visual Studio 14.0\Common7\Tools\vsvars32.bat"
$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
+ $packageName = "vcbuildtools"
+ If ((-not (Test-Path $nativeMSBuildPath)) -or (-not (Test-Path $VcVars)) -or (-not (Test-Path $sdkPath))) {
+ Write-BuildMsg -AsInfo -Message "$packageName not present. Installing $packageName ..."
+ choco install $packageName -ia "/InstallSelectableItems VisualCppBuildTools_ATLMFC_SDK;VisualCppBuildTools_NETFX_SDK;Win81SDK_CppBuildSKUV1" -y --force --limitoutput --execution-timeout 10000 2>&1 >> $script:BuildLogFile
+ $errorCode = $LASTEXITCODE
+ if ($errorCode -eq 3010)
+ {
+ Write-Host "The recent package changes indicate a reboot is necessary. please reboot the machine, open a new powershell window and call Start-SSHBuild or Start-OpenSSHBootstrap again." -ForegroundColor Black -BackgroundColor Yellow
+ Do {
+ $input = Read-Host -Prompt "Reboot the machine? [Yes] Y; [No] N (default is `"Y`")"
+ if([string]::IsNullOrEmpty($input))
+ {
+ $input = 'Y'
+ }
+ } until ($input -match "^(y(es)?|N(o)?)$")
+ [string]$ret = $Matches[0]
+ if ($ret.ToLower().Startswith('y'))
+ {
+ Write-BuildMsg -AsWarning -Message "restarting machine ..."
+ Restart-Computer -Force
+ exit
+ }
+ else
+ {
+ Write-BuildMsg -AsError -ErrorAction Stop -Message "User choose not to restart the machine to apply the changes."
+ }
+ }
+ else
+ {
+ Write-BuildMsg -AsError -ErrorAction Stop -Message "$packageName installation failed with error code $errorCode"
+ }
}
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
+ Write-BuildMsg -AsVerbose -Message 'VC++ 2015 Build Tools already present.'
}
# Ensure the VS C toolset is installed
@@ -241,11 +278,11 @@ function Start-OpenSSHBootstrap
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."
+ 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
+function Get-Win32OpenSSHRepo
{
[bool] $silent = -not $script:Verbose
@@ -264,7 +301,7 @@ function Clone-Win32OpenSSH
Pop-Location
}
-function Delete-Win32OpenSSH
+function Remove-Win32OpenSSHRepo
{
Remove-Item -Path $script:win32OpenSSHPath -Recurse -Force -ErrorAction SilentlyContinue
}
@@ -282,7 +319,7 @@ function Copy-LibreSSLSDK
}
}
-function Package-OpenSSH
+function Start-OpenSSHPackage
{
[CmdletBinding(SupportsShouldProcess=$false)]
param
@@ -290,7 +327,7 @@ function Package-OpenSSH
[ValidateSet('x86', 'x64')]
[string]$NativeHostArch = "x64",
- [ValidateSet('Debug', 'Release', '')]
+ [ValidateSet('Debug', 'Release')]
[string]$Configuration = "Release",
# Copy payload to DestinationPath instead of packaging
@@ -315,7 +352,7 @@ function Package-OpenSSH
if ($NativeHostArch -ieq 'x86') {
$packageName = "OpenSSH-Win32"
}
- while((($service = Get-Service ssh-agent -ErrorAction Ignore) -ne $null) -and ($service.Status -ine 'Stopped'))
+ while((($service = Get-Service ssh-agent -ErrorAction SilentlyContinue) -ne $null) -and ($service.Status -ine 'Stopped'))
{
Stop-Service ssh-agent -Force
#sleep to wait the servicelog file write
@@ -361,11 +398,17 @@ function Package-OpenSSH
}
else {
Remove-Item ($packageDir + '.zip') -Force -ErrorAction SilentlyContinue
- Compress-Archive -Path $packageDir -DestinationPath ($packageDir + '.zip')
- Write-BuildMsg -AsInfo -Message "Packaged Payload - '$packageDir'.zip"
+ if(get-command Compress-Archive -ErrorAction SilentlyContinue)
+ {
+ Compress-Archive -Path $packageDir -DestinationPath ($packageDir + '.zip')
+ Write-BuildMsg -AsInfo -Message "Packaged Payload - '$packageDir.zip'"
+ }
+ else
+ {
+ Write-BuildMsg -AsInfo -Message "Packaged Payload not compressed."
+ }
}
Remove-Item $packageDir -Recurse -Force -ErrorAction SilentlyContinue
-
if ($DestinationPath -ne "") {
Copy-Item -Path $symbolsDir\* -Destination $DestinationPath -Force -Recurse
@@ -373,13 +416,20 @@ function Package-OpenSSH
}
else {
Remove-Item ($symbolsDir + '.zip') -Force -ErrorAction SilentlyContinue
- Compress-Archive -Path $symbolsDir -DestinationPath ($symbolsDir + '.zip')
- Write-BuildMsg -AsInfo -Message "Packaged Symbols - '$symbolsDir'.zip"
+ if(get-command Compress-Archive -ErrorAction SilentlyContinue)
+ {
+ Compress-Archive -Path $symbolsDir -DestinationPath ($symbolsDir + '.zip')
+ Write-BuildMsg -AsInfo -Message "Packaged Symbols - '$symbolsDir.zip'"
+ }
+ else
+ {
+ Write-BuildMsg -AsInfo -Message "Packaged Symbols not compressed."
+ }
}
Remove-Item $symbolsDir -Recurse -Force -ErrorAction SilentlyContinue
}
-function Build-OpenSSH
+function Start-OpenSSHBuild
{
[CmdletBinding(SupportsShouldProcess=$false)]
param
@@ -387,12 +437,11 @@ function Build-OpenSSH
[ValidateSet('x86', 'x64')]
[string]$NativeHostArch = "x64",
- [ValidateSet('Debug', 'Release', '')]
+ [ValidateSet('Debug', 'Release')]
[string]$Configuration = "Release",
[switch]$NoOpenSSL
- )
- Set-StrictMode -Version Latest
+ )
$script:BuildLogFile = $null
[System.IO.DirectoryInfo] $repositoryRoot = Get-RepositoryRoot
@@ -420,9 +469,9 @@ function Build-OpenSSH
$script:win32OpenSSHPath = join-path $script:gitRoot "Win32-OpenSSH"
if (-not (Test-Path (Join-Path $PSScriptRoot LibreSSLSDK)))
{
- Clone-Win32OpenSSH
+ Get-Win32OpenSSHRepo
Copy-LibreSSLSDK
- Delete-Win32OpenSSH
+ Remove-Win32OpenSSHRepo
}
if ($NoOpenSSL)
@@ -465,7 +514,7 @@ function Get-BuildLogFile
[ValidateSet('x86', 'x64')]
[string]$NativeHostArch = "x64",
- [ValidateSet('Debug', 'Release', '')]
+ [ValidateSet('Debug', 'Release')]
[string]$Configuration = "Release"
)
@@ -483,122 +532,6 @@ function Get-SolutionFile
return Join-Path -Path $root -ChildPath "contrib\win32\openssh\Win32-OpenSSH.sln"
}
-<#
- .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"
- )
-
- if ($Configuration -eq "")
- {
- $Configuration = 'Release'
- }
-
- if ($NativeHostArch -eq "")
- {
- $NativeHostArch = 'x64'
- if ($env:PROCESSOR_ARCHITECTURE -eq 'x86') {
- $NativeHostArch = 'x86'
- }
- }
-
- Package-OpenSSH -NativeHostArch $NativeHostArch -Configuration $Configuration -DestinationPath $OpenSSHDir
-
- Push-Location $OpenSSHDir
- & "$OpenSSHDir\install-sshd.ps1"
- & "$OpenSSHDir\ssh-keygen.exe" -A
-
- $keyFiles = Get-ChildItem "$OpenSSHDir\ssh_host_*_key*" | % {
- Adjust-HostKeyFileACL -FilePath $_.FullName
- }
-
- #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
-
- Pop-Location
- Write-Log -Message "OpenSSH installed!"
-}
-
-<#
- .Synopsis
- uninstalled sshd and sshla
-#>
-function UnInstall-OpenSSH
-{
- [CmdletBinding()]
- param
- (
- [string]$OpenSSHDir = "$env:SystemDrive\OpenSSH"
- )
-
- if (-not (Test-Path $OpenSSHDir))
- {
- return
- }
-
- Push-Location $OpenSSHDir
- if((Get-Service ssh-agent -ErrorAction Ignore) -ne $null) {
- Stop-Service ssh-agent -Force
- }
- &( "$OpenSSHDir\uninstall-sshd.ps1")
-
- $machinePath = [Environment]::GetEnvironmentVariable('Path', 'MACHINE')
- $newMachineEnvironmentPath = $machinePath
- if ($machinePath.ToLower().Contains($OpenSSHDir.ToLower()))
- {
- $newMachineEnvironmentPath = $newMachineEnvironmentPath.Replace("$OpenSSHDir;", '')
- $env:Path = $env:Path.Replace("$OpenSSHDir;", '')
- }
-
- if(Test-Path -Path $OpenSSHDir)
- {
- Push-Location $OpenSSHDir
- &( "$OpenSSHDir\uninstall-sshd.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
-
- Remove-Item -Path $OpenSSHDir -Recurse -Force -ErrorAction SilentlyContinue
- }
-}
-
-Export-ModuleMember -Function Build-OpenSSH, Get-BuildLogFile, Install-OpenSSH, UnInstall-OpenSSH, Package-OpenSSH
+Export-ModuleMember -Function Start-OpenSSHBuild, Get-BuildLogFile, Start-OpenSSHPackage
diff --git a/contrib/win32/openssh/OpenSSHCommonUtils.psm1 b/contrib/win32/openssh/OpenSSHCommonUtils.psm1
index d2d4f3f..3a58971 100644
--- a/contrib/win32/openssh/OpenSSHCommonUtils.psm1
+++ b/contrib/win32/openssh/OpenSSHCommonUtils.psm1
@@ -1,20 +1,18 @@
-<#
+If ($PSVersiontable.PSVersion.Major -le 2) {$PSScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path}
+Import-Module $PSScriptRoot\OpenSSHUtils -Force
+<#
.Synopsis
Finds the root of the git repository
.Outputs
- A System.IO.DirectoryInfo for the location of the root.
+ A System.IO.DirectoryInfo for the location of the root if root is found; otherwise, script 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
-
+{
+ $start = $currentDir = (Get-Item -Path $PSScriptRoot)
while ($null -ne $currentDir.Parent)
{
$path = Join-Path -Path $currentDir.FullName -ChildPath '.git'
@@ -24,147 +22,7 @@ function Get-RepositoryRoot
}
$currentDir = $currentDir.Parent
}
-
- throw new-object System.IO.DirectoryNotFoundException("Could not find the root of the GIT repository")
-}
-
-<#
-.Synopsis
- Set owner of the file to by LOCALSYSTEM account
- Set private host key be fully controlled by LOCALSYSTEM and Administrators
- Set public host key be fully controlled by LOCALSYSTEM and Administrators, read access by everyone
-
-.Outputs
- N/A
-
-.Inputs
- FilePath - The path to the file
-#>
-function Adjust-HostKeyFileACL
-{
- param (
- [parameter(Mandatory=$true)]
- [string]$FilePath
- )
-
- $myACL = Get-ACL $FilePath
- $myACL.SetAccessRuleProtection($True, $FALSE)
- Set-Acl -Path $FilePath -AclObject $myACL
-
- $systemAccount = New-Object System.Security.Principal.NTAccount("NT AUTHORITY", "SYSTEM")
- $adminAccount = New-Object System.Security.Principal.NTAccount("BUILTIN","Administrators")
- $everyoneAccount = New-Object System.Security.Principal.NTAccount("EveryOne")
- $myACL = Get-ACL $FilePath
-
- $myACL.SetOwner($systemAccount)
-
- if($myACL.Access)
- {
- $myACL.Access | % {
- if(-not ($myACL.RemoveAccessRule($_)))
- {
- throw "failed to remove access of $($_.IdentityReference.Value) rule in setup "
- }
- }
- }
-
- $adminACE = New-Object System.Security.AccessControl.FileSystemAccessRule `
- ($adminAccount, "FullControl", "None", "None", "Allow")
- $myACL.AddAccessRule($adminACE)
-
- $systemACE = New-Object System.Security.AccessControl.FileSystemAccessRule `
- ($systemAccount, "FullControl", "None", "None", "Allow")
- $myACL.AddAccessRule($systemACE)
-
- if($FilePath.EndsWith(".pub"))
- {
- $everyoneAce = New-Object System.Security.AccessControl.FileSystemAccessRule `
- ("Everyone", "Read", "None", "None", "Allow")
- $myACL.AddAccessRule($everyoneAce)
- }
-
- Set-Acl -Path $FilePath -AclObject $myACL
-}
-
-<#
-.Synopsis
- Set owner of the user key file
- Set ACL to have private user key be fully controlled by LOCALSYSTEM and Administrators, Read, write access by owner
- Set public user key be fully controlled by LOCALSYSTEM and Administrators, Read, write access by owner, read access by everyone
-
-.Outputs
- N/A
-
-.Inputs
- FilePath - The path to the file
- Owner - owner of the file
- OwnerPerms - the permissions grant to the owner
-#>
-function Adjust-UserKeyFileACL
-{
- param (
- [parameter(Mandatory=$true)]
- [string]$FilePath,
- [System.Security.Principal.NTAccount] $Owner = $null,
- [System.Security.AccessControl.FileSystemRights[]] $OwnerPerms = $null
- )
-
- $myACL = Get-ACL $FilePath
- $myACL.SetAccessRuleProtection($True, $FALSE)
- Set-Acl -Path $FilePath -AclObject $myACL
-
- $systemAccount = New-Object System.Security.Principal.NTAccount("NT AUTHORITY", "SYSTEM")
- $adminAccount = New-Object System.Security.Principal.NTAccount("BUILTIN","Administrators")
- $everyoneAccount = New-Object System.Security.Principal.NTAccount("EveryOne")
- $myACL = Get-ACL $FilePath
-
- $actualOwner = $null
- if($Owner -eq $null)
- {
- $actualOwner = New-Object System.Security.Principal.NTAccount($($env:USERDOMAIN), $($env:USERNAME))
- }
- else
- {
- $actualOwner = $Owner
- }
-
- $myACL.SetOwner($actualOwner)
-
- if($myACL.Access)
- {
- $myACL.Access | % {
- if(-not ($myACL.RemoveAccessRule($_)))
- {
- throw "failed to remove access of $($_.IdentityReference.Value) rule in setup "
- }
- }
- }
-
- $adminACE = New-Object System.Security.AccessControl.FileSystemAccessRule `
- ($adminAccount, "FullControl", "None", "None", "Allow")
- $myACL.AddAccessRule($adminACE)
-
- $systemACE = New-Object System.Security.AccessControl.FileSystemAccessRule `
- ($systemAccount, "FullControl", "None", "None", "Allow")
- $myACL.AddAccessRule($systemACE)
-
- if($OwnerPerms)
- {
- $OwnerPerms | % {
- $ownerACE = New-Object System.Security.AccessControl.FileSystemAccessRule `
- ($actualOwner, $_, "None", "None", "Allow")
- $myACL.AddAccessRule($ownerACE)
- }
- }
-
- if($FilePath.EndsWith(".pub"))
- {
- $everyoneAce = New-Object System.Security.AccessControl.FileSystemAccessRule `
- ("Everyone", "Read", "None", "None", "Allow")
- $myACL.AddAccessRule($everyoneAce)
- }
-
- Set-Acl -Path $FilePath -AclObject $myACL
+ return $start
}
<#
@@ -177,9 +35,9 @@ function Adjust-UserKeyFileACL
.Inputs
FilePath - The path to the file
User - account name
- Perm - The permission to grant.
+ Perms - The permission to grant.
#>
-function Add-PermissionToFileACL
+function Add-PermissionToFileACL
{
param (
[parameter(Mandatory=$true)]
@@ -200,8 +58,8 @@ function Add-PermissionToFileACL
$myACL.AddAccessRule($userACE)
}
}
-
+ Enable-Privilege SeRestorePrivilege | out-null
Set-Acl -Path $FilePath -AclObject $myACL
}
-Export-ModuleMember -Function Get-RepositoryRoot, Add-PermissionToFileACL, Adjust-HostKeyFileACL, Adjust-UserKeyFileACL
\ No newline at end of file
+Export-ModuleMember -Function Get-RepositoryRoot, Add-PermissionToFileACL
\ No newline at end of file
diff --git a/contrib/win32/openssh/OpenSSHTestHelper.psm1 b/contrib/win32/openssh/OpenSSHTestHelper.psm1
index 4001203..bd1a341 100644
--- a/contrib/win32/openssh/OpenSSHTestHelper.psm1
+++ b/contrib/win32/openssh/OpenSSHTestHelper.psm1
@@ -1,5 +1,7 @@
$ErrorActionPreference = 'Stop'
-Import-Module $PSScriptRoot\OpenSSHCommonUtils.psm1 -DisableNameChecking -Force
+If ($PSVersiontable.PSVersion.Major -le 2) {$PSScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path}
+Import-Module $PSScriptRoot\OpenSSHCommonUtils.psm1 -Force
+Import-Module $PSScriptRoot\OpenSSHUtils -Force
[System.IO.DirectoryInfo] $repositoryRoot = Get-RepositoryRoot
# test environment parameters initialized with defaults
@@ -17,23 +19,28 @@ $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"
-
+$Script:WindowsInBox = $false
+
<#
.Synopsis
- Setup-OpenSSHTestEnvironment
+ Set-OpenSSHTestEnvironment
TODO - split these steps into client and server side
#>
-function Setup-OpenSSHTestEnvironment
+function Set-OpenSSHTestEnvironment
{
- [CmdletBinding()]
+ [CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact="High")]
param
- (
- [switch] $Quiet,
+ (
[string] $OpenSSHBinPath,
[string] $TestDataPath = "$env:SystemDrive\OpenSSHTests",
[Boolean] $DebugMode = $false
)
+ if($PSBoundParameters.ContainsKey("Verbose"))
+ {
+ $verboseInfo = ($PSBoundParameters['Verbose']).IsPresent
+ }
+
if($Global:OpenSSHTestInfo -ne $null)
{
$Global:OpenSSHTestInfo.Clear()
@@ -65,41 +72,30 @@ function Setup-OpenSSHTestEnvironment
#if user does not set path, pick it up
if([string]::IsNullOrEmpty($OpenSSHBinPath))
{
- $sshcmd = get-command ssh.exe -ErrorAction Ignore
+ $sshcmd = get-command ssh.exe -ErrorAction SilentlyContinue
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") )
+ $description = "Pick up ssh.exe from $dirToCheck."
+ $prompt = "Are you sure you want to pick up ssh.exe from $($dirToCheck)?"
+ $caption = "Found ssh.exe from $dirToCheck"
+ if(-not $pscmdlet.ShouldProcess($description, $prompt, $caption))
{
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"
- }
+ $script:OpenSSHBinPath = $dirToCheck
}
}
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"
+ Throw "Cannot find OpenSSH binaries under $OpenSSHBinPath. Please specify -OpenSSHBinPath to the OpenSSH installed location"
}
else
{
@@ -113,7 +109,15 @@ function Setup-OpenSSHTestEnvironment
$env:Path = "$($script:OpenSSHBinPath);$($env:path)"
}
- $warning = @"
+ $acl = get-acl (join-path $script:OpenSSHBinPath "ssh.exe")
+
+ if($acl.Owner -ieq "NT SERVICE\TrustedInstaller")
+ {
+ $Script:WindowsInBox = $true
+ $Global:OpenSSHTestInfo.Add("WindowsInBox", $true)
+ }
+
+ $description = @"
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
@@ -125,21 +129,15 @@ WARNING: Following changes will be made to OpenSSH configuration
- $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 -ieq "N") -or ($continue -ieq "No") )
- {
- Write-Host "User decided not to make the changes."
- return
- }
- elseif(($continue -ne "") -and ($continue -ine "Y") -and ($continue -ine "Yes"))
- {
- Throw "User entered invalid option ($continue). Exit now."
- }
+ - To cleanup - Run Clear-OpenSSHTestEnvironment
+"@
+
+ $prompt = "Are you sure you want to perform the above operations?"
+ $caption = $description
+ if(-not $pscmdlet.ShouldProcess($description, $prompt, $caption))
+ {
+ Write-Host "User decided not to make the changes."
+ return
}
Install-OpenSSHTestDependencies
@@ -154,9 +152,15 @@ WARNING: Following changes will be made to OpenSSH configuration
if (-not (Test-Path $backupConfigPath -PathType Leaf)) {
Copy-Item (Join-Path $script:OpenSSHBinPath sshd_config) $backupConfigPath -Force
}
-
+ $targetsshdConfig = Join-Path $script:OpenSSHBinPath sshd_config
# copy new sshd_config
- Copy-Item (Join-Path $Script:E2ETestDirectory sshd_config) (Join-Path $script:OpenSSHBinPath sshd_config) -Force
+ if($Script:WindowsInBox -and (Test-Path $targetsshdConfig))
+ {
+ $currentUser = New-Object System.Security.Principal.NTAccount($($env:USERDOMAIN), $($env:USERNAME))
+ Add-PermissionToFileACL -FilePath $targetsshdConfig -User $currentUser -Perm "Read,Write"
+ }
+
+ Copy-Item (Join-Path $Script:E2ETestDirectory sshd_config) $targetsshdConfig -Force
Start-Service ssh-agent
@@ -164,12 +168,18 @@ WARNING: Following changes will be made to OpenSSH configuration
Copy-Item "$($Script:E2ETestDirectory)\sshtest*hostkey*" $script:OpenSSHBinPath -Force
Get-ChildItem "$($script:OpenSSHBinPath)\sshtest*hostkey*"| % {
#workaround for the cariggage new line added by git before copy them
- (Get-Content $_.FullName -Raw).Replace("`r`n","`n") | Set-Content $_.FullName -Force
- Adjust-HostKeyFileACL -FilePath $_.FullName
- if (-not ($_.Name.EndsWith(".pub"))) {
- #register private key with agent
- ssh-add-hostkey.ps1 $_.FullName
- }
+ $filePath = "$($_.FullName)"
+ $con = (Get-Content $filePath | Out-String).Replace("`r`n","`n")
+ Set-Content -Path $filePath -Value "$con"
+ if (-not ($_.Name.EndsWith(".pub")))
+ {
+ Repair-SshdHostKeyPermission -FilePath $_.FullName -confirm:$false
+ if($psversiontable.BuildVersion.Major -gt 6)
+ {
+ #register private key with agent
+ ssh-add-hostkey.ps1 $_.FullName
+ }
+ }
}
Restart-Service sshd -Force
@@ -192,7 +202,7 @@ WARNING: Following changes will be made to OpenSSH configuration
Copy-Item $sshConfigFilePath (Join-Path $dotSshDirectoryPath config.ori) -Force
}
Copy-Item (Join-Path $Script:E2ETestDirectory ssh_config) $sshConfigFilePath -Force
- Adjust-UserKeyFileACL -FilePath $sshConfigFilePath -OwnerPerms "Read,Write"
+ Repair-UserSshConfigPermission -FilePath $sshConfigFilePath -confirm:$false
# create test accounts
#TODO - this is Windows specific. Need to be in PAL
@@ -210,21 +220,22 @@ WARNING: Following changes will be made to OpenSSH configuration
}
}
- #setup single sign on for ssouser
+ #setup single sign on for ssouser
$ssouserProfile = Get-LocalUserProfile -User $SSOUser
$Global:OpenSSHTestInfo.Add("SSOUserProfile", $ssouserProfile)
- $Global:OpenSSHTestInfo.Add("PubKeyUserProfile", (Get-LocalUserProfile -User $PubKeyUser))
+ $Global:OpenSSHTestInfo.Add("PubKeyUserProfile", (Get-LocalUserProfile -User $PubKeyUser))
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
+ $testPubKeyPath = Join-Path $Script:E2ETestDirectory sshtest_userssokey_ed25519.pub
Copy-Item $testPubKeyPath $authorizedKeyPath -Force -ErrorAction SilentlyContinue
- $owner = New-Object System.Security.Principal.NTAccount($SSOUser)
- Adjust-UserKeyFileACL -FilePath $authorizedKeyPath -Owner $owner -OwnerPerms "Read","Write"
- Add-PermissionToFileACL -FilePath $authorizedKeyPath -User "NT Service\sshd" -Perm "Read"
+ Repair-AuthorizedKeyPermission -FilePath $authorizedKeyPath -confirm:$false
+
$testPriKeypath = Join-Path $Script:E2ETestDirectory sshtest_userssokey_ed25519
- (Get-Content $testPriKeypath -Raw).Replace("`r`n","`n") | Set-Content $testPriKeypath -Force
- Adjust-UserKeyFileACL -FilePath $testPriKeypath -OwnerPerms "Read, Write"
+ $con = (Get-Content $testPriKeypath | Out-String).Replace("`r`n","`n")
+ Set-Content -Path $testPriKeypath -Value "$con"
+ cmd /c "ssh-add -D 2>&1 >> $Script:TestSetupLogFile"
+ Repair-UserKeyPermission -FilePath $testPriKeypath -confirm:$false
cmd /c "ssh-add $testPriKeypath 2>&1 >> $Script:TestSetupLogFile"
Backup-OpenSSHTestInfo
}
@@ -256,6 +267,19 @@ function Install-OpenSSHTestDependencies
{
[CmdletBinding()]
param ()
+
+ #$isOpenSSHUtilsAvailable = Get-Module 'OpenSSHUtils' -ListAvailable
+ #if (-not ($isOpenSSHUtilsAvailable))
+ #{
+ Write-Log -Message "Installing Module OpenSSHUtils..."
+ Install-OpenSSHUtilsModule -SourceDir $PSScriptRoot
+ #}
+ Import-Module OpensshUtils -Force
+
+ if($Script:WindowsInBox)
+ {
+ return
+ }
# Install chocolatey
if(-not (Get-Command "choco" -ErrorAction SilentlyContinue))
@@ -267,10 +291,66 @@ function Install-OpenSSHTestDependencies
$isModuleAvailable = Get-Module 'Pester' -ListAvailable
if (-not ($isModuleAvailable))
{
- Write-Log -Message "Installing Pester..."
- choco install Pester -y --force --limitoutput 2>&1 >> $Script:TestSetupLogFile
+ Write-Log -Message "Installing Pester..."
+ choco install Pester -y --force --limitoutput 2>&1 >> $Script:TestSetupLogFile
}
}
+
+function Install-OpenSSHUtilsModule
+{
+ [CmdletBinding()]
+ param(
+ [string]$TargetDir = (Join-Path -Path $env:ProgramFiles -ChildPath "WindowsPowerShell\Modules\OpenSSHUtils"),
+ [string]$SourceDir)
+
+ $manifestFile = Join-Path -Path $SourceDir -ChildPath OpenSSHUtils.psd1
+ $moduleFile = Join-Path -Path $SourceDir -ChildPath OpenSSHUtils.psm1
+ $targetDirectory = $TargetDir
+ $manifest = Test-ModuleManifest -Path $manifestFile -WarningAction SilentlyContinue -ErrorAction Stop
+ if ($PSVersionTable.PSVersion.Major -ge 5)
+ {
+ $targetDirectory = Join-Path -Path $targetDir -ChildPath $manifest.Version.ToString()
+ }
+
+ $modulePath = Join-Path -Path $env:ProgramFiles -ChildPath WindowsPowerShell\Modules
+ if(-not (Test-Path $targetDirectory -PathType Container))
+ {
+ New-Item -ItemType Directory -Path $targetDirectory -Force -ErrorAction SilentlyContinue | out-null
+ }
+ Copy-item $manifestFile -Destination $targetDirectory -Force -ErrorAction SilentlyContinue | out-null
+ Copy-item $moduleFile -Destination $targetDirectory -Force -ErrorAction SilentlyContinue | out-null
+
+ if ($PSVersionTable.PSVersion.Major -lt 4)
+ {
+ $modulePaths = [Environment]::GetEnvironmentVariable('PSModulePath', 'Machine') -split ';'
+ if ($modulePaths -notcontains $modulePath)
+ {
+ Write-Verbose -Message "Adding '$modulePath' to PSModulePath."
+
+ $modulePaths = @(
+ $modulePath
+ $modulePaths
+ )
+
+ $newModulePath = $modulePaths -join ';'
+
+ [Environment]::SetEnvironmentVariable('PSModulePath', $newModulePath, 'Machine')
+ $env:PSModulePath += ";$modulePath"
+ }
+ }
+}
+
+function Uninstall-OpenSSHUtilsModule
+{
+ [CmdletBinding()]
+ param([string]$TargetDir = (Join-Path -Path $env:ProgramFiles -ChildPath "WindowsPowerShell\Modules\OpenSSHUtils"))
+
+ if(Test-Path $TargetDir -PathType Container)
+ {
+ Remove-item $TargetDir -Recurse -Force -ErrorAction SilentlyContinue | out-null
+ }
+}
+
<#
.Synopsis
Get-UserSID
@@ -296,12 +376,12 @@ function Get-UserSID
<#
.Synopsis
- Cleanup-OpenSSHTestEnvironment
+ Clear-OpenSSHTestEnvironment
#>
-function Cleanup-OpenSSHTestEnvironment
+function Clear-OpenSSHTestEnvironment
{
if($Global:OpenSSHTestInfo -eq $null) {
- throw "OpenSSHTestInfo is not set. Did you run Setup-OpenSShTestEnvironment?"
+ throw "OpenSSHTestInfo is not set. Did you run Set-OpenSShTestEnvironment?"
}
$sshBinPath = $Global:OpenSSHTestInfo["OpenSSHBinPath"]
@@ -356,6 +436,13 @@ function Cleanup-OpenSSHTestEnvironment
$Global:OpenSSHTestInfo.Clear()
$Global:OpenSSHTestInfo = $null
}
+
+ $isOpenSSHUtilsAvailable = Get-Module 'OpenSSHUtils' -ListAvailable
+ if ($isOpenSSHUtilsAvailable)
+ {
+ Write-Log -Message "Uninstalling Module OpenSSHUtils..."
+ Uninstall-OpenSSHUtilsModule
+ }
}
<#
@@ -418,12 +505,13 @@ function Get-UnitTestDirectory
.Synopsis
Run OpenSSH pester tests.
#>
-function Run-OpenSSHE2ETest
+function Invoke-OpenSSHE2ETest
{
- # Discover all CI tests and run them.
+ # Discover all CI tests and run them.
+ Import-Module pester -force -global
Push-Location $Script:E2ETestDirectory
Write-Log -Message "Running OpenSSH E2E tests..."
- $testFolders = Get-ChildItem *.tests.ps1 -Recurse | ForEach-Object{ Split-Path $_.FullName} | Sort-Object -Unique
+ $testFolders = @(Get-ChildItem *.tests.ps1 -Recurse | ForEach-Object{ Split-Path $_.FullName} | Sort-Object -Unique)
Invoke-Pester $testFolders -OutputFormat NUnitXml -OutputFile $Script:E2ETestResultsFile -Tag 'CI'
Pop-Location
}
@@ -432,35 +520,45 @@ function Run-OpenSSHE2ETest
.Synopsis
Run openssh unit tests.
#>
-function Run-OpenSSHUnitTest
+function Invoke-OpenSSHUnitTest
{
# Discover all CI tests and run them.
+ if([string]::Isnullorempty($Script:UnitTestDirectory))
+ {
+ $Script:UnitTestDirectory = $OpenSSHTestInfo["UnitTestDirectory"]
+ }
Push-Location $Script:UnitTestDirectory
Write-Log -Message "Running OpenSSH unit tests..."
- if (Test-Path $Script:UnitTestResultsFile)
+ 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 |
+ $testFolders = Get-ChildItem -filter 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 $_
+ $testFolders | % {
$unittestFile = "$(Split-Path $_ -Leaf).exe"
- Write-log "Running OpenSSH unit $unittestFile ..."
- & .\$unittestFile >> $Script:UnitTestResultsFile
+ $unittestFilePath = join-path $_ $unittestFile
+ $Error.clear()
+ $LASTEXITCODE=0
+ if(Test-Path $unittestFilePath -pathtype leaf)
+ {
+ Push-Location $_
+ Write-Log "Running OpenSSH unit $unittestFile ..."
+ & "$unittestFilePath" >> $Script:UnitTestResultsFile
+ Pop-Location
+ }
$errorCode = $LASTEXITCODE
if ($errorCode -ne 0)
{
$testfailed = $true
- $errorMessage = "$($_.FullName) test failed for OpenSSH.`nExitCode: $errorCode. Detail test log is at $($Script:UnitTestResultsFile)."
+ $errorMessage = "$_ test failed for OpenSSH.`nExitCode: $errorCode. Detail test log is at $($Script:UnitTestResultsFile)."
Write-Warning $errorMessage
- }
- Pop-Location
+ }
}
}
Pop-Location
@@ -475,7 +573,7 @@ function Backup-OpenSSHTestInfo
)
if ($Global:OpenSSHTestInfo -eq $null) {
- Throw "`$OpenSSHTestInfo is null. Did you run Setup-OpenSSHTestEnvironment yet?"
+ Throw "`$OpenSSHTestInfo is null. Did you run Set-OpenSSHTestEnvironment yet?"
}
$testInfo = $Global:OpenSSHTestInfo
@@ -492,7 +590,7 @@ function Backup-OpenSSHTestInfo
}
}
-function Recover-OpenSSHTestInfo
+function Restore-OpenSSHTestInfo
{
param
(
@@ -538,4 +636,4 @@ function Write-Log
}
}
-Export-ModuleMember -Function Setup-OpenSSHTestEnvironment, Cleanup-OpenSSHTestEnvironment, Run-OpenSSHUnitTest, Run-OpenSSHE2ETest, Backup-OpenSSHTestInfo, Recover-OpenSSHTestInfo
+Export-ModuleMember -Function Set-OpenSSHTestEnvironment, Clear-OpenSSHTestEnvironment, Invoke-OpenSSHUnitTest, Invoke-OpenSSHE2ETest, Backup-OpenSSHTestInfo, Restore-OpenSSHTestInfo
diff --git a/contrib/win32/openssh/OpenSSHUtils.psm1 b/contrib/win32/openssh/OpenSSHUtils.psm1
index 8654fa5..b32f096 100644
--- a/contrib/win32/openssh/OpenSSHUtils.psm1
+++ b/contrib/win32/openssh/OpenSSHUtils.psm1
@@ -1,9 +1,49 @@
Set-StrictMode -Version 2.0
-$systemAccount = New-Object System.Security.Principal.NTAccount("NT AUTHORITY", "SYSTEM")
-$adminsAccount = New-Object System.Security.Principal.NTAccount("BUILTIN","Administrators")
-$currentUser = New-Object System.Security.Principal.NTAccount($($env:USERDOMAIN), $($env:USERNAME))
-$everyone = New-Object System.Security.Principal.NTAccount("EveryOne")
-$sshdAccount = New-Object System.Security.Principal.NTAccount("NT SERVICE","sshd")
+
+<#
+ .Synopsis
+ Get-UserSID
+#>
+function Get-UserSID
+{
+ [CmdletBinding(DefaultParameterSetName='User')]
+ param
+ ( [parameter(Mandatory=$true, ParameterSetName="User")]
+ [ValidateNotNull()]
+ [System.Security.Principal.NTAccount]$User,
+ [parameter(Mandatory=$true, ParameterSetName="WellKnownSidType")]
+ [ValidateNotNull()]
+ [System.Security.Principal.WellKnownSidType]$WellKnownSidType
+ )
+ try
+ {
+ if($PSBoundParameters.ContainsKey("User"))
+ {
+ $sid = $User.Translate([System.Security.Principal.SecurityIdentifier])
+ }
+ elseif($PSBoundParameters.ContainsKey("WellKnownSidType"))
+ {
+ $sid = New-Object System.Security.Principal.SecurityIdentifier($WellKnownSidType, $null)
+ }
+ $sid
+ }
+ catch {
+ return $null
+ }
+}
+
+# get the local System user
+$systemSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::LocalSystemSid)
+
+# get the Administrators group
+$adminsSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::BuiltinAdministratorsSid)
+
+# get the everyone
+$everyoneSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::WorldSid)
+
+$sshdSid = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-80-3847866527-469524349-687026318-516638107-1125189541")
+
+$currentUserSid = Get-UserSID -User "$($env:USERDOMAIN)\$($env:USERNAME)"
#Taken from P/Invoke.NET with minor adjustments.
$definition = @'
@@ -72,7 +112,7 @@ function Repair-SshdConfigPermission
[ValidateNotNullOrEmpty()]
[string]$FilePath)
- Repair-FilePermission -Owners $systemAccount,$adminsAccount -ReadAccessNeeded $sshdAccount @psBoundParameters
+ Repair-FilePermission -Owners $systemSid,$adminsSid -ReadAccessNeeded $sshdSid @psBoundParameters
}
<#
@@ -86,18 +126,18 @@ function Repair-SshdHostKeyPermission
[CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact="High")]
param (
[parameter(Mandatory=$true)]
- [ValidateNotNullOrEmpty()]
- [string]$FilePath)
+ [ValidateNotNullOrEmpty()]
+ [string]$FilePath)
if($PSBoundParameters["FilePath"].EndsWith(".pub"))
{
$PSBoundParameters["FilePath"] = $PSBoundParameters["FilePath"].Replace(".pub", "")
}
- Repair-FilePermission -Owners $systemAccount,$adminsAccount -ReadAccessNeeded $sshdAccount @psBoundParameters
+ Repair-FilePermission -Owners $systemSid,$adminsSid -ReadAccessNeeded $sshdSid @psBoundParameters
- $PSBoundParameters["FilePath"] += ".pub"
- Repair-FilePermission -Owners $systemAccount,$adminsAccount -ReadAccessOK $everyone -ReadAccessNeeded $sshdAccount @psBoundParameters
+ $PSBoundParameters["FilePath"] += ".pub"
+ Repair-FilePermission -Owners $systemSid,$adminsSid -ReadAccessOK $everyoneSid -ReadAccessNeeded $sshdSid @psBoundParameters
}
<#
@@ -127,20 +167,14 @@ function Repair-AuthorizedKeyPermission
{
$userProfilePath = $properties.ProfileImagePath
}
- $fullPath -ieq "$userProfilePath\.ssh\authorized_keys"
+ $userProfilePath = $userProfilePath.Replace("\", "\\")
+ $fullPath -match "^$userProfilePath[\\|\W|\w]+authorized_keys$"
}
if($profileItem)
{
- $userSid = $profileItem.PSChildName
- $account = Get-UserAccount -UserSid $userSid
- if($account)
- {
- Repair-FilePermission -Owners $account,$adminsAccount,$systemAccount -AnyAccessOK $account -ReadAccessNeeded $sshdAccount @psBoundParameters
- }
- else
- {
- Write-host "Can't translate $userSid to an account. skip checking $fullPath..." -ForegroundColor Yellow
- }
+ $userSid = $profileItem.PSChildName
+ Repair-FilePermission -Owners $userSid,$adminsSid,$systemSid -AnyAccessOK $userSid -ReadAccessNeeded $sshdSid @psBoundParameters
+
}
else
{
@@ -162,16 +196,16 @@ function Repair-UserKeyPermission
[parameter(Mandatory=$true, Position = 0)]
[ValidateNotNullOrEmpty()]
[string]$FilePath,
- [System.Security.Principal.NTAccount] $User = $currentUser)
+ [System.Security.Principal.SecurityIdentifier] $UserSid = $currentUserSid)
if($PSBoundParameters["FilePath"].EndsWith(".pub"))
{
$PSBoundParameters["FilePath"] = $PSBoundParameters["FilePath"].Replace(".pub", "")
}
- Repair-FilePermission -Owners $User, $adminsAccount,$systemAccount -AnyAccessOK $User @psBoundParameters
+ Repair-FilePermission -Owners $UserSid, $adminsSid,$systemSid -AnyAccessOK $UserSid @psBoundParameters
$PSBoundParameters["FilePath"] += ".pub"
- Repair-FilePermission -Owners $User, $adminsAccount,$systemAccount -AnyAccessOK $User -ReadAccessOK $everyone @psBoundParameters
+ Repair-FilePermission -Owners $UserSid, $adminsSid,$systemSid -AnyAccessOK $UserSid -ReadAccessOK $everyoneSid @psBoundParameters
}
<#
@@ -185,8 +219,9 @@ function Repair-UserSshConfigPermission
param (
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
- [string]$FilePath)
- Repair-FilePermission -Owners $currentUser,$adminsAccount,$systemAccount -AnyAccessOK $currentUser @psBoundParameters
+ [string]$FilePath,
+ [System.Security.Principal.SecurityIdentifier] $UserSid = $currentUserSid)
+ Repair-FilePermission -Owners $UserSid,$adminsSid,$systemSid -AnyAccessOK $UserSid @psBoundParameters
}
<#
@@ -202,10 +237,11 @@ function Repair-FilePermission
[ValidateNotNullOrEmpty()]
[string]$FilePath,
[ValidateNotNull()]
- [System.Security.Principal.NTAccount[]] $Owners = $currentUser,
- [System.Security.Principal.NTAccount[]] $AnyAccessOK,
- [System.Security.Principal.NTAccount[]] $ReadAccessOK,
- [System.Security.Principal.NTAccount[]] $ReadAccessNeeded
+ [System.Security.Principal.SecurityIdentifier[]] $Owners = $currentUserSid,
+ [System.Security.Principal.SecurityIdentifier[]] $AnyAccessOK = $null,
+ [System.Security.Principal.SecurityIdentifier[]] $FullAccessNeeded = $null,
+ [System.Security.Principal.SecurityIdentifier[]] $ReadAccessOK = $null,
+ [System.Security.Principal.SecurityIdentifier[]] $ReadAccessNeeded = $null
)
if(-not (Test-Path $FilePath -PathType Leaf))
@@ -235,10 +271,11 @@ function Repair-FilePermissionInternal {
[ValidateNotNullOrEmpty()]
[string]$FilePath,
[ValidateNotNull()]
- [System.Security.Principal.NTAccount[]] $Owners = $currentUser,
- [System.Security.Principal.NTAccount[]] $AnyAccessOK,
- [System.Security.Principal.NTAccount[]] $ReadAccessOK,
- [System.Security.Principal.NTAccount[]] $ReadAccessNeeded
+ [System.Security.Principal.SecurityIdentifier[]] $Owners = $currentUserSid,
+ [System.Security.Principal.SecurityIdentifier[]] $AnyAccessOK = $null,
+ [System.Security.Principal.SecurityIdentifier[]] $FullAccessNeeded = $null,
+ [System.Security.Principal.SecurityIdentifier[]] $ReadAccessOK = $null,
+ [System.Security.Principal.SecurityIdentifier[]] $ReadAccessNeeded = $null
)
$acl = Get-Acl $FilePath
@@ -246,26 +283,19 @@ function Repair-FilePermissionInternal {
$health = $true
$paras = @{}
$PSBoundParameters.GetEnumerator() | % { if((-not $_.key.Contains("Owners")) -and (-not $_.key.Contains("Access"))) { $paras.Add($_.key,$_.Value) } }
-
- $validOwner = $owners | ? { $_.equals([System.Security.Principal.NTAccount]$acl.owner)}
- if($validOwner -eq $null)
- {
- $caption = "Current owner: '$($acl.Owner)'. '$($Owners[0])' should own '$FilePath'."
+
+ $currentOwnerSid = Get-UserSid -User $acl.owner
+ if($owners -notcontains $currentOwnerSid)
+ {
+ $newOwner = Get-UserAccount -User $Owners[0]
+ $caption = "Current owner: '$($acl.Owner)'. '$newOwner' should own '$FilePath'."
$prompt = "Shall I set the file owner?"
- $description = "Set '$($Owners[0])' as owner of '$FilePath'."
+ $description = "Set '$newOwner' as owner of '$FilePath'."
if($pscmdlet.ShouldProcess($description, $prompt, $caption))
- {
+ {
Enable-Privilege SeRestorePrivilege | out-null
- $acl.SetOwner($Owners[0])
- Set-Acl -Path $FilePath -AclObject $acl -ErrorVariable e -Confirm:$false
- if($e)
- {
- Write-Warning "Set owner failed with error: $($e[0].ToString())."
- }
- else
- {
- Write-Host "'$($Owners[0])' now owns '$FilePath'. " -ForegroundColor Green
- }
+ $acl.SetOwner($newOwner)
+ Set-Acl -Path $FilePath -AclObject $acl -Confirm:$false
}
else
{
@@ -279,56 +309,126 @@ function Repair-FilePermissionInternal {
$ReadAccessPerm = ([System.UInt32] [System.Security.AccessControl.FileSystemRights]::Read.value__) -bor `
([System.UInt32] [System.Security.AccessControl.FileSystemRights]::Synchronize.value__)
+ $FullControlPerm = [System.UInt32] [System.Security.AccessControl.FileSystemRights]::FullControl.value__
#system and admin groups can have any access to the file; plus the account in the AnyAccessOK list
- $realAnyAccessOKList = $AnyAccessOK + @($systemAccount, $adminsAccount)
-
- #if accounts in the ReadAccessNeeded already part of dacl, they are okay; need to make sure they have read access only
- $realReadAcessOKList = $ReadAccessOK + $ReadAccessNeeded
-
- #this is orginal list requested by the user, the account will be removed from the list if they already part of the dacl
+ $realAnyAccessOKList = @($systemSid, $adminsSid)
+ if($AnyAccessOK)
+ {
+ $realAnyAccessOKList += $AnyAccessOK
+ }
+
+ $realFullAccessNeeded = $FullAccessNeeded
$realReadAccessNeeded = $ReadAccessNeeded
-
- #'APPLICATION PACKAGE AUTHORITY\ALL RESTRICTED APPLICATION PACKAGES'- can't translate fully qualified name. it is a win32 API bug.
- #'ALL APPLICATION PACKAGES' exists only on Win2k12 and Win2k16 and 'ALL RESTRICTED APPLICATION PACKAGES' exists only in Win2k16
- $specialIdRefs = "ALL APPLICATION PACKAGES","ALL RESTRICTED APPLICATION PACKAGES"
+ if($realFullAccessNeeded -contains $everyoneSid)
+ {
+ $realFullAccessNeeded = @($everyoneSid)
+ $realReadAccessNeeded = $null
+ }
+
+ if($realReadAccessNeeded -contains $everyoneSid)
+ {
+ $realReadAccessNeeded = @($everyoneSid)
+ }
+ #this is orginal list requested by the user, the account will be removed from the list if they already part of the dacl
+ if($realReadAccessNeeded)
+ {
+ $realReadAccessNeeded = $realReadAccessNeeded | ? { ($_ -ne $null) -and ($realFullAccessNeeded -notcontains $_) }
+ }
+
+ #if accounts in the ReadAccessNeeded or $realFullAccessNeeded already part of dacl, they are okay;
+ #need to make sure they have read access only
+ $realReadAcessOKList = $ReadAccessOK + $realReadAccessNeeded
foreach($a in $acl.Access)
{
- if($realAnyAccessOKList -and (($realAnyAccessOKList | ? { $_.equals($a.IdentityReference)}) -ne $null))
+ $IdentityReferenceSid = Get-UserSid -User $a.IdentityReference
+ if($IdentityReferenceSid -eq $null)
+ {
+ $idRefShortValue = ($a.IdentityReference.Value).split('\')[-1]
+ $IdentityReferenceSid = Get-UserSID -User $idRefShortValue
+ if($IdentityReferenceSid -eq $null)
+ {
+ Write-Warning "Can't translate '$idRefShortValue'. "
+ continue
+ }
+ }
+
+ if($realFullAccessNeeded -contains ($IdentityReferenceSid))
+ {
+ $realFullAccessNeeded = $realFullAccessNeeded | ? { ($_ -ne $null) -and (-not $_.Equals($IdentityReferenceSid)) }
+ if($realReadAccessNeeded)
+ {
+ $realReadAccessNeeded = $realReadAccessNeeded | ? { ($_ -ne $null) -and (-not $_.Equals($IdentityReferenceSid)) }
+ }
+ if (($a.AccessControlType.Equals([System.Security.AccessControl.AccessControlType]::Allow)) -and `
+ ((([System.UInt32]$a.FileSystemRights.value__) -band $FullControlPerm) -eq $FullControlPerm))
+ {
+ continue;
+ }
+ #update the account to full control
+ if($a.IsInherited)
+ {
+ if($needChange)
+ {
+ Enable-Privilege SeRestorePrivilege | out-null
+ Set-Acl -Path $FilePath -AclObject $acl -Confirm:$false
+ }
+
+ return Remove-RuleProtection @paras
+ }
+ $caption = "'$($a.IdentityReference)' has the following access to '$FilePath': '$($a.AccessControlType)'-'$($a.FileSystemRights)'."
+ $prompt = "Shall I make it Allow FullControl?"
+ $description = "Grant '$($a.IdentityReference)' FullControl access to '$FilePath'. "
+
+ if($pscmdlet.ShouldProcess($description, $prompt, $caption))
+ {
+ $needChange = $true
+ $ace = New-Object System.Security.AccessControl.FileSystemAccessRule `
+ ($IdentityReferenceSid, "FullControl", "None", "None", "Allow")
+
+ $acl.SetAccessRule($ace)
+ Write-Host "'$($a.IdentityReference)' now has FullControl access to '$FilePath'. " -ForegroundColor Green
+ }
+ else
+ {
+ $health = $false
+ if(-not $PSBoundParameters.ContainsKey("WhatIf"))
+ {
+ Write-Host "'$($a.IdentityReference)' still has these access to '$FilePath': '$($a.AccessControlType)'-'$($a.FileSystemRights)'." -ForegroundColor Yellow
+ }
+ }
+ }
+ elseif(($realAnyAccessOKList -contains $everyoneSid) -or ($realAnyAccessOKList -contains $IdentityReferenceSid))
{
#ignore those accounts listed in the AnyAccessOK list.
+ continue;
}
#If everyone is in the ReadAccessOK list, any user can have read access;
# below block make sure they are granted Read access only
- elseif($realReadAcessOKList -and ((($realReadAcessOKList | ? { $_.Equals($everyone)}) -ne $null) -or `
- (($realReadAcessOKList | ? { $_.equals($a.IdentityReference)}) -ne $null)))
+ elseif(($realReadAcessOKList -contains $everyoneSid) -or ($realReadAcessOKList -contains $IdentityReferenceSid))
{
- if($realReadAccessNeeded -and ($a.IdentityReference.Equals($everyone)))
+ if($realReadAccessNeeded -and ($IdentityReferenceSid.Equals($everyoneSid)))
{
- $realReadAccessNeeded=@()
+ $realReadAccessNeeded= $null
}
elseif($realReadAccessNeeded)
{
- $realReadAccessNeeded = $realReadAccessNeeded | ? { -not $_.Equals($a.IdentityReference) }
+ $realReadAccessNeeded = $realReadAccessNeeded | ? { ($_ -ne $null ) -and (-not $_.Equals($IdentityReferenceSid)) }
}
if (-not ($a.AccessControlType.Equals([System.Security.AccessControl.AccessControlType]::Allow)) -or `
(-not (([System.UInt32]$a.FileSystemRights.value__) -band (-bnot $ReadAccessPerm))))
{
continue;
- }
+ }
if($a.IsInherited)
{
if($needChange)
{
Enable-Privilege SeRestorePrivilege | out-null
- Set-Acl -Path $FilePath -AclObject $acl -ErrorVariable e -Confirm:$false
- if($e)
- {
- Write-Warning "Repair permission failed with error: $($e[0].ToString())."
- }
+ Set-Acl -Path $FilePath -AclObject $acl -Confirm:$false
}
return Remove-RuleProtection @paras
@@ -340,28 +440,11 @@ function Repair-FilePermissionInternal {
if($pscmdlet.ShouldProcess($description, $prompt, $caption))
{
$needChange = $true
- $idRefShortValue = ($a.IdentityReference.Value).split('\')[-1]
- if ($specialIdRefs -icontains $idRefShortValue )
- {
- $ruleIdentity = Get-UserSID -User (New-Object Security.Principal.NTAccount $idRefShortValue)
- if($ruleIdentity)
- {
- $ace = New-Object System.Security.AccessControl.FileSystemAccessRule `
- ($ruleIdentity, "Read", "None", "None", "Allow")
- }
- else
- {
- Write-Warning "Can't translate '$idRefShortValue'. "
- continue
- }
- }
- else
- {
- $ace = New-Object System.Security.AccessControl.FileSystemAccessRule `
- ($a.IdentityReference, "Read", "None", "None", "Allow")
- }
+ $ace = New-Object System.Security.AccessControl.FileSystemAccessRule `
+ ($IdentityReferenceSid, "Read", "None", "None", "Allow")
+
$acl.SetAccessRule($ace)
- Write-Host "'$($a.IdentityReference)' now has Read access to '$FilePath'. " -ForegroundColor Green
+ Write-Host "'$($a.IdentityReference)' now has Read access to '$FilePath'. " -ForegroundColor Green
}
else
{
@@ -381,11 +464,7 @@ function Repair-FilePermissionInternal {
if($needChange)
{
Enable-Privilege SeRestorePrivilege | out-null
- Set-Acl -Path $FilePath -AclObject $acl -ErrorVariable e -Confirm:$false
- if($e)
- {
- Write-Warning "Repair permission failed with error: $($e[0].ToString())."
- }
+ Set-Acl -Path $FilePath -AclObject $acl -Confirm:$false
}
return Remove-RuleProtection @paras
}
@@ -395,23 +474,9 @@ function Repair-FilePermissionInternal {
if($pscmdlet.ShouldProcess($description, $prompt, "$caption."))
{
- $needChange = $true
- $ace = $a
- $idRefShortValue = ($a.IdentityReference.Value).split('\')[-1]
- if ($specialIdRefs -icontains $idRefShortValue)
- {
- $ruleIdentity = Get-UserSID -User (New-Object Security.Principal.NTAccount $idRefShortValue)
- if($ruleIdentity)
- {
- $ace = New-Object System.Security.AccessControl.FileSystemAccessRule `
- ($ruleIdentity, $a.FileSystemRights, $a.InheritanceFlags, $a.PropagationFlags, $a.AccessControlType)
- }
- else
- {
- Write-Warning "Can't translate '$idRefShortValue'. "
- continue
- }
- }
+ $needChange = $true
+ $ace = New-Object System.Security.AccessControl.FileSystemAccessRule `
+ ($IdentityReferenceSid, $a.FileSystemRights, $a.InheritanceFlags, $a.PropagationFlags, $a.AccessControlType)
if(-not ($acl.RemoveAccessRule($ace)))
{
@@ -432,20 +497,55 @@ function Repair-FilePermissionInternal {
}
}
}
+
+ if($realFullAccessNeeded)
+ {
+ $realFullAccessNeeded | % {
+ $account = Get-UserAccount -UserSid $_
+ if($account -eq $null)
+ {
+ Write-Warning "'$_' needs FullControl access to '$FilePath', but it can't be translated on the machine."
+ }
+ else
+ {
+ $caption = "'$account' needs FullControl access to '$FilePath'."
+ $prompt = "Shall I make the above change?"
+ $description = "Set '$account' FullControl access to '$FilePath'. "
+
+ if($pscmdlet.ShouldProcess($description, $prompt, $caption))
+ {
+ $needChange = $true
+ $ace = New-Object System.Security.AccessControl.FileSystemAccessRule `
+ ($_, "FullControl", "None", "None", "Allow")
+ $acl.AddAccessRule($ace)
+ Write-Host "'$account' now has FullControl to '$FilePath'." -ForegroundColor Green
+ }
+ else
+ {
+ $health = $false
+ if(-not $PSBoundParameters.ContainsKey("WhatIf"))
+ {
+ Write-Host "'$account' does not have FullControl to '$FilePath'." -ForegroundColor Yellow
+ }
+ }
+ }
+ }
+ }
#This is the real account list we need to add read access to the file
if($realReadAccessNeeded)
{
$realReadAccessNeeded | % {
- if((Get-UserSID -User $_) -eq $null)
+ $account = Get-UserAccount -UserSid $_
+ if($account -eq $null)
{
Write-Warning "'$_' needs Read access to '$FilePath', but it can't be translated on the machine."
}
else
{
- $caption = "'$_' needs Read access to '$FilePath'."
+ $caption = "'$account' needs Read access to '$FilePath'."
$prompt = "Shall I make the above change?"
- $description = "Set '$_' Read only access to '$FilePath'. "
+ $description = "Set '$account' Read only access to '$FilePath'. "
if($pscmdlet.ShouldProcess($description, $prompt, $caption))
{
@@ -453,14 +553,14 @@ function Repair-FilePermissionInternal {
$ace = New-Object System.Security.AccessControl.FileSystemAccessRule `
($_, "Read", "None", "None", "Allow")
$acl.AddAccessRule($ace)
- Write-Host "'$_' now has Read access to '$FilePath'." -ForegroundColor Green
+ Write-Host "'$account' now has Read access to '$FilePath'." -ForegroundColor Green
}
else
{
$health = $false
if(-not $PSBoundParameters.ContainsKey("WhatIf"))
{
- Write-Host "'$_' does not have Read access to '$FilePath'." -ForegroundColor Yellow
+ Write-Host "'$account' does not have Read access to '$FilePath'." -ForegroundColor Yellow
}
}
}
@@ -470,11 +570,7 @@ function Repair-FilePermissionInternal {
if($needChange)
{
Enable-Privilege SeRestorePrivilege | out-null
- Set-Acl -Path $FilePath -AclObject $acl -ErrorVariable e -Confirm:$false
- if($e)
- {
- Write-Warning "Repair permission failed with error: $($e[0].ToString())."
- }
+ Set-Acl -Path $FilePath -AclObject $acl -Confirm:$false
}
if($health)
{
@@ -525,41 +621,44 @@ function Remove-RuleProtection
return $false
}
}
+
<#
.Synopsis
Get-UserAccount
#>
function Get-UserAccount
{
+ [CmdletBinding(DefaultParameterSetName='Sid')]
param
- ( [parameter(Mandatory=$true)]
- [string]$UserSid
+ ( [parameter(Mandatory=$true, ParameterSetName="Sid")]
+ [ValidateNotNull()]
+ [System.Security.Principal.SecurityIdentifier]$UserSid,
+ [parameter(Mandatory=$true, ParameterSetName="WellKnownSidType")]
+ [ValidateNotNull()]
+ [System.Security.Principal.WellKnownSidType]$WellKnownSidType
)
try
{
- $objSID = New-Object System.Security.Principal.SecurityIdentifier($UserSid)
- $objUser = $objSID.Translate( [System.Security.Principal.NTAccount])
+ if($PSBoundParameters.ContainsKey("UserSid"))
+ {
+ $objUser = $UserSid.Translate([System.Security.Principal.NTAccount])
+ }
+ elseif($PSBoundParameters.ContainsKey("WellKnownSidType"))
+ {
+ $objSID = New-Object System.Security.Principal.SecurityIdentifier($WellKnownSidType, $null)
+ $objUser = $objSID.Translate( [System.Security.Principal.NTAccount])
+ }
$objUser
}
catch {
+ return $null
}
}
<#
.Synopsis
- Get-UserSID
+ Enable-Privilege
#>
-function Get-UserSID
-{
- param ([System.Security.Principal.NTAccount]$User)
- try
- {
- $User.Translate([System.Security.Principal.SecurityIdentifier])
- }
- catch {
- }
-}
-
function Enable-Privilege {
param(
#The privilege to adjust. This set is taken from
@@ -584,4 +683,4 @@ function Enable-Privilege {
$type[0]::EnablePrivilege($Privilege, $Disable)
}
-Export-ModuleMember -Function Repair-FilePermission, Repair-SshdConfigPermission, Repair-SshdHostKeyPermission, Repair-AuthorizedKeyPermission, Repair-UserKeyPermission, Repair-UserSshConfigPermission
+Export-ModuleMember -Function Repair-FilePermission, Repair-SshdConfigPermission, Repair-SshdHostKeyPermission, Repair-AuthorizedKeyPermission, Repair-UserKeyPermission, Repair-UserSshConfigPermission, Enable-Privilege, Get-UserAccount, Get-UserSID
diff --git a/contrib/win32/openssh/VSWithBuildTools.xml b/contrib/win32/openssh/VSWithBuildTools.xml
deleted file mode 100644
index 279fedf..0000000
--- a/contrib/win32/openssh/VSWithBuildTools.xml
+++ /dev/null
@@ -1,84 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/contrib/win32/openssh/sshd.vcxproj b/contrib/win32/openssh/sshd.vcxproj
index 2061408..c68b4e1 100644
--- a/contrib/win32/openssh/sshd.vcxproj
+++ b/contrib/win32/openssh/sshd.vcxproj
@@ -246,6 +246,7 @@
+
diff --git a/contrib/win32/openssh/sshd.vcxproj.filters b/contrib/win32/openssh/sshd.vcxproj.filters
index e3254ed..f5c2282 100644
--- a/contrib/win32/openssh/sshd.vcxproj.filters
+++ b/contrib/win32/openssh/sshd.vcxproj.filters
@@ -150,6 +150,9 @@
Source Files
+
+ Source Files
+
diff --git a/contrib/win32/openssh/sshd_config b/contrib/win32/openssh/sshd_config
index 651af0b..7a25ba8 100644
--- a/contrib/win32/openssh/sshd_config
+++ b/contrib/win32/openssh/sshd_config
@@ -119,4 +119,5 @@ Subsystem sftp sftp-server.exe
# X11Forwarding no
# AllowTcpForwarding no
# ForceCommand cvs server
-# PubkeyAcceptedKeyTypes ssh-ed25519*
\ No newline at end of file
+# PubkeyAcceptedKeyTypes ssh-ed25519*
+hostkeyagent \\.\pipe\openssh-ssh-agent
\ No newline at end of file
diff --git a/contrib/win32/openssh/version.rc b/contrib/win32/openssh/version.rc
index 7b37b2b..b43900b 100644
Binary files a/contrib/win32/openssh/version.rc and b/contrib/win32/openssh/version.rc differ
diff --git a/contrib/win32/win32compat/fileio.c b/contrib/win32/win32compat/fileio.c
index de9fbe8..c876adb 100644
--- a/contrib/win32/win32compat/fileio.c
+++ b/contrib/win32/win32compat/fileio.c
@@ -114,9 +114,8 @@ int
fileio_connect(struct w32_io* pio, char* name)
{
wchar_t* name_w = NULL;
- wchar_t pipe_name[PATH_MAX];
HANDLE h = INVALID_HANDLE_VALUE;
- int ret = 0, r;
+ int ret = 0;
if (pio->handle != 0 && pio->handle != INVALID_HANDLE_VALUE) {
debug3("fileio_connect called in unexpected state, pio = %p", pio);
@@ -129,16 +128,9 @@ fileio_connect(struct w32_io* pio, char* name)
errno = ENOMEM;
return -1;
}
- r = _snwprintf_s(pipe_name, PATH_MAX, PATH_MAX, L"\\\\.\\pipe\\%ls", name_w);
- if (r < 0 || r >= PATH_MAX) {
- debug3("cannot create pipe name with %s", name);
- errno = EOTHER;
- return -1;
- }
-
-
+
do {
- h = CreateFileW(pipe_name, GENERIC_READ | GENERIC_WRITE, 0,
+ h = CreateFileW(name_w, GENERIC_READ | GENERIC_WRITE, 0,
NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED | SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION, NULL);
if (h != INVALID_HANDLE_VALUE)
diff --git a/contrib/win32/win32compat/misc.c b/contrib/win32/win32compat/misc.c
index f016eaa..144589d 100644
--- a/contrib/win32/win32compat/misc.c
+++ b/contrib/win32/win32compat/misc.c
@@ -478,11 +478,23 @@ strmode(mode_t mode, char *p)
break;
}
- /* The below code is commented as the group, other is not applicable on the windows.
- * As of now we are keeping "*" for everything.
- * TODO - figure out if there is a better option
- */
- const char *permissions = "********* ";
+ /* group, other are not applicable on the windows */
+
+ /* usr */
+ if (mode & S_IREAD)
+ *p++ = 'r';
+ else
+ *p++ = '-';
+ if (mode & S_IWRITE)
+ *p++ = 'w';
+ else
+ *p++ = '-';
+ if (mode & S_IEXEC)
+ *p++ = 'x';
+ else
+ *p++ = '-';
+
+ const char *permissions = "****** ";
for(int i = 0; i < strlen(permissions); i++)
*p++ = permissions[i];
@@ -950,7 +962,8 @@ w32_strerror(int errnum)
}
char *
-readpassphrase(const char *prompt, char *outBuf, size_t outBufLen, int flags) {
+readpassphrase(const char *prompt, char *outBuf, size_t outBufLen, int flags)
+{
int current_index = 0;
char ch;
wchar_t* wtmp = NULL;
diff --git a/contrib/win32/win32compat/priv-agent.h b/contrib/win32/win32compat/priv-agent.h
new file mode 100644
index 0000000..f98ac15
--- /dev/null
+++ b/contrib/win32/win32compat/priv-agent.h
@@ -0,0 +1,8 @@
+/*
+ * Definitions for IPC between sshd and privileged agent
+ */
+#pragma once
+
+#define SSH_PRIV_AGENT_MSG_ID 0
+#define PUBKEY_AUTH_REQUEST "pubkey"
+#define LOAD_USER_PROFILE_REQUEST "loadprofile"
diff --git a/contrib/win32/win32compat/shell-host.c b/contrib/win32/win32compat/shell-host.c
index f50443f..019a657 100644
--- a/contrib/win32/win32compat/shell-host.c
+++ b/contrib/win32/win32compat/shell-host.c
@@ -102,6 +102,9 @@ struct key_translation keys[] = {
{ L"\x1b[B", VK_DOWN, 0 , 0},
{ L"\x1b[C", VK_RIGHT, 0 , 0},
{ L"\x1b[D", VK_LEFT, 0 , 0},
+ { L"\x1b[F", VK_END, 0 , 0 }, /* KeyPad END */
+ { L"\x1b[H", VK_HOME, 0 , 0 }, /* KeyPad HOME */
+ { L"\x1b[Z", 0, 0 , 0 }, /* ignore Shift+TAB */
{ L"\x1b[1~", VK_HOME, 0 , 0},
{ L"\x1b[2~", VK_INSERT, 0 , 0},
{ L"\x1b[3~", VK_DELETE, 0 , 0},
@@ -120,11 +123,17 @@ struct key_translation keys[] = {
{ L"\x1b[21~", VK_F10, 0 , 0},
{ L"\x1b[23~", VK_F11, 0 , 0},
{ L"\x1b[24~", VK_F12, 0 , 0},
+ { L"\x1bOP", VK_F1, 0 , 0 },
+ { L"\x1bOQ", VK_F2, 0 , 0 },
+ { L"\x1bOR", VK_F3, 0 , 0 },
+ { L"\x1bOS", VK_F4, 0 , 0 },
{ L"\x1b", VK_ESCAPE, L'\x1b' , 0}
};
static SHORT lastX = 0;
static SHORT lastY = 0;
+static wchar_t cmd_exe_path[PATH_MAX];
+
SHORT currentLine = 0;
consoleEvent* head = NULL;
consoleEvent* tail = NULL;
@@ -939,6 +948,19 @@ cleanup:
return 0;
}
+wchar_t *
+w32_cmd_path()
+{
+ ZeroMemory(cmd_exe_path, PATH_MAX);
+ if (!GetSystemDirectory(cmd_exe_path, sizeof(cmd_exe_path))) {
+ printf("GetSystemDirectory failed");
+ exit(255);
+ }
+
+ wcscat_s(cmd_exe_path, sizeof(cmd_exe_path), L"\\cmd.exe");
+ return cmd_exe_path;
+}
+
int
start_with_pty(wchar_t *command)
{
@@ -1004,9 +1026,8 @@ start_with_pty(wchar_t *command)
/* disable inheritance on pipe_in*/
GOTO_CLEANUP_ON_FALSE(SetHandleInformation(pipe_in, HANDLE_FLAG_INHERIT, 0));
- /*TODO - pick this up from system32*/
cmd[0] = L'\0';
- GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, L"cmd.exe"));
+ GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, w32_cmd_path()));
if (command) {
GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, L" /c"));
@@ -1178,10 +1199,9 @@ start_withno_pty(wchar_t *command)
run_under_cmd = TRUE;
/* if above failed with FILE_NOT_FOUND, try running the provided command under cmd*/
- if (run_under_cmd) {
- /*TODO - pick this up from system32*/
+ if (run_under_cmd) {
cmd[0] = L'\0';
- GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, L"cmd.exe"));
+ GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, w32_cmd_path()));
if (command) {
GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, L" /c"));
GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, L" "));
diff --git a/contrib/win32/win32compat/ssh-agent/agent-request.h b/contrib/win32/win32compat/ssh-agent/agent-request.h
index 3d7c3df..2ee6222 100644
--- a/contrib/win32/win32compat/ssh-agent/agent-request.h
+++ b/contrib/win32/win32compat/ssh-agent/agent-request.h
@@ -16,6 +16,6 @@ int process_request_identities(struct sshbuf*, struct sshbuf*, struct agent_conn
int process_sign_request(struct sshbuf*, struct sshbuf*, struct agent_connection*);
int process_remove_key(struct sshbuf*, struct sshbuf*, struct agent_connection*);
int process_remove_all(struct sshbuf*, struct sshbuf*, struct agent_connection*);
-int process_authagent_request(struct sshbuf*, struct sshbuf*, struct agent_connection*);
+int process_privagent_request(struct sshbuf*, struct sshbuf*, struct agent_connection*);
/* auth */
diff --git a/contrib/win32/win32compat/ssh-agent/agent.c b/contrib/win32/win32compat/ssh-agent/agent.c
index d1042d4..54f4a5f 100644
--- a/contrib/win32/win32compat/ssh-agent/agent.c
+++ b/contrib/win32/win32compat/ssh-agent/agent.c
@@ -37,7 +37,7 @@
static HANDLE ioc_port = NULL;
static BOOL debug_mode = FALSE;
-#define AGENT_PIPE_ID L"\\\\.\\pipe\\ssh-agent"
+#define AGENT_PIPE_ID L"\\\\.\\pipe\\openssh-ssh-agent"
static HANDLE event_stop_agent;
static OVERLAPPED ol;
@@ -168,12 +168,14 @@ agent_cleanup_connection(struct agent_connection* con)
{
debug("connection %p clean up", con);
CloseHandle(con->pipe_handle);
- if (con->hProfile)
- UnloadUserProfile(con->auth_token, con->hProfile);
- if (con->auth_token)
- CloseHandle(con->auth_token);
+ if (con->profile_handle)
+ UnloadUserProfile(con->profile_token, con->profile_handle);
+ if (con->profile_token)
+ CloseHandle(con->profile_token);
if (con->client_impersonation_token)
CloseHandle(con->client_impersonation_token);
+ if (con->client_process_handle)
+ CloseHandle(con->client_process_handle);
free(con);
CloseHandle(ioc_port);
ioc_port = NULL;
@@ -251,13 +253,13 @@ get_con_client_info(struct agent_connection* con)
DWORD sshd_sid_len = 0;
PSID sshd_sid = NULL;
SID_NAME_USE nuse;
- HANDLE client_primary_token = NULL, client_impersonation_token = NULL, client_proc_handle = NULL;
+ HANDLE client_primary_token = NULL, client_impersonation_token = NULL, client_process_handle = NULL;
TOKEN_USER* info = NULL;
BOOL isMember = FALSE;
if (GetNamedPipeClientProcessId(con->pipe_handle, &client_pid) == FALSE ||
- (client_proc_handle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, client_pid)) == NULL ||
- OpenProcessToken(client_proc_handle, TOKEN_QUERY | TOKEN_DUPLICATE, &client_primary_token) == FALSE ||
+ (client_process_handle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_DUP_HANDLE, FALSE, client_pid)) == NULL ||
+ OpenProcessToken(client_process_handle, TOKEN_QUERY | TOKEN_DUPLICATE, &client_primary_token) == FALSE ||
DuplicateToken(client_primary_token, SecurityImpersonation, &client_impersonation_token) == FALSE) {
error("cannot retrieve client impersonatin token");
goto done;
@@ -341,15 +343,19 @@ done:
free(ref_dom);
if (info)
free(info);
- if (client_proc_handle)
- CloseHandle(client_proc_handle);
if (client_primary_token)
CloseHandle(client_primary_token);
- if (r == 0)
+ if (r == 0) {
+ con->client_process_handle = client_process_handle;
con->client_impersonation_token = client_impersonation_token;
- else if (client_impersonation_token)
- CloseHandle(client_impersonation_token);
+ }
+ else {
+ if (client_process_handle)
+ CloseHandle(client_process_handle);
+ if (client_impersonation_token)
+ CloseHandle(client_impersonation_token);
+ }
return r;
}
diff --git a/contrib/win32/win32compat/ssh-agent/agent.h b/contrib/win32/win32compat/ssh-agent/agent.h
index ea2da0a..f732908 100644
--- a/contrib/win32/win32compat/ssh-agent/agent.h
+++ b/contrib/win32/win32compat/ssh-agent/agent.h
@@ -4,17 +4,18 @@
#include "log.h"
#define MAX_MESSAGE_SIZE 256 * 1024
-#define SSH_ROOT L"SOFTWARE\\SSH"
+#define SSH_ROOT L"SOFTWARE\\OpenSSH"
#define SSH_AGENT_ROOT SSH_ROOT L"\\Agent"
#define SSH_KEYS_KEY L"Keys"
-#define SSH_KEYS_ROOT SSH_ROOT L"\\" SSH_KEYS_KEY
+#define SSH_KEYS_ROOT SSH_AGENT_ROOT L"\\" SSH_KEYS_KEY
#define HEADER_SIZE 4
struct agent_connection {
OVERLAPPED ol;
HANDLE pipe_handle;
- HANDLE client_impersonation_token;
+ HANDLE client_impersonation_token;
+ HANDLE client_process_handle;
struct {
DWORD num_bytes;
DWORD transferred;
@@ -36,8 +37,9 @@ struct agent_connection {
SYSTEM, /* client is running as System */
SERVICE, /* client is running as LS or NS */
} client_type;
- HANDLE auth_token;
- HANDLE hProfile;
+ /* user profile related members */
+ HANDLE profile_token;
+ HANDLE profile_handle;
};
void agent_connection_on_io(struct agent_connection*, DWORD, OVERLAPPED*);
diff --git a/contrib/win32/win32compat/ssh-agent/agentconfig.c b/contrib/win32/win32compat/ssh-agent/agentconfig.c
index 836616e..954e4e0 100644
--- a/contrib/win32/win32compat/ssh-agent/agentconfig.c
+++ b/contrib/win32/win32compat/ssh-agent/agentconfig.c
@@ -72,6 +72,12 @@ mm_user_key_allowed(struct passwd *pw, Key *k, int i)
return 0;
}
+void* mm_auth_pubkey(const char* user_name, const struct sshkey *key,
+ const u_char *sig, size_t slen, struct sshbuf* b)
+{
+ return NULL;
+}
+
int
kexgex_server(struct ssh * sh) {
return -1;
diff --git a/contrib/win32/win32compat/ssh-agent/authagent-request.c b/contrib/win32/win32compat/ssh-agent/authagent-request.c
index 32603b9..3aafdf8 100644
--- a/contrib/win32/win32compat/ssh-agent/authagent-request.c
+++ b/contrib/win32/win32compat/ssh-agent/authagent-request.c
@@ -39,6 +39,7 @@
#include "agent-request.h"
#include "key.h"
#include "inc\utf.h"
+#include "..\priv-agent.h"
#pragma warning(push, 3)
@@ -83,9 +84,11 @@ done:
}
-void
-LoadProfile(struct agent_connection* con, wchar_t* user, wchar_t* domain) {
+static HANDLE
+LoadProfile(HANDLE user_token, wchar_t* user, wchar_t* domain) {
PROFILEINFOW profileInfo;
+ HANDLE ret = NULL;
+
profileInfo.dwFlags = PI_NOUI;
profileInfo.lpProfilePath = NULL;
profileInfo.lpUserName = user;
@@ -96,12 +99,16 @@ LoadProfile(struct agent_connection* con, wchar_t* user, wchar_t* domain) {
profileInfo.dwSize = sizeof(profileInfo);
EnablePrivilege("SeBackupPrivilege", 1);
EnablePrivilege("SeRestorePrivilege", 1);
- if (LoadUserProfileW(con->auth_token, &profileInfo) == FALSE)
+ if (LoadUserProfileW(user_token, &profileInfo) == FALSE) {
debug("Loading user (%ls,%ls) profile failed ERROR: %d", user, domain, GetLastError());
+ goto done;
+ }
else
- con->hProfile = profileInfo.hProfile;
+ ret = profileInfo.hProfile;
+done:
EnablePrivilege("SeBackupPrivilege", 0);
EnablePrivilege("SeRestorePrivilege", 0);
+ return ret;
}
#define MAX_USER_LEN 64
@@ -238,73 +245,13 @@ done:
return dup_t;
}
-/* TODO - SecureZeroMemory password */
-int process_passwordauth_request(struct sshbuf* request, struct sshbuf* response, struct agent_connection* con) {
- char *user = NULL, *domain = NULL, *pwd = NULL;
- size_t user_len, pwd_len;
- wchar_t *user_utf16 = NULL, *udom_utf16 = NULL, *pwd_utf16 = NULL, *tmp;
- int r = -1;
- HANDLE token = 0, dup_token;
-
- if (sshbuf_get_cstring(request, &user, &user_len) != 0 ||
- sshbuf_get_cstring(request, &pwd, &pwd_len) != 0 ||
- user_len == 0 ||
- pwd_len == 0 ||
- user_len > MAX_USER_LEN + MAX_FQDN_LEN ||
- pwd_len > MAX_PW_LEN) {
- debug("bad password auth request");
- goto done;
- }
-
- if ((user_utf16 = utf8_to_utf16(user)) == NULL ||
- (pwd_utf16 = utf8_to_utf16(pwd)) == NULL) {
- debug("out of memory");
- goto done;
- }
-
- if ((tmp = wcschr(user_utf16, L'@') ) != NULL ) {
- udom_utf16 = tmp + 1;
- *tmp = L'\0';
- }
-
- if (LogonUserW(user_utf16, udom_utf16, pwd_utf16, LOGON32_LOGON_NETWORK_CLEARTEXT, LOGON32_PROVIDER_DEFAULT, &token) == FALSE) {
- debug("failed to logon user: %ls domain: %ls", user_utf16, udom_utf16);
- goto done;
- }
-
- if ((dup_token = duplicate_token_for_client(con, token)) == NULL)
- goto done;
-
- if (sshbuf_put_u32(response, (int)(intptr_t)dup_token) != 0)
- goto done;
-
- con->auth_token = token;
- LoadProfile(con, user_utf16, udom_utf16);
- r = 0;
-done:
- /* TODO Fix this hacky protocol*/
- if ((r == -1) && (sshbuf_put_u8(response, SSH_AGENT_FAILURE) == 0))
- r = 0;
-
- if (user)
- free(user);
- if (pwd)
- free(pwd);
- if (user_utf16)
- free(user_utf16);
- if (pwd_utf16)
- free(pwd_utf16);
-
- return r;
-}
-
int process_pubkeyauth_request(struct sshbuf* request, struct sshbuf* response, struct agent_connection* con) {
int r = -1;
char *key_blob, *user, *sig, *blob;
size_t key_blob_len, user_len, sig_len, blob_len;
struct sshkey *key = NULL;
HANDLE token = NULL, dup_token = NULL;
- wchar_t *user_utf16 = NULL, *udom_utf16 = NULL, *tmp;
+ wchar_t *user_utf16 = NULL;
PWSTR wuser_home = NULL;
@@ -346,14 +293,6 @@ int process_pubkeyauth_request(struct sshbuf* request, struct sshbuf* response,
if (sshbuf_put_u32(response, (int)(intptr_t)dup_token) != 0)
goto done;
- con->auth_token = token;
- token = NULL;
- if ((tmp = wcschr(user_utf16, L'@')) != NULL) {
- udom_utf16 = tmp + 1;
- *tmp = L'\0';
- }
- LoadProfile(con, user_utf16, udom_utf16);
-
r = 0;
done:
/* TODO Fix this hacky protocol*/
@@ -373,7 +312,60 @@ done:
return r;
}
-int process_authagent_request(struct sshbuf* request, struct sshbuf* response, struct agent_connection* con) {
+int process_loadprofile_request(struct sshbuf* request, struct sshbuf* response, struct agent_connection* con) {
+ int r = 0, success = 0;
+ char *user;
+ size_t user_len;
+ u_int32_t user_token_int = 0;
+ HANDLE user_token = NULL;
+ wchar_t *user_utf16 = NULL, *dom_utf16 = NULL, *tmp;
+
+ /* is profile already loaded */
+ if (con->profile_handle) {
+ success = 1;
+ goto done;
+ }
+
+ if (sshbuf_get_cstring(request, &user, &user_len) != 0 ||
+ user_len > MAX_USER_LEN ||
+ sshbuf_get_u32(request, &user_token_int) != 0){
+ debug("invalid loadprofile request");
+ goto done;
+ }
+
+ if (DuplicateHandle(con->client_process_handle, (HANDLE)(INT_PTR)user_token_int, GetCurrentProcess(),
+ &user_token, TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE, FALSE, 0) == FALSE) {
+ debug("cannot duplicate user token, error: %d", GetLastError());
+ goto done;
+ }
+
+ if ((user_utf16 = utf8_to_utf16(user)) == NULL) {
+ debug("out of memory");
+ goto done;
+ }
+
+ /* split user and domain */
+ if ((tmp = wcschr(user_utf16, L'@')) != NULL) {
+ dom_utf16 = tmp + 1;
+ *tmp = L'\0';
+ }
+
+ if ((con->profile_handle = LoadProfile(user_token, user_utf16, dom_utf16)) == NULL)
+ goto done;
+
+ con->profile_token = user_token;
+ user_token = NULL;
+ success = 1;
+done:
+ if (sshbuf_put_u8(response, success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE) != 0)
+ r = -1;
+
+ if (user_token)
+ CloseHandle(user_token);
+ return r;
+}
+
+int process_privagent_request(struct sshbuf* request, struct sshbuf* response, struct agent_connection* con) {
char *opn;
size_t opn_len;
if (sshbuf_get_string_direct(request, &opn, &opn_len) != 0) {
@@ -383,14 +375,14 @@ int process_authagent_request(struct sshbuf* request, struct sshbuf* response, s
/* allow only admins and NT Service\sshd to send auth requests */
if (con->client_type != SSHD_SERVICE && con->client_type != ADMIN_USER) {
- error("cannot authenticate: client process is not admin or sshd");
+ error("cannot process request: client process is not admin or sshd");
return -1;
}
if (memcmp(opn, PUBKEY_AUTH_REQUEST, opn_len) == 0)
return process_pubkeyauth_request(request, response, con);
- else if (memcmp(opn, PASSWD_AUTH_REQUEST, opn_len) == 0)
- return process_passwordauth_request(request, response, con);
+ else if (memcmp(opn, LOAD_USER_PROFILE_REQUEST, opn_len) == 0)
+ return process_loadprofile_request(request, response, con);
else {
debug("unknown auth request: %s", opn);
return -1;
diff --git a/contrib/win32/win32compat/ssh-agent/connection.c b/contrib/win32/win32compat/ssh-agent/connection.c
index d6ae7c2..ecb71e2 100644
--- a/contrib/win32/win32compat/ssh-agent/connection.c
+++ b/contrib/win32/win32compat/ssh-agent/connection.c
@@ -30,6 +30,7 @@
*/
#include "agent.h"
#include "agent-request.h"
+#include "..\priv-agent.h"
#pragma warning(push, 3)
@@ -168,8 +169,8 @@ process_request(struct agent_connection* con)
case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
r = process_remove_all(request, response, con);
break;
- case SSH_AGENT_AUTHENTICATE:
- r = process_authagent_request(request, response, con);
+ case SSH_PRIV_AGENT_MSG_ID:
+ r = process_privagent_request(request, response, con);
break;
default:
debug("unknown agent request %d", type);
diff --git a/contrib/win32/win32compat/win32_monitor_wrap.c b/contrib/win32/win32compat/win32_monitor_wrap.c
new file mode 100644
index 0000000..01893c2
--- /dev/null
+++ b/contrib/win32/win32compat/win32_monitor_wrap.c
@@ -0,0 +1,214 @@
+/*
+* Author: Manoj Ampalam
+* mm_* routines that delegate privileged operations to privileged
+* agent.
+*
+* Copyright (c) 2015 Microsoft Corp.
+* All rights reserved
+*
+* Microsoft openssh win32 port
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* 1. Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+*
+* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "includes.h"
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef WITH_OPENSSL
+#include
+#include
+#include
+#endif
+
+#include "openbsd-compat/sys-queue.h"
+#include "xmalloc.h"
+#include "ssh.h"
+#ifdef WITH_OPENSSL
+#include "dh.h"
+#endif
+#include "buffer.h"
+#include "key.h"
+#include "cipher.h"
+#include "kex.h"
+#include "hostfile.h"
+#include "auth.h"
+#include "auth-options.h"
+#include "packet.h"
+#include "mac.h"
+#include "log.h"
+#include "auth-pam.h"
+#include "monitor_wrap.h"
+#include "atomicio.h"
+#include "monitor_fdpass.h"
+#include "misc.h"
+#include "uuencode.h"
+
+#include "channels.h"
+#include "session.h"
+#include "servconf.h"
+
+#include "ssherr.h"
+#include "priv-agent.h"
+#include "authfd.h"
+
+int priv_agent_sock = -1;
+int ssh_request_reply(int, struct sshbuf *, struct sshbuf *);
+
+/*
+ * Get socket connected to privileged agent
+ * In Windows, this is implemented within ssh-agent
+ * that server both as a key-agent (like in Unix) and
+ * privileged agent.
+ * This is a temporary accomodation until Windows has
+ * Unix like privilege separation (monitor and less
+ * privileged worker)
+ */
+int get_priv_agent_sock()
+{
+ extern int auth_sock;
+ char env_value[12]; /* enough to accomodate "ssh-agent"*/
+ size_t tmp;
+
+ if (priv_agent_sock != -1)
+ return priv_agent_sock;
+
+ /* check if auth_sock is populated and connected to "ssh-agent"*/
+ if (auth_sock != -1 &&
+ getenv_s(&tmp, env_value, 12, SSH_AUTHSOCKET_ENV_NAME) == 0 &&
+ strncmp(env_value, "ssh-agent", 12) == 0 )
+ priv_agent_sock = auth_sock;
+ else {
+ struct sockaddr_un sunaddr;
+ int sock;
+
+ memset(&sunaddr, 0, sizeof(sunaddr));
+ sunaddr.sun_family = AF_UNIX;
+ strlcpy(sunaddr.sun_path, "\\\\.\\pipe\\openssh-ssh-agent", sizeof(sunaddr.sun_path));
+
+ if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+ debug("%s: unable to create AF_UNIX socket, errno:%d", __func__, errno);
+ return -1;
+ }
+
+ /* close on exec */
+ if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1 ||
+ connect(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) {
+ close(sock);
+ debug("%s: unable to connect to privileged agent, errno:%d", __func__, errno);
+ return -1;
+ }
+
+ priv_agent_sock = sock;
+ }
+
+ return priv_agent_sock;
+}
+
+
+void* mm_auth_pubkey(const char* user_name, const struct sshkey *key,
+ const u_char *sig, size_t slen, struct sshbuf* b)
+{
+ /* Pass key challenge material to privileged agent to retrieve token upon successful authentication */
+ struct sshbuf *msg = NULL;
+ u_char *blob = NULL;
+ size_t blen = 0;
+ DWORD token = 0;
+ int agent_fd;
+
+ while (1) {
+ if ((agent_fd = get_priv_agent_sock()) == -1)
+ break;
+
+ msg = sshbuf_new();
+ if (!msg)
+ fatal("%s: out of memory", __func__);
+ if (sshbuf_put_u8(msg, SSH_PRIV_AGENT_MSG_ID) != 0 ||
+ sshbuf_put_cstring(msg, PUBKEY_AUTH_REQUEST) != 0 ||
+ sshkey_to_blob(key, &blob, &blen) != 0 ||
+ sshbuf_put_string(msg, blob, blen) != 0 ||
+ sshbuf_put_cstring(msg, user_name) != 0 ||
+ sshbuf_put_string(msg, sig, slen) != 0 ||
+ sshbuf_put_string(msg, sshbuf_ptr(b), sshbuf_len(b)) != 0 ||
+ ssh_request_reply(agent_fd, msg, msg) != 0) {
+ debug("unable to send pubkeyauth request");
+ break;
+ }
+
+ if (sshbuf_get_u32(msg, &token) != 0)
+ break;
+
+ debug3("%s authenticated via pubkey", user_name);
+ break;
+
+ }
+ if (blob)
+ free(blob);
+ if (msg)
+ sshbuf_free(msg);
+
+ return (void*)(INT_PTR)token;
+}
+
+int mm_load_profile(const char* user_name, u_int token)
+{
+ struct sshbuf *msg = NULL;
+ int agent_fd;
+ u_char result = 0;
+
+ while (1) {
+ if ((agent_fd = get_priv_agent_sock()) == -1)
+ break;
+
+ msg = sshbuf_new();
+ if (!msg)
+ fatal("%s: out of memory", __func__);
+ if (sshbuf_put_u8(msg, SSH_PRIV_AGENT_MSG_ID) != 0 ||
+ sshbuf_put_cstring(msg, LOAD_USER_PROFILE_REQUEST) != 0 ||
+ sshbuf_put_cstring(msg, user_name) != 0 ||
+ sshbuf_put_u32(msg, token) != 0 ||
+ ssh_request_reply(agent_fd, msg, msg) != 0) {
+ debug("unable to send loadprofile request %s", user_name);
+ break;
+ }
+
+ if (sshbuf_get_u8(msg, &result) != 0 || result == SSH_AGENT_FAILURE) {
+ debug("agent failed to load profile for user %s", user_name);
+ break;
+ }
+
+ break;
+
+ }
+
+ return result;
+}
\ No newline at end of file
diff --git a/contrib/win32/win32compat/wmain_common.c b/contrib/win32/win32compat/wmain_common.c
index 585442d..b78d8cf 100644
--- a/contrib/win32/win32compat/wmain_common.c
+++ b/contrib/win32/win32compat/wmain_common.c
@@ -51,7 +51,7 @@ wmain(int argc, wchar_t **wargv) {
}
if (getenv("SSH_AUTH_SOCK") == NULL)
- _putenv("SSH_AUTH_SOCK=ssh-agent");
+ _putenv("SSH_AUTH_SOCK=\\\\.\\pipe\\openssh-ssh-agent");
w32posix_initialize();
diff --git a/contrib/win32/win32compat/wmain_sshd.c b/contrib/win32/win32compat/wmain_sshd.c
index 3f1bc58..5e75d01 100644
--- a/contrib/win32/win32compat/wmain_sshd.c
+++ b/contrib/win32/win32compat/wmain_sshd.c
@@ -108,9 +108,6 @@ int sshd_main(int argc, wchar_t **wargv) {
argv[i] = utf16_to_utf8(wargv[i]);
}
- if (getenv("SSH_AUTH_SOCK") == NULL)
- _putenv("SSH_AUTH_SOCK=ssh-agent");
-
w32posix_initialize();
if (getenv("SSHD_REMSOC"))
is_child = 1;
diff --git a/monitor_wrap.h b/monitor_wrap.h
index 9e032d2..72ba1cd 100644
--- a/monitor_wrap.h
+++ b/monitor_wrap.h
@@ -98,4 +98,9 @@ int mm_bsdauth_respond(void *, u_int, char **);
int mm_skey_query(void *, char **, char **, u_int *, char ***, u_int **);
int mm_skey_respond(void *, u_int, char **);
+/* Windows specific */
+void* mm_auth_pubkey(const char*, const struct sshkey *, const u_char *, size_t,
+ struct sshbuf*);
+int mm_load_profile(const char*, u_int );
+
#endif /* _MM_WRAP_H_ */
diff --git a/regress/pesterTests/Authorized_keys_fileperm.Tests.ps1 b/regress/pesterTests/Authorized_keys_fileperm.Tests.ps1
index ffbcb1b..d1f43fe 100644
--- a/regress/pesterTests/Authorized_keys_fileperm.Tests.ps1
+++ b/regress/pesterTests/Authorized_keys_fileperm.Tests.ps1
@@ -1,4 +1,6 @@
-Import-Module $PSScriptRoot\CommonUtils.psm1 -Force -DisableNameChecking
+If ($PSVersiontable.PSVersion.Major -le 2) {$PSScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path}
+Import-Module $PSScriptRoot\CommonUtils.psm1 -Force
+Import-Module OpenSSHUtils -Force
$tC = 1
$tI = 0
$suite = "authorized_keys_fileperm"
@@ -6,7 +8,7 @@ Describe "Tests for authorized_keys file permission" -Tags "CI" {
BeforeAll {
if($OpenSSHTestInfo -eq $null)
{
- Throw "`$OpenSSHTestInfo is null. Please run Setup-OpenSSHTestEnvironment to setup test environment."
+ Throw "`$OpenSSHTestInfo is null. Please run Set-OpenSSHTestEnvironment to set test environments."
}
$testDir = "$($OpenSSHTestInfo["TestDataPath"])\$suite"
@@ -22,17 +24,31 @@ Describe "Tests for authorized_keys file permission" -Tags "CI" {
$ssouser = $OpenSSHTestInfo["SSOUser"]
$PwdUser = $OpenSSHTestInfo["PasswdUser"]
$ssouserProfile = $OpenSSHTestInfo["SSOUserProfile"]
- Remove-Item -Path (Join-Path $testDir "*$fileName") -Force -ErrorAction ignore
+ Remove-Item -Path (Join-Path $testDir "*$fileName") -Force -ErrorAction SilentlyContinue
+ $platform = Get-Platform
+ $skip = ($platform -eq [PlatformType]::Windows) -and ($PSVersionTable.PSVersion.Major -le 2)
+ if(($platform -eq [PlatformType]::Windows) -and ($psversiontable.BuildVersion.Major -le 6))
+ {
+ #suppress the firewall blocking dialogue on win7
+ netsh advfirewall firewall add rule name="sshd" program="$($OpenSSHTestInfo['OpenSSHBinPath'])\sshd.exe" protocol=any action=allow dir=in
+ }
}
AfterEach { $tI++ }
+
+ AfterAll {
+ if(($platform -eq [PlatformType]::Windows) -and ($psversiontable.BuildVersion.Major -le 6))
+ {
+ netsh advfirewall firewall delete rule name="sshd" program="$($OpenSSHTestInfo['OpenSSHBinPath'])\sshd.exe" protocol=any dir=in
+ }
+ }
Context "Authorized key file permission" {
BeforeAll {
- $systemAccount = New-Object System.Security.Principal.NTAccount("NT AUTHORITY", "SYSTEM")
- $adminAccount = New-Object System.Security.Principal.NTAccount("BUILTIN","Administrators")
- $objUser = New-Object System.Security.Principal.NTAccount($ssouser)
- $currentUser = New-Object System.Security.Principal.NTAccount($($env:USERDOMAIN), $($env:USERNAME))
+ $systemSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::LocalSystemSid)
+ $adminsSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::BuiltinAdministratorsSid)
+ $currentUserSid = Get-UserSID -User "$($env:USERDOMAIN)\$($env:USERNAME)"
+ $objUserSid = Get-UserSID -User $ssouser
$ssouserSSHProfilePath = Join-Path $ssouserProfile .testssh
if(-not (Test-Path $ssouserSSHProfilePath -PathType Container)) {
@@ -43,21 +59,22 @@ Describe "Tests for authorized_keys file permission" -Tags "CI" {
$testknownhosts = Join-path $PSScriptRoot testdata\test_known_hosts
Copy-Item $Source $ssouserSSHProfilePath -Force -ErrorAction Stop
- Adjust-UserKeyFileACL -Filepath $authorizedkeyPath -Owner $objUser -OwnerPerms "Read, Write"
+ Repair-AuthorizedKeyPermission -Filepath $authorizedkeyPath -confirm:$false
- Get-Process -Name sshd | Where-Object {$_.SI -ne 0} | Stop-process
+ Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
#add wrong password so ssh does not prompt password if failed with authorized keys
Add-PasswordSetting -Pass "WrongPass"
$tI=1
}
AfterAll {
+ Repair-AuthorizedKeyPermission -Filepath $authorizedkeyPath -confirm:$false
if(Test-Path $authorizedkeyPath) {
- Adjust-UserKeyFileACL -Filepath $authorizedkeyPath -Owner $objUser -OwnerPerms "Read, Write"
- Remove-Item $authorizedkeyPath -Force -ErrorAction Ignore
+ Repair-AuthorizedKeyPermission -Filepath $authorizedkeyPath -confirm:$false
+ Remove-Item $authorizedkeyPath -Force -ErrorAction SilentlyContinue
}
if(Test-Path $ssouserSSHProfilePath) {
- Remove-Item $ssouserSSHProfilePath -Force -ErrorAction Ignore -Recurse
+ Remove-Item $ssouserSSHProfilePath -Force -ErrorAction SilentlyContinue -Recurse
}
Remove-PasswordSetting
$tC++
@@ -66,11 +83,12 @@ Describe "Tests for authorized_keys file permission" -Tags "CI" {
BeforeEach {
$filePath = Join-Path $testDir "$tC.$tI.$fileName"
$logPath = Join-Path $testDir "$tC.$tI.$logName"
+ Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
}
It "$tC.$tI-authorized_keys-positive(pwd user is the owner and running process can access to the file)" {
#setup to have ssouser as owner and grant ssouser read and write, admins group, and local system full control
- Adjust-UserKeyFileACL -Filepath $authorizedkeyPath -Owner $objUser -OwnerPerms "Read, Write"
+ Repair-FilePermission -Filepath $authorizedkeyPath -Owners $objUserSid -FullAccessNeeded $adminsSid,$systemSid,$objUserSid -confirm:$false
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-p $port", "-o `"AuthorizedKeysFile .testssh/authorized_keys`"", "-E $logPath") -NoNewWindow
@@ -78,14 +96,12 @@ Describe "Tests for authorized_keys file permission" -Tags "CI" {
$o | Should Be "1234"
#Cleanup
- Get-Process -Name sshd | % { if($_.SI -ne 0) { Start-sleep 1; Stop-Process $_; Start-sleep 1 } }
+ Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
}
It "$tC.$tI-authorized_keys-positive(authorized_keys is owned by local system)" {
#setup to have system as owner and grant it full control
- Set-FileOwnerAndACL -Filepath $authorizedkeyPath -Owner $systemAccount -OwnerPerms "FullControl"
- Add-PermissionToFileACL -FilePath $authorizedkeyPath -User $adminAccount -Perms "FullControl"
- Add-PermissionToFileACL -FilePath $authorizedkeyPath -User $objUser -Perms "Read, Write"
+ Repair-FilePermission -Filepath $authorizedkeyPath -Owner $systemSid -FullAccessNeeded $adminsSid,$systemSid,$objUserSid -confirm:$false
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-p $port", "-o `"AuthorizedKeysFile .testssh/authorized_keys`"", "-E $logPath") -NoNewWindow
@@ -93,14 +109,12 @@ Describe "Tests for authorized_keys file permission" -Tags "CI" {
$o | Should Be "1234"
#Cleanup
- Get-Process -Name sshd | % { if($_.SI -ne 0) { Start-sleep 1; Stop-Process $_; Start-sleep 1 } }
+ Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
}
It "$tC.$tI-authorized_keys-positive(authorized_keys is owned by admins group and pwd does not have explict ACE)" {
- #setup to have admin group as owner and grant it full control
-
- Set-FileOwnerAndACL -Filepath $authorizedkeyPath -Owner $adminAccount -OwnerPerms "FullControl"
- Add-PermissionToFileACL -FilePath $authorizedkeyPath -User $systemAccount -Perms "FullControl"
+ #setup to have admin group as owner and grant it full control
+ Repair-FilePermission -Filepath $authorizedkeyPath -Owner $adminsSid -FullAccessNeeded $adminsSid,$systemSid -confirm:$false
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-p $port", "-o `"AuthorizedKeysFile .testssh/authorized_keys`"", "-E $logPath") -NoNewWindow
@@ -108,15 +122,12 @@ Describe "Tests for authorized_keys file permission" -Tags "CI" {
$o | Should Be "1234"
#Cleanup
- Get-Process -Name sshd | % { if($_.SI -ne 0) { Start-sleep 1; Stop-Process $_; Start-sleep 1 } }
+ Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
}
It "$tC.$tI-authorized_keys-positive(authorized_keys is owned by admins group and pwd have explict ACE)" {
#setup to have admin group as owner and grant it full control
-
- Set-FileOwnerAndACL -Filepath $authorizedkeyPath -Owner $adminAccount -OwnerPerms "FullControl"
- Add-PermissionToFileACL -FilePath $authorizedkeyPath -User $systemAccount -Perms "FullControl"
- Add-PermissionToFileACL -FilePath $authorizedkeyPath -User $objUser -Perms "Read, Write"
+ Repair-FilePermission -Filepath $authorizedkeyPath -Owner $adminsSid -FullAccessNeeded $adminsSid,$systemSid,$objUserSid -confirm:$false
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-p $port", "-o `"AuthorizedKeysFile .testssh/authorized_keys`"", "-E $logPath") -NoNewWindow
@@ -124,14 +135,12 @@ Describe "Tests for authorized_keys file permission" -Tags "CI" {
$o | Should Be "1234"
#Cleanup
- Get-Process -Name sshd | % { if($_.SI -ne 0) { Start-sleep 1; Stop-Process $_; Start-sleep 1 } }
+ Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
}
It "$tC.$tI-authorized_keys-negative(authorized_keys is owned by other admin user)" {
#setup to have current user (admin user) as owner and grant it full control
- Set-FileOwnerAndACL -Filepath $authorizedkeyPath -Owner $currentUser -OwnerPerms "Read","Write"
- Add-PermissionToFileACL -FilePath $authorizedkeyPath -User $systemAccount -Perms "FullControl"
- Add-PermissionToFileACL -FilePath $authorizedkeyPath -User $adminAccount -Perms "FullControl"
+ Repair-FilePermission -Filepath $authorizedkeyPath -Owner $currentUserSid -FullAccessNeeded $adminsSid,$systemSid -confirm:$false
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-p $port", "-o `"AuthorizedKeysFile .testssh/authorized_keys`"", "-E $logPath") -NoNewWindow
@@ -141,18 +150,16 @@ Describe "Tests for authorized_keys file permission" -Tags "CI" {
$matches.Count | Should BeGreaterThan 2
#Cleanup
- Get-Process -Name sshd | % { if($_.SI -ne 0) { Start-sleep 1; Stop-Process $_; Start-sleep 1 } }
+ Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
}
It "$tC.$tI-authorized_keys-negative(other account can access private key file)" {
- #setup to have current user as owner and grant it full control
- Set-FileOwnerAndACL -Filepath $authorizedkeyPath -Owner $objUser -OwnerPerms "Read","Write"
- Add-PermissionToFileACL -FilePath $authorizedkeyPath -User $systemAccount -Perms "FullControl"
- Add-PermissionToFileACL -FilePath $authorizedkeyPath -User $adminAccount -Perms "FullControl"
+ #setup to have current user as owner and grant it full control
+ Repair-FilePermission -Filepath $authorizedkeyPath -Owner $objUserSid -FullAccessNeeded $adminsSid,$systemSid,$objUserSid -confirm:$false
#add $PwdUser to access the file authorized_keys
- $objPwdUser = New-Object System.Security.Principal.NTAccount($PwdUser)
- Add-PermissionToFileACL -FilePath $authorizedkeyPath -User $objPwdUser -Perm "Read"
+ $objPwdUserSid = Get-UserSid -User $PwdUser
+ Set-FilePermission -FilePath $authorizedkeyPath -User $objPwdUserSid -Perm "Read"
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-p $port", "-o `"AuthorizedKeysFile .testssh/authorized_keys`"", "-E $logPath") -NoNewWindow
@@ -162,15 +169,13 @@ Describe "Tests for authorized_keys file permission" -Tags "CI" {
$matches.Count | Should BeGreaterThan 2
#Cleanup
- Get-Process -Name sshd | % { if($_.SI -ne 0) { Start-sleep 1; Stop-Process $_; Start-sleep 1 } }
+ Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
}
It "$tC.$tI-authorized_keys-negative(authorized_keys is owned by other non-admin user)" {
- #setup to have PwdUser as owner and grant it full control
- $objPwdUser = New-Object System.Security.Principal.NTAccount($PwdUser)
- Set-FileOwnerAndACL -Filepath $authorizedkeyPath -owner $objPwdUser -OwnerPerms "Read","Write"
- Add-PermissionToFileACL -FilePath $authorizedkeyPath -User $systemAccount -Perms "FullControl"
- Add-PermissionToFileACL -FilePath $authorizedkeyPath -User $adminAccount -Perms "FullControl"
+ #setup to have PwdUser as owner and grant it full control
+ $objPwdUserSid = Get-UserSid -User $PwdUser
+ Repair-FilePermission -Filepath $authorizedkeyPath -Owner $objPwdUserSid -FullAccessNeeded $adminsSid,$systemSid,$objPwdUser -confirm:$false
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-p $port", "-o `"AuthorizedKeysFile .testssh/authorized_keys`"", "-E $logPath") -NoNewWindow
@@ -180,12 +185,12 @@ Describe "Tests for authorized_keys file permission" -Tags "CI" {
$matches.Count | Should BeGreaterThan 2
#Cleanup
- Get-Process -Name sshd | % { if($_.SI -ne 0) { Start-sleep 1; Stop-Process $_; Start-sleep 1 } }
+ Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
}
- It "$tC.$tI-authorized_keys-negative(the running process does not have read access to the authorized_keys)" {
+ It "$tC.$tI-authorized_keys-negative(the running process does not have read access to the authorized_keys)" -skip:$skip {
#setup to have ssouser as owner and grant it full control
- Set-FileOwnerAndACL -Filepath $authorizedkeyPath -Owner $objUser -OwnerPerms "Read","Write"
- Add-PermissionToFileACL -FilePath $authorizedkeyPath -User $systemAccount -Perms "FullControl"
+ Repair-FilePermission -Filepath $authorizedkeyPath -Owner $objUserSid -FullAccessNeeded $systemSid,$objUserSid -confirm:$false
+ Set-FilePermission -Filepath $authorizedkeyPath -UserSid $adminsSid -Action Delete
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-p $port", "-o `"AuthorizedKeysFile .testssh/authorized_keys`"", "-E $logPath") -NoNewWindow
@@ -196,7 +201,7 @@ Describe "Tests for authorized_keys file permission" -Tags "CI" {
$matches.Count | Should BeGreaterThan 2
#Cleanup
- Get-Process -Name sshd | % { if($_.SI -ne 0) { Start-sleep 1; Stop-Process $_; Start-sleep 1 } }
+ Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
}
}
}
diff --git a/regress/pesterTests/Cfginclude.Tests.ps1 b/regress/pesterTests/Cfginclude.Tests.ps1
index 59ac559..3075565 100644
--- a/regress/pesterTests/Cfginclude.Tests.ps1
+++ b/regress/pesterTests/Cfginclude.Tests.ps1
@@ -1,4 +1,5 @@
-Import-Module $PSScriptRoot\CommonUtils.psm1 -Force -DisableNameChecking
+If ($PSVersiontable.PSVersion.Major -le 2) {$PSScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path}
+Import-Module $PSScriptRoot\CommonUtils.psm1 -Force
$tC = 1
$tI = 0
$suite = "authorized_keys_fileperm"
@@ -6,7 +7,7 @@ Describe "Tests for ssh config" -Tags "CI" {
BeforeAll {
if($OpenSSHTestInfo -eq $null)
{
- Throw "`$OpenSSHTestInfo is null. Please run Setup-OpenSSHTestEnvironment to setup test environment."
+ Throw "`$OpenSSHTestInfo is null. Please run Set-OpenSSHTestEnvironment to set test environments."
}
if(-not (Test-Path $OpenSSHTestInfo["TestDataPath"]))
@@ -27,38 +28,39 @@ Describe "Tests for ssh config" -Tags "CI" {
# 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
- Remove-Item -Path (Join-Path $testDir "*log*.log") -Force -ErrorAction ignore
+ Clear-Content "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\ssh-agent.log" -Force -ErrorAction SilentlyContinue
+ Clear-Content "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\sshd.log" -Force -ErrorAction SilentlyContinue
+ Remove-Item -Path (Join-Path $testDir "*log*.log") -Force -ErrorAction SilentlyContinue
}
- Remove-Item -Path (Join-Path $testDir "*logName") -Force -ErrorAction ignore
+ Remove-Item -Path (Join-Path $testDir "*logName") -Force -ErrorAction SilentlyContinue
}
AfterEach {
if( $OpenSSHTestInfo["DebugMode"])
{
- Copy-Item "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\ssh-agent.log" "$testDir\agentlog$tC.$tI.log" -Force -ErrorAction ignore
- Copy-Item "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\sshd.log" "$testDir\sshdlog$tC.$tI.log" -Force -ErrorAction ignore
+ Copy-Item "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\ssh-agent.log" "$testDir\agentlog$tC.$tI.log" -Force -ErrorAction SilentlyContinue
+ Copy-Item "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\sshd.log" "$testDir\sshdlog$tC.$tI.log" -Force -ErrorAction SilentlyContinue
#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\ssh-agent.log" -Force -ErrorAction SilentlyContinue
+ Clear-Content "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\sshd.log" -Force -ErrorAction SilentlyContinue
}
$tI++
}
Context "$tC-User SSHConfig--ReadConfig" {
BeforeAll {
- $systemAccount = New-Object System.Security.Principal.NTAccount("NT AUTHORITY", "SYSTEM")
- $adminAccount = New-Object System.Security.Principal.NTAccount("BUILTIN","Administrators")
- $objUser = New-Object System.Security.Principal.NTAccount($ssouser)
- $currentUser = New-Object System.Security.Principal.NTAccount($($env:USERDOMAIN), $($env:USERNAME))
+ $systemSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::LocalSystemSid)
+ $adminsSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::BuiltinAdministratorsSid)
+ $currentUserSid = Get-UserSID -User "$($env:USERDOMAIN)\$($env:USERNAME)"
+ $objUserSid = Get-UserSID -User $ssouser
$userConfigFile = Join-Path $home ".ssh\config"
if( -not (Test-path $userConfigFile) ) {
Copy-item "$PSScriptRoot\testdata\ssh_config" $userConfigFile -force
}
+ Enable-Privilege SeRestorePrivilege | out-null
$oldACL = Get-ACL $userConfigFile
$tI=1
}
@@ -67,8 +69,8 @@ Describe "Tests for ssh config" -Tags "CI" {
$logPath = Join-Path $testDir "$tC.$tI.$logName"
}
- AfterEach {
- Set-Acl -Path $userConfigFile -AclObject $oldACL
+ AfterEach {
+ Set-Acl -Path $userConfigFile -AclObject $oldACL -confirm:$false
}
AfterAll {
@@ -77,9 +79,7 @@ Describe "Tests for ssh config" -Tags "CI" {
It "$tC.$tI-User SSHConfig-ReadConfig positive (current logon user is the owner)" {
#setup
- Set-FileOwnerAndACL -Filepath $userConfigFile -Owner $currentUser -OwnerPerms "Read","Write"
- Add-PermissionToFileACL -FilePath $userConfigFile -User $systemAccount -Perms "FullControl"
- Add-PermissionToFileACL -FilePath $userConfigFile -User $adminAccount -Perms "FullControl"
+ Repair-FilePermission -Filepath $userConfigFile -Owners $currentUserSid -FullAccessNeeded $adminsSid,$systemSid,$currentUserSid -confirm:$false
#Run
$o = ssh test_target echo 1234
@@ -88,8 +88,7 @@ Describe "Tests for ssh config" -Tags "CI" {
It "$tC.$tI-User SSHConfig-ReadConfig positive (local system is the owner)" {
#setup
- Set-FileOwnerAndACL -Filepath $userConfigFile -Owner $systemAccount -OwnerPerms "FullControl"
- Add-PermissionToFileACL -FilePath $userConfigFile -User $adminAccount -Perms "FullControl"
+ Repair-FilePermission -Filepath $userConfigFile -Owners $systemSid -FullAccessNeeded $adminsSid,$systemSid -confirm:$false
#Run
$o = ssh test_target echo 1234
@@ -98,8 +97,8 @@ Describe "Tests for ssh config" -Tags "CI" {
It "$tC.$tI-User SSHConfig-ReadConfig positive (admin is the owner and current user has no explict ACE)" {
#setup
- Set-FileOwnerAndACL -Filepath $userConfigFile -Owner $adminAccount -OwnerPerms "FullControl"
- Add-PermissionToFileACL -FilePath $userConfigFile -User $systemAccount -Perms "FullControl"
+ Repair-FilePermission -Filepath $userConfigFile -Owners $adminsSid -FullAccessNeeded $adminsSid,$systemSid -confirm:$false
+ Set-FilePermission -Filepath $userConfigFile -UserSid $currentUserSid -Action Delete
#Run
$o = ssh test_target echo 1234
@@ -108,10 +107,8 @@ Describe "Tests for ssh config" -Tags "CI" {
It "$tC.$tI-User SSHConfig-ReadConfig positive (admin is the owner and current user has explict ACE)" {
#setup
- Set-FileOwnerAndACL -Filepath $userConfigFile -Owner $adminAccount -OwnerPerms "FullControl"
- Add-PermissionToFileACL -FilePath $userConfigFile -User $systemAccount -Perms "FullControl"
- Add-PermissionToFileACL -FilePath $userConfigFile -User $currentUser -Perms "Read, Write"
-
+ Repair-FilePermission -Filepath $userConfigFile -Owners $adminsSid -FullAccessNeeded $adminsSid,$systemSid,$currentUserSid -confirm:$false
+
#Run
$o = ssh test_target echo 1234
$o | Should Be "1234"
@@ -119,9 +116,7 @@ Describe "Tests for ssh config" -Tags "CI" {
It "$tC.$tI-User SSHConfig-ReadConfig negative (wrong owner)" {
#setup
- Set-FileOwnerAndACL -Filepath $userConfigFile -Owner $ssouser -OwnerPerms "Read","Write"
- Add-PermissionToFileACL -FilePath $userConfigFile -User $systemAccount -Perms "FullControl"
- Add-PermissionToFileACL -FilePath $userConfigFile -User $adminAccount -Perms "FullControl"
+ Repair-FilePermission -Filepath $userConfigFile -Owners $objUserSid -FullAccessNeeded $adminsSid,$systemSid,$objUserSid -confirm:$false
#Run
cmd /c "ssh test_target echo 1234 2> $logPath"
@@ -131,10 +126,7 @@ Describe "Tests for ssh config" -Tags "CI" {
It "$tC.$tI-User SSHConfig-ReadConfig negative (others has permission)" {
#setup
- Set-FileOwnerAndACL -Filepath $userConfigFile -Owner $currentUser -OwnerPerms "Read","Write"
- Add-PermissionToFileACL -FilePath $userConfigFile -User $systemAccount -Perms "FullControl"
- Add-PermissionToFileACL -FilePath $userConfigFile -User $adminAccount -Perms "FullControl"
- Add-PermissionToFileACL -FilePath $userConfigFile -User $objUser -Perms "Read"
+ Repair-FilePermission -Filepath $userConfigFile -Owners $currentUserSid -FullAccessNeeded $adminsSid,$systemSid,$currentUserSid -ReadAccessNeeded $objUserSid -confirm:$false
#Run
cmd /c "ssh test_target echo 1234 2> $logPath"
diff --git a/regress/pesterTests/CommonUtils.psm1 b/regress/pesterTests/CommonUtils.psm1
index 49f345a..ffcd1f8 100644
--- a/regress/pesterTests/CommonUtils.psm1
+++ b/regress/pesterTests/CommonUtils.psm1
@@ -1,8 +1,13 @@
-Enum PlatformType {
- Windows
- Linux
- OSX
-}
+Import-Module OpenSSHUtils -Force
+
+Add-Type -TypeDefinition @"
+ public enum PlatformType
+ {
+ Windows,
+ Linux,
+ OSX
+ }
+"@
function Get-Platform {
# Use the .NET Core APIs to determine the current platform; if a runtime
@@ -31,157 +36,59 @@ function Get-Platform {
}
}
-<#
-.Synopsis
- user key should be owned by current user account
- private key can be accessed only by the file owner, localsystem and Administrators
- public user key can be accessed by only file owner, localsystem and Administrators and read by everyone
-
-.Outputs
- N/A
-
-.Inputs
- FilePath - The path to the file
- Owner - The file owner
- OwnerPerms - The permissions grant to owner
-#>
-function Adjust-UserKeyFileACL
-{
- param (
- [parameter(Mandatory=$true)]
- [string]$FilePath,
- [System.Security.Principal.NTAccount] $Owner = $null,
- [System.Security.AccessControl.FileSystemRights[]] $OwnerPerms = $null
- )
-
- $myACL = Get-ACL $FilePath
- $myACL.SetAccessRuleProtection($True, $FALSE)
- Set-Acl -Path $FilePath -AclObject $myACL
-
- $systemAccount = New-Object System.Security.Principal.NTAccount("NT AUTHORITY", "SYSTEM")
- $adminAccount = New-Object System.Security.Principal.NTAccount("BUILTIN","Administrators")
- $everyoneAccount = New-Object System.Security.Principal.NTAccount("EveryOne")
- $myACL = Get-ACL $FilePath
-
- $actualOwner = $null
- if($Owner -eq $null)
- {
- $actualOwner = New-Object System.Security.Principal.NTAccount($($env:USERDOMAIN), $($env:USERNAME))
- }
- else
- {
- $actualOwner = $Owner
- }
-
- $myACL.SetOwner($actualOwner)
-
- if($myACL.Access)
- {
- $myACL.Access | % {
- if(-not ($myACL.RemoveAccessRule($_)))
- {
- throw "failed to remove access of $($_.IdentityReference.Value) rule in setup "
- }
- }
- }
-
- $adminACE = New-Object System.Security.AccessControl.FileSystemAccessRule `
- ($adminAccount, "FullControl", "None", "None", "Allow")
- $myACL.AddAccessRule($adminACE)
-
- $systemACE = New-Object System.Security.AccessControl.FileSystemAccessRule `
- ($systemAccount, "FullControl", "None", "None", "Allow")
- $myACL.AddAccessRule($systemACE)
-
- if(-not ($actualOwner.Equals($adminAccount)) -and (-not $actualOwner.Equals($systemAccount)) -and $OwnerPerms)
- {
- $OwnerPerms | % {
- $ownerACE = New-Object System.Security.AccessControl.FileSystemAccessRule `
- ($actualOwner, $_, "None", "None", "Allow")
- $myACL.AddAccessRule($ownerACE)
- }
- }
-
- if($FilePath.EndsWith(".pub"))
- {
- $everyoneAce = New-Object System.Security.AccessControl.FileSystemAccessRule `
- ("Everyone", "Read", "None", "None", "Allow")
- $myACL.AddAccessRule($everyoneAce)
- }
-
- Set-Acl -Path $FilePath -AclObject $myACL
-}
-
-function Set-FileOwnerAndACL
-{
- param(
- [parameter(Mandatory=$true)]
- [string]$FilePath,
- [System.Security.Principal.NTAccount]$Owner = $null,
- [System.Security.AccessControl.FileSystemRights[]] $OwnerPerms = @("Read", "Write")
- )
-
- $myACL = Get-ACL -Path $FilePath
- $myACL.SetAccessRuleProtection($True, $FALSE)
- Set-Acl -Path $FilePath -AclObject $myACL
-
- $myACL = Get-ACL $FilePath
- $actualOwner = $null
- if($owner -eq $null)
- {
- $actualOwner = New-Object System.Security.Principal.NTAccount($($env:USERDOMAIN), $($env:USERNAME))
- }
- else
- {
- $actualOwner = $Owner
- }
-
- $myACL.SetOwner($actualOwner)
-
- if($myACL.Access)
- {
- $myACL.Access | % {
- if(-not ($myACL.RemoveAccessRule($_)))
- {
- throw "failed to remove access of $($_.IdentityReference.Value) rule in setup "
- }
- }
- }
-
- if($OwnerPerms)
- {
- $OwnerPerms | % {
- $ownerACE = New-Object System.Security.AccessControl.FileSystemAccessRule `
- ($actualOwner, $_, "None", "None", "Allow")
- $myACL.AddAccessRule($ownerACE)
- }
- }
-
- Set-Acl -Path $FilePath -AclObject $myACL
-}
-
-function Add-PermissionToFileACL
+function Set-FilePermission
{
param(
[parameter(Mandatory=$true)]
[string]$FilePath,
- [System.Security.Principal.NTAccount] $User,
+ [parameter(Mandatory=$true)]
+ [System.Security.Principal.SecurityIdentifier] $UserSid,
[System.Security.AccessControl.FileSystemRights[]]$Perms,
- [System.Security.AccessControl.AccessControlType] $AccessType = "Allow"
+ [System.Security.AccessControl.AccessControlType] $AccessType = "Allow",
+ [ValidateSet("Add", "Delete")]
+ [string]$Action = "Add"
)
$myACL = Get-ACL $FilePath
-
- if($Perms)
+ $account = Get-UserAccount -UserSid $UserSid
+ if($Action -ieq "Delete")
+ {
+ $myACL.SetAccessRuleProtection($True, $True)
+ Enable-Privilege SeRestorePrivilege | out-null
+ Set-Acl -Path $FilePath -AclObject $myACL
+ $myACL = Get-ACL $FilePath
+
+ if($myACL.Access)
+ {
+ $myACL.Access | % {
+ if($_.IdentityReference.Equals($account))
+ {
+ if($_.IsInherited)
+ {
+ $myACL.SetAccessRuleProtection($True, $True)
+ Enable-Privilege SeRestorePrivilege | out-null
+ Set-Acl -Path $FilePath -AclObject $myACL
+ $myACL = Get-ACL $FilePath
+ }
+
+ if(-not ($myACL.RemoveAccessRule($_)))
+ {
+ throw "failed to remove access of $($_.IdentityReference) rule in setup "
+ }
+ }
+ }
+ }
+ }
+ elseif($Perms)
{
$Perms | % {
$userACE = New-Object System.Security.AccessControl.FileSystemAccessRule `
- ($User, $_, "None", "None", $AccessType)
+ ($UserSid, $_, "None", "None", $AccessType)
$myACL.AddAccessRule($userACE)
}
- }
-
- Set-Acl -Path $FilePath -AclObject $myACL
+ }
+ Enable-Privilege SeRestorePrivilege | out-null
+ Set-Acl -Path $FilePath -AclObject $myACL -confirm:$false
}
function Add-PasswordSetting
diff --git a/regress/pesterTests/Hostkey_fileperm.Tests.ps1 b/regress/pesterTests/Hostkey_fileperm.Tests.ps1
index 365bb20..0bb7bc4 100644
--- a/regress/pesterTests/Hostkey_fileperm.Tests.ps1
+++ b/regress/pesterTests/Hostkey_fileperm.Tests.ps1
@@ -1,4 +1,5 @@
-Import-Module $PSScriptRoot\CommonUtils.psm1 -Force -DisableNameChecking
+If ($PSVersiontable.PSVersion.Major -le 2) {$PSScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path}
+Import-Module $PSScriptRoot\CommonUtils.psm1 -Force
$tC = 1
$tI = 0
$suite = "hostkey_fileperm"
@@ -6,7 +7,7 @@ Describe "Tests for host keys file permission" -Tags "CI" {
BeforeAll {
if($OpenSSHTestInfo -eq $null)
{
- Throw "`$OpenSSHTestInfo is null. Please run Setup-OpenSSHTestEnvironment to setup test environment."
+ Throw "`$OpenSSHTestInfo is null. Please run Set-OpenSSHTestEnvironment to set test environments."
}
$testDir = "$($OpenSSHTestInfo["TestDataPath"])\$suite"
@@ -19,30 +20,57 @@ Describe "Tests for host keys file permission" -Tags "CI" {
$port = 47003
$ssouser = $OpenSSHTestInfo["SSOUser"]
$script:logNum = 0
- Remove-Item -Path (Join-Path $testDir "*$logName") -Force -ErrorAction ignore
+ Remove-Item -Path (Join-Path $testDir "*$logName") -Force -ErrorAction SilentlyContinue
+ $platform = Get-Platform
+ $skip = ($platform -eq [PlatformType]::Windows) -and ($PSVersionTable.PSVersion.Major -le 2)
+ if(($platform -eq [PlatformType]::Windows) -and ($psversiontable.BuildVersion.Major -le 6))
+ {
+ #suppress the firewall blocking dialogue on win7
+ netsh advfirewall firewall add rule name="sshd" program="$($OpenSSHTestInfo['OpenSSHBinPath'])\sshd.exe" protocol=any action=allow dir=in
+ }
}
AfterEach { $tI++ }
+ AfterAll {
+ if(($platform -eq [PlatformType]::Windows) -and ($psversiontable.BuildVersion.Major -le 6))
+ {
+ netsh advfirewall firewall delete rule name="sshd" program="$($OpenSSHTestInfo['OpenSSHBinPath'])\sshd.exe" protocol=any dir=in
+ }
+ }
Context "$tC - Host key files permission" {
BeforeAll {
- $systemAccount = New-Object System.Security.Principal.NTAccount("NT AUTHORITY", "SYSTEM")
- $adminAccount = New-Object System.Security.Principal.NTAccount("BUILTIN","Administrators")
- $objUser = New-Object System.Security.Principal.NTAccount($ssouser)
- $currentUser = New-Object System.Security.Principal.NTAccount($($env:USERDOMAIN), $($env:USERNAME))
- $everyone = New-Object System.Security.Principal.NTAccount("EveryOne")
+ $systemSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::LocalSystemSid)
+ $adminsSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::BuiltinAdministratorsSid)
+ $currentUserSid = Get-UserSID -User "$($env:USERDOMAIN)\$($env:USERNAME)"
+ $objUserSid = Get-UserSID -User $ssouser
+ $everyoneSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::WorldSid)
$hostKeyFilePath = join-path $testDir hostkeyFilePermTest_ed25519_key
if(Test-path $hostKeyFilePath -PathType Leaf) {
- Set-FileOwnerAndACL -filepath $hostKeyFilePath
+ Repair-SshdHostKeyPermission -filepath $hostKeyFilePath -confirm:$false
}
- if(Test-path "$hostKeyFilePath.pub" -PathType Leaf){
- Set-FileOwnerAndACL -filepath "$hostKeyFilePath.pub"
- }
- Remove-Item -path "$hostKeyFilePath*" -Force -ErrorAction Ignore
+ Remove-Item -path "$hostKeyFilePath*" -Force -ErrorAction SilentlyContinue
ssh-keygen.exe -t ed25519 -f $hostKeyFilePath -P `"`"
- Get-Process -Name sshd | Where-Object {$_.SI -ne 0} | Stop-process
+ Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
$tI=1
+
+ function WaitForValidation
+ {
+ param([string]$logPath, [int]$length)
+ $num = 0
+ while((-not (Test-Path $logPath -PathType leaf)) -or ((Get-item $logPath).Length -lt $length) -and ($num++ -lt 4))
+ {
+ Start-Sleep -Milliseconds 1000
+ }
+ Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
+
+ $num = 0
+ while ([string]::IsNullorEmpty($(Get-Content $logPath -ErrorAction SilentlyContinue | Out-String)) -and ($num++ -lt 4))
+ {
+ Start-Sleep -Milliseconds 1000
+ }
+ }
}
BeforeEach {
@@ -50,76 +78,59 @@ Describe "Tests for host keys file permission" -Tags "CI" {
}
AfterAll {
- if(Test-path $hostKeyFilePath -PathType Leaf){
- Adjust-UserKeyFileACL -Filepath $hostKeyFilePath -Owner $systemAccount
- }
- if(Test-path "$hostKeyFilePath.pub" -PathType Leaf){
- Adjust-UserKeyFileACL -Filepath "$hostKeyFilePath.pub" -Owner $systemAccount
+ if(Test-path $hostKeyFilePath -PathType Leaf) {
+ Repair-SshdHostKeyPermission -filepath $hostKeyFilePath -confirm:$false
}
$tC++
}
- It "$tC.$tI-Host keys-positive (both public and private keys are owned by admin groups and running process can access to public key file)" {
- Set-FileOwnerAndACL -Filepath $hostKeyFilePath -Owner $adminAccount -OwnerPerms "FullControl"
- Add-PermissionToFileACL -FilePath $hostKeyFilePath -User $systemAccount -Perms "FullControl"
+ It "$tC.$tI-Host keys-positive (both public and private keys are owned by admin groups and running process can access to public key file)" {
+ Repair-FilePermission -Filepath $hostKeyFilePath -Owners $adminsSid -FullAccessNeeded $adminsSid,$systemSid -confirm:$false
+ Repair-FilePermission -Filepath "$hostKeyFilePath.pub" -Owners $adminsSid -FullAccessNeeded $adminsSid,$systemSid -confirm:$false
+
+ #Run
+
+ Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-p $port", "-h $hostKeyFilePath", "-E $logPath") -NoNewWindow
+ WaitForValidation -LogPath $logPath -Length 600
+
+ #validate file content does not contain unprotected info.
+ $logPath | Should Not Contain "UNPROTECTED PRIVATE KEY FILE!"
- Set-FileOwnerAndACL -Filepath "$hostKeyFilePath.pub" -Owner $adminAccount -OwnerPerms "FullControl"
- Add-PermissionToFileACL -FilePath "$hostKeyFilePath.pub" -User $systemAccount -Perms "FullControl"
- Add-PermissionToFileACL -FilePath "$hostKeyFilePath.pub" -User $everyOne -Perms "Read"
+ }
+
+ It "$tC.$tI-Host keys-positive (both public and private keys are owned by admin groups and pwd user has explicit ACE)" {
+ Repair-FilePermission -Filepath $hostKeyFilePath -Owners $adminsSid -FullAccessNeeded $adminsSid,$systemSid -ReadAccessNeeded $currentUserSid -confirm:$false
+ Repair-FilePermission -Filepath "$hostKeyFilePath.pub" -Owners $adminsSid -FullAccessNeeded $adminsSid,$systemSid -ReadAccessNeeded $everyOneSid -confirm:$false
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-p $port", "-h $hostKeyFilePath", "-E $logPath") -NoNewWindow
- Get-Process -Name sshd | % { if($_.SI -ne 0) { Start-sleep 2; Stop-Process $_; Start-sleep 1 } }
+ WaitForValidation -LogPath $logPath -Length 600
#validate file content does not contain unprotected info.
$logPath | Should Not Contain "UNPROTECTED PRIVATE KEY FILE!"
}
- It "$tC.$tI-Host keys-positive (both public and private keys are owned by admin groups and pwd user has explicit ACE)" {
- Set-FileOwnerAndACL -Filepath $hostKeyFilePath -Owner $adminAccount -OwnerPerms "FullControl"
- Add-PermissionToFileACL -FilePath $hostKeyFilePath -User $systemAccount -Perms "FullControl"
- Add-PermissionToFileACL -FilePath "$hostKeyFilePath.pub" -User $currentUser -Perms "Read"
+ It "$tC.$tI-Host keys-positive (both public and private keys are owned by system and running process can access to public key file)" -skip:$skip {
+ Repair-FilePermission -Filepath $hostKeyFilePath -Owners $systemSid -FullAccessNeeded $systemSid,$adminsSid -ReadAccessNeeded $currentUserSid -confirm:$false
+ Set-FilePermission -Filepath $hostKeyFilePath -UserSid $adminsSid -Action Delete
+ Repair-FilePermission -Filepath "$hostKeyFilePath.pub" -Owners $systemSid -FullAccessNeeded $systemSid,$adminsSid -ReadAccessNeeded $currentUserSid -confirm:$false
+ Set-FilePermission -Filepath "$hostKeyFilePath.pub" -UserSid $adminsSid -Action Delete
- Set-FileOwnerAndACL -Filepath "$hostKeyFilePath.pub" -Owner $adminAccount -OwnerPerms "FullControl"
- Add-PermissionToFileACL -FilePath "$hostKeyFilePath.pub" -User $systemAccount -Perms "FullControl"
- Add-PermissionToFileACL -FilePath "$hostKeyFilePath.pub" -User $everyOne -Perms "Read"
-
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-p $port", "-h $hostKeyFilePath", "-E $logPath") -NoNewWindow
- Get-Process -Name sshd | % { if($_.SI -ne 0) { Start-sleep 2; Stop-Process $_; Start-sleep 1 } }
-
- #validate file content does not contain unprotected info.
- $logPath | Should Not Contain "UNPROTECTED PRIVATE KEY FILE!"
- }
-
- It "$tC.$tI-Host keys-positive (both public and private keys are owned by system and running process can access to public key file)" {
- Set-FileOwnerAndACL -Filepath $hostKeyFilePath -Owner $systemAccount -OwnerPerms "FullControl"
- Add-PermissionToFileACL -FilePath $hostKeyFilePath -User $adminAccount -Perms "Read"
-
- Set-FileOwnerAndACL -Filepath "$hostKeyFilePath.pub" -Owner $systemAccount -OwnerPerms "FullControl"
- Add-PermissionToFileACL -FilePath "$hostKeyFilePath.pub" -User $adminAccount -Perms "Read"
-
- #Run
- Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-p $port", "-h $hostKeyFilePath", "-E $logPath") -NoNewWindow
- Get-Process -Name sshd | % { if($_.SI -ne 0) { Start-sleep 2; Stop-Process $_; Start-sleep 1 } }
-
+ WaitForValidation -LogPath $logPath -Length 600
#validate file content does not contain unprotected info.
$logPath | Should Not Contain "UNPROTECTED PRIVATE KEY FILE!"
}
It "$tC.$tI-Host keys-negative (other account can access private key file)" {
- Set-FileOwnerAndACL -Filepath $hostKeyFilePath -Owner $systemAccount -OwnerPerms "FullControl"
- Add-PermissionToFileACL -FilePath $hostKeyFilePath -User $adminAccount -Perms "FullControl"
- Add-PermissionToFileACL -FilePath $hostKeyFilePath -User $objUser -Perms "Read"
+ Repair-FilePermission -Filepath $hostKeyFilePath -Owners $adminsSid -FullAccessNeeded $systemSid,$adminsSid -ReadAccessNeeded $objUserSid -confirm:$false
+ Repair-FilePermission -Filepath "$hostKeyFilePath.pub" -Owners $adminsSid -FullAccessNeeded $systemSid,$adminsSid -ReadAccessNeeded $everyOneSid -confirm:$false
- Set-FileOwnerAndACL -Filepath "$hostKeyFilePath.pub" -Owner $adminAccount -OwnerPerms "FullControl"
- Add-PermissionToFileACL -FilePath "$hostKeyFilePath.pub" -User $systemAccount -Perms "FullControl"
- Add-PermissionToFileACL -FilePath "$hostKeyFilePath.pub" -User $everyOne -Perms "Read"
-
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-p $port", "-h $hostKeyFilePath", "-E $logPath") -NoNewWindow
- Get-Process -Name sshd | % { if($_.SI -ne 0) { Start-sleep 2; Stop-Process $_; Start-sleep 1 } }
+ WaitForValidation -LogPath $logPath -Length 1100
#validate file content contains unprotected info.
$logPath | Should Contain "key_load_private: bad permissions"
@@ -127,32 +138,26 @@ Describe "Tests for host keys file permission" -Tags "CI" {
It "$tC.$tI-Host keys-negative (the private key has wrong owner)" {
#setup to have ssouser as owner and grant it full control
- Set-FileOwnerAndACL -FilePath $hostKeyFilePath -Owner $objUser -OwnerPerms "Read","Write"
- Add-PermissionToFileACL -FilePath $hostKeyFilePath -User $adminAccount -Perms "FullControl"
- Add-PermissionToFileACL -FilePath $hostKeyFilePath -User $systemAccount -Perms "FullControl"
-
- Set-FileOwnerAndACL -Filepath "$hostKeyFilePath.pub" -Owner $adminAccount -OwnerPerms "FullControl"
- Add-PermissionToFileACL -FilePath "$hostKeyFilePath.pub" -User $systemAccount -Perms "FullControl"
- Add-PermissionToFileACL -FilePath "$hostKeyFilePath.pub" -User $everyOne -Perms "Read"
+ Repair-FilePermission -Filepath $hostKeyFilePath -Owners $objUserSid -FullAccessNeeded $systemSid,$adminsSid,$objUserSid -confirm:$false
+ Repair-FilePermission -Filepath "$hostKeyFilePath.pub" -Owners $adminsSid -FullAccessNeeded $systemSid,$adminsSid -ReadAccessNeeded $everyOneSid -confirm:$false
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-p $port", "-h $hostKeyFilePath", "-E $logPath") -NoNewWindow
- Get-Process -Name sshd | % { if($_.SI -ne 0) { Start-sleep 2; Stop-Process $_; Start-sleep 1 } }
+ WaitForValidation -LogPath $logPath -Length 1100
#validate file content contains unprotected info.
$logPath | Should Contain "key_load_private: bad permissions"
}
- It "$tC.$tI-Host keys-negative (the running process does not have read access to public key)" {
+ It "$tC.$tI-Host keys-negative (the running process does not have read access to public key)" -skip:$skip {
#setup to have ssouser as owner and grant it full control
- Set-FileOwnerAndACL -FilePath $hostKeyFilePath -Owner $systemAccount -OwnerPerms "FullControl"
- Add-PermissionToFileACL -FilePath $hostKeyFilePath -User $adminAccount -Perms "Read"
-
- Set-FileOwnerAndACL -Filepath "$hostKeyFilePath.pub" -Owner $systemAccount -OwnerPerms "FullControl"
+ Repair-FilePermission -Filepath $hostKeyFilePath -Owners $systemSid -FullAccessNeeded $systemSid,$adminsSid -confirm:$false
+ Repair-FilePermission -Filepath "$hostKeyFilePath.pub" -Owners $systemSid -FullAccessNeeded $systemSid -confirm:$false
+ Set-FilePermission -Filepath "$hostKeyFilePath.pub" -UserSid $adminsSid -Action Delete
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-p $port", "-h $hostKeyFilePath", "-E $logPath") -NoNewWindow
- Get-Process -Name sshd | % { if($_.SI -ne 0) { Start-sleep 2; Stop-Process $_; Start-sleep 1 } }
+ WaitForValidation -LogPath $logPath -Length 1100
#validate file content contains unprotected info.
$logPath | Should Contain "key_load_public: Permission denied"
diff --git a/regress/pesterTests/KeyUtils.Tests.ps1 b/regress/pesterTests/KeyUtils.Tests.ps1
index 7793dc0..d4f33e2 100644
--- a/regress/pesterTests/KeyUtils.Tests.ps1
+++ b/regress/pesterTests/KeyUtils.Tests.ps1
@@ -1,4 +1,5 @@
-Import-Module $PSScriptRoot\CommonUtils.psm1 -Force -DisableNameChecking
+If ($PSVersiontable.PSVersion.Major -le 2) {$PSScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path}
+Import-Module $PSScriptRoot\CommonUtils.psm1 -Force
$tC = 1
$tI = 0
$suite = "keyutils"
@@ -7,7 +8,7 @@ Describe "E2E scenarios for ssh key management" -Tags "CI" {
BeforeAll {
if($OpenSSHTestInfo -eq $null)
{
- Throw "`$OpenSSHTestInfo is null. Please run Setup-OpenSSHTestEnvironment to setup test environment."
+ Throw "`$OpenSSHTestInfo is null. Please run Set-OpenSSHTestEnvironment to set test environments."
}
$testDir = "$($OpenSSHTestInfo["TestDataPath"])\$suite"
@@ -20,48 +21,58 @@ Describe "E2E scenarios for ssh key management" -Tags "CI" {
$keytypes = @("rsa","dsa","ecdsa","ed25519")
$ssouser = $OpenSSHTestInfo["SSOUser"]
-
- $systemAccount = New-Object System.Security.Principal.NTAccount("NT AUTHORITY", "SYSTEM")
- $adminsAccount = New-Object System.Security.Principal.NTAccount("BUILTIN","Administrators")
- $currentUser = New-Object System.Security.Principal.NTAccount($($env:USERDOMAIN), $($env:USERNAME))
- $everyone = New-Object System.Security.Principal.NTAccount("EveryOne")
- $objUser = New-Object System.Security.Principal.NTAccount($ssouser)
+
+ $systemSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::LocalSystemSid)
+ $adminsSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::BuiltinAdministratorsSid)
+ $currentUserSid = Get-UserSID -User "$($env:USERDOMAIN)\$($env:USERNAME)"
+ $objUserSid = Get-UserSID -User $ssouser
+ $everyoneSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::WorldSid)
#only validate owner and ACEs of the file
function ValidateKeyFile {
param([string]$FilePath)
$myACL = Get-ACL $FilePath
- $myACL.Owner.Equals($currentUser.Value) | Should Be $true
+ $currentOwnerSid = Get-UserSid -User $myACL.Owner
+ $currentOwnerSid.Equals($currentUserSid) | Should Be $true
$myACL.Access | Should Not Be $null
+
+ $ReadAccessPerm = ([System.UInt32] [System.Security.AccessControl.FileSystemRights]::Read.value__) -bor `
+ ([System.UInt32] [System.Security.AccessControl.FileSystemRights]::Synchronize.value__)
+ $ReadWriteAccessPerm = ([System.UInt32] [System.Security.AccessControl.FileSystemRights]::Read.value__) -bor `
+ ([System.UInt32] [System.Security.AccessControl.FileSystemRights]::Write.value__) -bor `
+ ([System.UInt32] [System.Security.AccessControl.FileSystemRights]::Synchronize.value__)
+ $FullControlPerm = [System.UInt32] [System.Security.AccessControl.FileSystemRights]::FullControl.value__
+
if($FilePath.EndsWith(".pub")) {
$myACL.Access.Count | Should Be 4
- $identities = @($systemAccount.Value, $adminsAccount.Value, $currentUser.Value, $everyone.Value)
+ $identities = @($systemSid, $adminsSid, $currentUserSid, $everyoneSid)
}
else {
$myACL.Access.Count | Should Be 3
- $identities = @($systemAccount.Value, $adminsAccount.Value, $currentUser.Value)
+ $identities = @($systemSid, $adminsSid, $currentUserSid)
}
foreach ($a in $myACL.Access) {
- $a.IdentityReference.Value -in $identities | Should Be $true
+ $id = Get-UserSid -User $a.IdentityReference
+ $identities -contains $id | Should Be $true
- switch ($a.IdentityReference.Value)
+ switch ($id)
{
- {$_ -in @($systemAccount.Value, $adminsAccount.Value)}
+ {@($systemSid, $adminsSid) -contains $_}
{
- $a.FileSystemRights | Should Be "FullControl"
+ ([System.UInt32]$a.FileSystemRights.value__) | Should Be $FullControlPerm
break;
}
- $currentUser.Value
+ $currentUserSid
{
- $a.FileSystemRights | Should Be "Write, Read, Synchronize"
+ ([System.UInt32]$a.FileSystemRights.value__) | Should Be $ReadWriteAccessPerm
break;
}
- $everyone.Value
+ $everyoneSid
{
- $a.FileSystemRights | Should Be "Read, Synchronize"
+ ([System.UInt32]$a.FileSystemRights.value__) | Should Be $ReadAccessPerm
break;
}
}
@@ -106,7 +117,7 @@ Describe "E2E scenarios for ssh key management" -Tags "CI" {
foreach($type in $keytypes)
{
$keyPath = Join-Path $testDir "id_$type"
- remove-item $keyPath -ErrorAction ignore
+ remove-item $keyPath -ErrorAction SilentlyContinue
ssh-keygen -t $type -P $keypassphrase -f $keyPath
ValidateKeyFile -FilePath $keyPath
ValidateKeyFile -FilePath "$keyPath.pub"
@@ -116,7 +127,17 @@ Describe "E2E scenarios for ssh key management" -Tags "CI" {
# This uses keys generated in above context
Context "$tC -ssh-add test cases" {
- BeforeAll {$tI=1}
+ BeforeAll {
+ $tI=1
+ function WaitForStatus
+ {
+ param([string]$ServiceName, [string]$Status)
+ while((((Get-Service $ServiceName).Status) -ine $Status) -and ($num++ -lt 4))
+ {
+ Start-Sleep -Milliseconds 1000
+ }
+ }
+ }
AfterAll{$tC++}
# Executing ssh-agent will start agent service
@@ -131,16 +152,21 @@ Describe "E2E scenarios for ssh key management" -Tags "CI" {
(Get-Service sshd).Status | Should Be "Stopped"
ssh-agent
+ WaitForStatus -ServiceName ssh-agent -Status "Running"
(Get-Service ssh-agent).Status | Should Be "Running"
Stop-Service ssh-agent -Force
+
+ WaitForStatus -ServiceName ssh-agent -Status "Stopped"
(Get-Service ssh-agent).Status | Should Be "Stopped"
(Get-Service sshd).Status | Should Be "Stopped"
# this should automatically start both the services
Start-Service sshd
+
+ WaitForStatus -ServiceName sshd -Status "Running"
(Get-Service ssh-agent).Status | Should Be "Running"
(Get-Service sshd).Status | Should Be "Running"
}
@@ -170,7 +196,7 @@ Describe "E2E scenarios for ssh key management" -Tags "CI" {
{
$keyPath = Join-Path $testDir "id_$type"
$pubkeyraw = ((Get-Content "$keyPath.pub").Split(' '))[1]
- ($allkeys | where { $_.contains($pubkeyraw) }).count | Should Be 1
+ @($allkeys | where { $_.contains($pubkeyraw) }).count | Should Be 1
}
#delete added keys
@@ -188,7 +214,7 @@ Describe "E2E scenarios for ssh key management" -Tags "CI" {
{
$keyPath = Join-Path $testDir "id_$type"
$pubkeyraw = ((Get-Content "$keyPath.pub").Split(' '))[1]
- ($allkeys | where { $_.contains($pubkeyraw) }).count | Should Be 0
+ @($allkeys | where { $_.contains($pubkeyraw) }).count | Should Be 0
}
}
}
@@ -197,7 +223,7 @@ Describe "E2E scenarios for ssh key management" -Tags "CI" {
BeforeAll {
$keyFileName = "sshadd_userPermTestkey_ed25519"
$keyFilePath = Join-Path $testDir $keyFileName
- Remove-Item -path "$keyFilePath*" -Force -ErrorAction Ignore
+ Remove-Item -path "$keyFilePath*" -Force -ErrorAction SilentlyContinue
ssh-keygen.exe -t ed25519 -f $keyFilePath -P $keypassphrase
#set up SSH_ASKPASS
Add-PasswordSetting -Pass $keypassphrase
@@ -209,7 +235,7 @@ Describe "E2E scenarios for ssh key management" -Tags "CI" {
}
AfterEach {
if(Test-Path $keyFilePath) {
- Adjust-UserKeyFileACL -FilePath $keyFilePath -Owner $currentUser -OwnerPerms "Read, Write"
+ Repair-FilePermission -FilePath $keyFilePath -Owner $currentUserSid -FullAccessNeeded $currentUserSid,$systemSid,$adminsSid -confirm:$false
}
}
@@ -220,30 +246,30 @@ Describe "E2E scenarios for ssh key management" -Tags "CI" {
}
It "$tC.$tI- ssh-add - positive (Secured private key owned by current user)" {
- #setup to have current user as owner and grant it full control
- Set-FileOwnerAndACL -FilePath $keyFilePath -Owner $currentUser -OwnerPerms "FullControl"
+ #setup to have current user as owner and grant it full control
+ Repair-FilePermission -FilePath $keyFilePath -Owner $currentUserSid -FullAccessNeeded $currentUserSid,$systemSid,$adminsSid -confirm:$false
# for ssh-add to consume SSh_ASKPASS, stdin should not be TTY
cmd /c "ssh-add $keyFilePath < $nullFile 2> nul"
$LASTEXITCODE | Should Be 0
$allkeys = ssh-add -L
$pubkeyraw = ((Get-Content "$keyFilePath.pub").Split(' '))[1]
- ($allkeys | where { $_.contains($pubkeyraw) }).count | Should Be 1
+ @($allkeys | where { $_.contains($pubkeyraw) }).count | Should Be 1
#clean up
cmd /c "ssh-add -d $keyFilePath 2> nul "
}
It "$tC.$tI - ssh-add - positive (Secured private key owned by Administrators group and the current user has no explicit ACE)" {
- #setup to have local admin group as owner and grant it full control
- Set-FileOwnerAndACL -FilePath $keyFilePath -Owner $adminsAccount -OwnerPerms "FullControl"
+ #setup to have local admin group as owner and grant it full control
+ Repair-FilePermission -FilePath $keyFilePath -Owner $adminsSid -FullAccessNeeded $adminsSid,$systemSid -confirm:$false
# for ssh-add to consume SSh_ASKPASS, stdin should not be TTY
cmd /c "ssh-add $keyFilePath < $nullFile 2> nul "
$LASTEXITCODE | Should Be 0
$allkeys = ssh-add -L
$pubkeyraw = ((Get-Content "$keyFilePath.pub").Split(' '))[1]
- ($allkeys | where { $_.contains($pubkeyraw) }).count | Should Be 1
+ @($allkeys | where { $_.contains($pubkeyraw) }).count | Should Be 1
#clean up
cmd /c "ssh-add -d $keyFilePath 2> nul "
@@ -251,62 +277,56 @@ Describe "E2E scenarios for ssh key management" -Tags "CI" {
It "$tC.$tI - ssh-add - positive (Secured private key owned by Administrators group and the current user has explicit ACE)" {
#setup to have local admin group as owner and grant it full control
- Set-FileOwnerAndACL -FilePath $keyFilePath -Owner $adminsAccount -OwnerPerms "FullControl"
- Add-PermissionToFileACL -FilePath $keyFilePath -User $currentUser -Perm "Read, Write"
+ Repair-FilePermission -FilePath $keyFilePath -Owners $adminsSid -FullAccessNeeded $currentUserSid,$adminsSid,$systemSid -confirm:$false
# for ssh-add to consume SSh_ASKPASS, stdin should not be TTY
cmd /c "ssh-add $keyFilePath < $nullFile 2> nul "
$LASTEXITCODE | Should Be 0
$allkeys = ssh-add -L
$pubkeyraw = ((Get-Content "$keyFilePath.pub").Split(' '))[1]
- ($allkeys | where { $_.contains($pubkeyraw) }).count | Should Be 1
+ @($allkeys | where { $_.contains($pubkeyraw) }).count | Should Be 1
#clean up
cmd /c "ssh-add -d $keyFilePath 2> nul "
}
It "$tC.$tI - ssh-add - positive (Secured private key owned by local system group)" {
- #setup to have local admin group as owner and grant it full control
- Set-FileOwnerAndACL -FilePath $keyFilePath -Owner $systemAccount -OwnerPerms "FullControl"
- Add-PermissionToFileACL -FilePath $keyFilePath -User $adminsAccount -Perm "FullControl"
+ #setup to have local admin group as owner and grant it full control
+ Repair-FilePermission -FilePath $keyFilePath -Owners $systemSid -FullAccessNeeded $systemSid,$adminsSid -confirm:$false
# for ssh-add to consume SSh_ASKPASS, stdin should not be TTY
cmd /c "ssh-add $keyFilePath < $nullFile 2> nul "
$LASTEXITCODE | Should Be 0
$allkeys = ssh-add -L
$pubkeyraw = ((Get-Content "$keyFilePath.pub").Split(' '))[1]
- ($allkeys | where { $_.contains($pubkeyraw) }).count | Should Be 1
+ @($allkeys | where { $_.contains($pubkeyraw) }).count | Should Be 1
#clean up
cmd /c "ssh-add -d $keyFilePath 2> nul "
}
It "$tC.$tI- ssh-add - negative (other account can access private key file)" {
- #setup to have current user as owner and grant it full control
- Set-FileOwnerAndACL -FilePath $keyFilePath -Owner $currentUser -OwnerPerms "FullControl"
-
- #add ssouser to access the private key
- Add-PermissionToFileACL -FilePath $keyFilePath -User $objUser -Perm "Read"
+ #setup to have current user as owner and grant it full control
+ Repair-FilePermission -FilePath $keyFilePath -Owners $currentUserSid -FullAccessNeeded $currentUserSid,$adminsSid, $systemSid -ReadAccessNeeded $objUserSid -confirm:$false
cmd /c "ssh-add $keyFilePath < $nullFile 2> nul "
$LASTEXITCODE | Should Not Be 0
$allkeys = ssh-add -L
$pubkeyraw = ((Get-Content "$keyFilePath.pub").Split(' '))[1]
- ($allkeys | where { $_.contains($pubkeyraw) }).count | Should Be 0
+ @($allkeys | where { $_.contains($pubkeyraw) }).count | Should Be 0
}
It "$tC.$tI - ssh-add - negative (the private key has wrong owner)" {
#setup to have ssouser as owner and grant it full control
- Set-FileOwnerAndACL -FilePath $keyFilePath -owner $objUser -OwnerPerms "Read, Write"
- Add-PermissionToFileACL -FilePath $keyFilePath -User $adminsAccount -Perm "FullControl"
+ Repair-FilePermission -FilePath $keyFilePath -Owners $objUserSid -FullAccessNeeded $objUserSid,$adminsSid, $systemSid -confirm:$false
cmd /c "ssh-add $keyFilePath < $nullFile 2> nul "
$LASTEXITCODE | Should Not Be 0
$allkeys = ssh-add -L
$pubkeyraw = ((Get-Content "$keyFilePath.pub").Split(' '))[1]
- ($allkeys | where { $_.contains($pubkeyraw) }).count | Should Be 0
+ @($allkeys | where { $_.contains($pubkeyraw) }).count | Should Be 0
}
}
@@ -314,7 +334,7 @@ Describe "E2E scenarios for ssh key management" -Tags "CI" {
BeforeAll {
$tI=1
$port = $OpenSSHTestInfo["Port"]
- Remove-item (join-path $testDir "$tC.$tI.out.txt") -force -ErrorAction Ignore
+ Remove-item (join-path $testDir "$tC.$tI.out.txt") -force -ErrorAction SilentlyContinue
}
BeforeEach {
$outputFile = join-path $testDir "$tC.$tI.out.txt"
diff --git a/regress/pesterTests/Log_fileperm.Tests.ps1 b/regress/pesterTests/Log_fileperm.Tests.ps1
index 0dbe490..7b3177e 100644
--- a/regress/pesterTests/Log_fileperm.Tests.ps1
+++ b/regress/pesterTests/Log_fileperm.Tests.ps1
@@ -1,4 +1,6 @@
-$tC = 1
+If ($PSVersiontable.PSVersion.Major -le 2) {$PSScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path}
+Import-Module $PSScriptRoot\CommonUtils.psm1 -Force
+$tC = 1
$tI = 0
$suite = "log_fileperm"
@@ -15,38 +17,52 @@ Describe "Tests for log file permission" -Tags "CI" {
$null = New-Item $testDir -ItemType directory -Force -ErrorAction SilentlyContinue
}
$port = 47003
- $logName = "log.txt"
+ $logName = "log.txt"
+
+ $systemSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::LocalSystemSid)
+ $adminsSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::BuiltinAdministratorsSid)
+ $currentUserSid = Get-UserSID -User "$($env:USERDOMAIN)\$($env:USERNAME)"
- $systemAccount = New-Object System.Security.Principal.NTAccount("NT AUTHORITY", "SYSTEM")
- $adminsAccount = New-Object System.Security.Principal.NTAccount("BUILTIN","Administrators")
- $currentUser = New-Object System.Security.Principal.NTAccount($($env:USERDOMAIN), $($env:USERNAME))
-
- Remove-Item (Join-Path $testDir "*$logName") -Force -ErrorAction Ignore
+ Remove-Item (Join-Path $testDir "*$logName") -Force -ErrorAction SilentlyContinue
+
+ $platform = Get-Platform
+ if(($platform -eq [PlatformType]::Windows) -and ($psversiontable.BuildVersion.Major -le 6))
+ {
+ #suppress the firewall blocking dialogue on win7
+ netsh advfirewall firewall add rule name="sshd" program="$($OpenSSHTestInfo['OpenSSHBinPath'])\sshd.exe" protocol=any action=allow dir=in
+ }
#only validate owner and ACEs of the file
- function ValiLogFilePerm {
+ function ValidateLogFilePerm {
param([string]$FilePath)
-
+
$myACL = Get-ACL $FilePath
- $myACL.Owner.Equals($currentUser.Value) | Should Be $true
- $myACL.Access | Should Not Be $null
+ $currentOwnerSid = Get-UserSid -User $myACL.Owner
+ $currentOwnerSid.Equals($currentUserSid) | Should Be $true
+ $myACL.Access | Should Not Be $null
+
+ $ReadWriteAccessPerm = ([System.UInt32] [System.Security.AccessControl.FileSystemRights]::Read.value__) -bor `
+ ([System.UInt32] [System.Security.AccessControl.FileSystemRights]::Write.value__) -bor `
+ ([System.UInt32] [System.Security.AccessControl.FileSystemRights]::Synchronize.value__)
+ $FullControlPerm = [System.UInt32] [System.Security.AccessControl.FileSystemRights]::FullControl.value__
+
$myACL.Access.Count | Should Be 3
- $identities = @($systemAccount.Value, $adminsAccount.Value, $currentUser.Value)
+ $identities = @($systemSid, $adminsSid, $currentUserSid)
foreach ($a in $myACL.Access) {
- $a.IdentityReference.Value -in $identities | Should Be $true
+ $id = Get-UserSid -User $a.IdentityReference
+ $identities -contains $id | Should Be $true
- switch ($a.IdentityReference.Value)
+ switch ($id)
{
- {$_ -in @($systemAccount.Value, $adminsAccount.Value)}
+ {@($systemSid, $adminsSid) -contains $_}
{
- $a.FileSystemRights | Should Be "FullControl"
+ ([System.UInt32]$a.FileSystemRights.value__) | Should Be $FullControlPerm
break;
}
-
- $currentUser.Value
+ $currentUserSid
{
- $a.FileSystemRights | Should Be "Write, Read, Synchronize"
+ ([System.UInt32]$a.FileSystemRights.value__) | Should Be $ReadWriteAccessPerm
break;
}
}
@@ -63,11 +79,17 @@ Describe "Tests for log file permission" -Tags "CI" {
$logPath = Join-Path $testDir "$tC.$tI.$logName"
}
- AfterEach {$tI++;}
+ AfterEach {$tI++;}
+ AfterAll {
+ if(($platform -eq [PlatformType]::Windows) -and ($psversiontable.BuildVersion.Major -le 6))
+ {
+ netsh advfirewall firewall delete rule name="sshd" program="$($OpenSSHTestInfo['OpenSSHBinPath'])\sshd.exe" protocol=any dir=in
+ }
+ }
Context "$tC-SSHD -E Log file permission" {
BeforeAll {
- Get-Process -Name sshd | Where-Object {$_.SI -ne 0} | Stop-process
+ Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
$tI=1
}
@@ -79,8 +101,8 @@ Describe "Tests for log file permission" -Tags "CI" {
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-p $port", "-E $logPath") -NoNewWindow
Start-sleep 1;
- ValiLogFilePerm -FilePath $logPath
- Get-Process -Name sshd | % { if($_.SI -ne 0) { Stop-Process $_; Start-sleep 1 } }
+ ValidateLogFilePerm -FilePath $logPath
+ Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
}
}
}
\ No newline at end of file
diff --git a/regress/pesterTests/PortForwarding.Tests.ps1 b/regress/pesterTests/PortForwarding.Tests.ps1
index 44fbcc4..609d6a9 100644
--- a/regress/pesterTests/PortForwarding.Tests.ps1
+++ b/regress/pesterTests/PortForwarding.Tests.ps1
@@ -1,14 +1,22 @@
-$tC = 1
+If ($PSVersiontable.PSVersion.Major -le 2) {$PSScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path}
+Import-Module $PSScriptRoot\CommonUtils.psm1 -Force
+$tC = 1
$tI = 0
$suite = "portfwd"
Describe "E2E scenarios for port forwarding" -Tags "CI" {
BeforeAll {
+ if($OpenSSHTestInfo -eq $null)
+ {
+ Throw "`$OpenSSHTestInfo is null. Please run Set-OpenSSHTestEnvironment to set test environments."
+ }
$testDir = Join-Path $OpenSSHTestInfo["TestDataPath"] $suite
if(-not (Test-Path $testDir))
{
$null = New-Item $testDir -ItemType directory -Force -ErrorAction SilentlyContinue
}
+ $platform = Get-Platform
+ $skip = ($platform -eq [PlatformType]::Windows) -and ($PSVersionTable.PSVersion.Major -le 2)
}
BeforeEach {
@@ -23,12 +31,12 @@ Describe "E2E scenarios for port forwarding" -Tags "CI" {
AfterAll{$tC++}
#TODO - this relies on winrm (that is windows specific)
- It "$tC.$tI - local port forwarding" {
+ It "$tC.$tI - local port forwarding" -skip:$skip {
ssh -L 5432:127.0.0.1:47001 test_target powershell.exe Test-WSMan -computer 127.0.0.1 -port 5432 | Set-Content $stdoutFile
$stdoutFile | Should Contain "wsmid"
}
- It "$tC.$tI - remote port forwarding" {
+ It "$tC.$tI - remote port forwarding" -skip:$skip {
ssh -R 5432:127.0.0.1:47001 test_target powershell.exe Test-WSMan -computer 127.0.0.1 -port 5432 | Set-Content $stdoutFile
$stdoutFile | Should Contain "wsmid"
}
diff --git a/regress/pesterTests/SCP.Tests.ps1 b/regress/pesterTests/SCP.Tests.ps1
index 3f7c994..b2d9ff6 100644
--- a/regress/pesterTests/SCP.Tests.ps1
+++ b/regress/pesterTests/SCP.Tests.ps1
@@ -1,11 +1,12 @@
-
+If ($PSVersiontable.PSVersion.Major -le 2) {$PSScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path}
+Import-Module $PSScriptRoot\CommonUtils.psm1 -Force
#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 {
if($OpenSSHTestInfo -eq $null)
{
- Throw "`$OpenSSHTestInfo is null. Please run Setup-OpenSSHTestEnvironment to setup test environment."
+ Throw "`$OpenSSHTestInfo is null. Please run Set-OpenSSHTestEnvironment to set test environments."
}
$fileName1 = "test.txt"
@@ -19,8 +20,8 @@ Describe "Tests for scp command" -Tags "CI" {
$NestedSourceFilePath = Join-Path $NestedSourceDir $fileName2
$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
+ $null = New-item -path $SourceFilePath -ItemType file -force -ErrorAction SilentlyContinue
+ $null = New-item -path $NestedSourceFilePath -ItemType file -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 -ErrorAction SilentlyContinue
@@ -94,8 +95,8 @@ Describe "Tests for scp command" -Tags "CI" {
# 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\ssh-agent.log" -Force -ErrorAction SilentlyContinue
+ Clear-Content "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\sshd.log" -Force -ErrorAction SilentlyContinue
}
function CheckTarget {
@@ -110,8 +111,8 @@ Describe "Tests for scp command" -Tags "CI" {
$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
+ Clear-Content "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\ssh-agent.log" -Force -ErrorAction SilentlyContinue
+ Clear-Content "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\sshd.log" -Force -ErrorAction SilentlyContinue
}
return $false
@@ -144,6 +145,7 @@ Describe "Tests for scp command" -Tags "CI" {
AfterEach {
Get-ChildItem $DestinationDir -Recurse | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
+ Start-Sleep 1
}
@@ -184,7 +186,7 @@ Describe "Tests for scp command" -Tags "CI" {
$equal = @(Compare-Object (Get-ChildItem -Recurse -path $SourceDir) (Get-ChildItem -Recurse -path (join-path $DestinationDir $SourceDirName) ) -Property Name, Length).Length -eq 0
$equal | Should Be $true
- if($Options.contains("-p"))
+ if($Options.contains("-p") -and ($platform -eq [PlatformType]::Windows) -and ($PSVersionTable.PSVersion.Major -gt 2))
{
$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
diff --git a/regress/pesterTests/SFTP.Tests.ps1 b/regress/pesterTests/SFTP.Tests.ps1
index 3d17df3..cf856ed 100644
--- a/regress/pesterTests/SFTP.Tests.ps1
+++ b/regress/pesterTests/SFTP.Tests.ps1
@@ -1,9 +1,12 @@
-Import-Module $PSScriptRoot\CommonUtils.psm1 -Force -DisableNameChecking
+If ($PSVersiontable.PSVersion.Major -le 2) {$PSScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path}
+Import-Module $PSScriptRoot\CommonUtils.psm1 -Force
Describe "SFTP Test Cases" -Tags "CI" {
BeforeAll {
+ $serverDirectory = $null
+ $clientDirectory = $null
if($OpenSSHTestInfo -eq $null)
{
- Throw "`$OpenSSHTestInfo is null. Please run Setup-OpenSSHTestEnvironment to setup test environment."
+ Throw "`$OpenSSHTestInfo is null. Please run Set-OpenSSHTestEnvironment to set test environments."
}
$rootDirectory = "$($OpenSSHTestInfo["TestDataPath"])\SFTP"
@@ -29,8 +32,11 @@ Describe "SFTP Test Cases" -Tags "CI" {
$ssouser = $OpenSSHTestInfo["SSOUser"]
$script:testId = 1
- Remove-item (Join-Path $rootDirectory "*.$outputFileName") -Force -ErrorAction Ignore
- Remove-item (Join-Path $rootDirectory "*.$batchFileName") -Force -ErrorAction Ignore
+ Remove-item (Join-Path $rootDirectory "*.$outputFileName") -Force -ErrorAction SilentlyContinue
+ Remove-item (Join-Path $rootDirectory "*.$batchFileName") -Force -ErrorAction SilentlyContinue
+
+ $platform = Get-Platform
+ $skip = ($platform -eq [PlatformType]::Windows) -and ($PSVersionTable.PSVersion.Major -le 2)
$testData1 = @(
@{
@@ -162,9 +168,9 @@ Describe "SFTP Test Cases" -Tags "CI" {
# 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
+ Clear-Content "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\ssh-agent.log" -Force -ErrorAction SilentlyContinue
+ Clear-Content "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\sshd.log" -Force -ErrorAction SilentlyContinue
+ Clear-Content "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\sftp-server.log" -Force -ErrorAction SilentlyContinue
}
function CopyDebugLogs {
@@ -175,21 +181,21 @@ Describe "SFTP Test Cases" -Tags "CI" {
Copy-Item "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\sftp-server.log" "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\sftp-server_$script:testId.log" -Force
# 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
+ Clear-Content "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\ssh-agent.log" -Force -ErrorAction SilentlyContinue
+ Clear-Content "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\sshd.log" -Force -ErrorAction SilentlyContinue
+ Clear-Content "$($OpenSSHTestInfo['OpenSSHBinPath'])\logs\sftp-server.log" -Force -ErrorAction SilentlyContinue
}
}
}
AfterAll {
- Get-ChildItem $serverDirectory | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
- Get-ChildItem $clientDirectory | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
+ if($serverDirectory) { Get-ChildItem $serverDirectory | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue }
+ if($clientDirectory) { Get-ChildItem $clientDirectory | 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
+ if($serverDirectory) { Get-ChildItem $serverDirectory | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue }
+ if($clientDirectory) { Get-ChildItem $clientDirectory | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue }
$outputFilePath = Join-Path $rootDirectory "$($script:testId).$outputFileName"
$batchFilePath = Join-Path $rootDirectory "$($script:testId).$batchFileName"
}
@@ -212,6 +218,7 @@ Describe "SFTP Test Cases" -Tags "CI" {
It '' -TestCases:$testData2 {
param([string]$Title, $Options, $tmpFileName1, $tmpFilePath1, $tmpFileName2, $tmpFilePath2, $tmpDirectoryName1, $tmpDirectoryPath1, $tmpDirectoryName2, $tmpDirectoryPath2)
+ if($skip) { return }
#rm (remove file)
$commands = "mkdir $tmpDirectoryPath1
@@ -263,16 +270,19 @@ Describe "SFTP Test Cases" -Tags "CI" {
}
It "$script:testId-ls lists items the user has no read permission" {
+ $adminsSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::BuiltinAdministratorsSid)
+ $currentUserSid = Get-UserSID -User "$($env:USERDOMAIN)\$($env:USERNAME)"
+
$permTestHasAccessFile = "permTestHasAccessFile.txt"
$permTestHasAccessFilePath = Join-Path $serverDirectory $permTestHasAccessFile
- Remove-Item $permTestHasAccessFilePath -Force -ErrorAction Ignore
+ Remove-Item $permTestHasAccessFilePath -Force -ErrorAction SilentlyContinue
New-Item $permTestHasAccessFilePath -ItemType file -Force -value "perm test has access file data" | Out-Null
$permTestNoAccessFile = "permTestNoAccessFile.txt"
$permTestNoAccessFilePath = Join-Path $serverDirectory $permTestNoAccessFile
- Remove-Item $permTestNoAccessFilePath -Force -ErrorAction Ignore
+ Remove-Item $permTestNoAccessFilePath -Force -ErrorAction SilentlyContinue
New-Item $permTestNoAccessFilePath -ItemType file -Force -value "perm test no access file data" | Out-Null
- Set-FileOwnerAndACL -Filepath $permTestNoAccessFilePath -OwnerPerms "Read","Write"
+ Repair-FilePermission -Filepath $permTestNoAccessFilePath -Owners $currentUserSid -FullAccessNeeded $adminsSid,$currentUserSid -confirm:$false
$Commands = "ls $serverDirectory"
Set-Content $batchFilePath -Encoding UTF8 -value $Commands
@@ -282,11 +292,11 @@ Describe "SFTP Test Cases" -Tags "CI" {
#cleanup
$HasAccessPattern = $permTestHasAccessFilePath.Replace("\", "[/\\]")
- $matches = $content | select-string -Pattern "^/$HasAccessPattern\s{0,}$"
+ $matches = @($content | select-string -Pattern "^/$HasAccessPattern\s{0,}$")
$matches.count | Should be 1
$NoAccessPattern = $permTestNoAccessFilePath.Replace("\", "[/\\]")
- $matches = $content | select-string -Pattern "^/$NoAccessPattern\s{0,}$"
+ $matches = @($content | select-string -Pattern "^/$NoAccessPattern\s{0,}$")
$matches.count | Should be 1
}
}
diff --git a/regress/pesterTests/SSH.Tests.ps1 b/regress/pesterTests/SSH.Tests.ps1
index 17434df..ab750de 100644
--- a/regress/pesterTests/SSH.Tests.ps1
+++ b/regress/pesterTests/SSH.Tests.ps1
@@ -1,4 +1,6 @@
-#todo: -i -q -v -l -c -C
+If ($PSVersiontable.PSVersion.Major -le 2) {$PSScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path}
+Import-Module $PSScriptRoot\CommonUtils.psm1 -Force
+#todo: -i -q -v -l -c -C
#todo: -S -F -V -e
$tC = 1
$tI = 0
@@ -8,7 +10,7 @@ Describe "E2E scenarios for ssh client" -Tags "CI" {
BeforeAll {
if($OpenSSHTestInfo -eq $null)
{
- Throw "`$OpenSSHTestInfo is null. Please run Setup-OpenSSHTestEnvironment to setup test environment."
+ Throw "`$OpenSSHTestInfo is null. Please run Set-OpenSSHTestEnvironment to set test environments."
}
$server = $OpenSSHTestInfo["Target"]
@@ -20,6 +22,8 @@ Describe "E2E scenarios for ssh client" -Tags "CI" {
{
$null = New-Item $testDir -ItemType directory -Force -ErrorAction SilentlyContinue
}
+ $platform = Get-Platform
+ $skip = ($platform -eq [PlatformType]::Windows) -and ($PSVersionTable.PSVersion.Major -le 2)
<#$testData = @(
@{
@@ -112,7 +116,7 @@ Describe "E2E scenarios for ssh client" -Tags "CI" {
BeforeAll {$tI=1}
AfterAll{$tC++}
- It "$tC.$tI - stdout to file" {
+ It "$tC.$tI - stdout to file" -skip:$skip {
ssh test_target powershell get-process > $stdoutFile
$stdoutFile | Should Contain "ProcessName"
}
diff --git a/regress/pesterTests/SSHDConfig.tests.ps1 b/regress/pesterTests/SSHDConfig.tests.ps1
index 10f884a..722d8ae 100644
--- a/regress/pesterTests/SSHDConfig.tests.ps1
+++ b/regress/pesterTests/SSHDConfig.tests.ps1
@@ -50,7 +50,7 @@
$client.AddPasswordSetting($password)
}
AfterEach {
- Remove-Item -Path $filePath -Force -ea ignore
+ Remove-Item -Path $filePath -Force -ea SilentlyContinue
}
AfterAll {
diff --git a/regress/pesterTests/SSHD_Config b/regress/pesterTests/SSHD_Config
index 4bab2a8..244471f 100644
--- a/regress/pesterTests/SSHD_Config
+++ b/regress/pesterTests/SSHD_Config
@@ -125,4 +125,5 @@ 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
+#AllowGroups allowgroup1 allowg*2 allowg?ou?3 Adm*
+hostkeyagent \\.\pipe\openssh-ssh-agent
diff --git a/regress/pesterTests/Userkey_fileperm.Tests.ps1 b/regress/pesterTests/Userkey_fileperm.Tests.ps1
index 1c4efb2..7e013b9 100644
--- a/regress/pesterTests/Userkey_fileperm.Tests.ps1
+++ b/regress/pesterTests/Userkey_fileperm.Tests.ps1
@@ -1,4 +1,5 @@
-Import-Module $PSScriptRoot\CommonUtils.psm1 -Force -DisableNameChecking
+If ($PSVersiontable.PSVersion.Major -le 2) {$PSScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path}
+Import-Module $PSScriptRoot\CommonUtils.psm1 -Force
$tC = 1
$tI = 0
@@ -8,7 +9,7 @@ Describe "Tests for user Key file permission" -Tags "CI" {
BeforeAll {
if($OpenSSHTestInfo -eq $null)
{
- Throw "`$OpenSSHTestInfo is null. Please run Setup-OpenSSHTestEnvironment to setup test environment."
+ Throw "`$OpenSSHTestInfo is null. Please run Set-OpenSSHTestEnvironment to setup test environment."
}
$testDir = "$($OpenSSHTestInfo["TestDataPath"])\$suite"
if( -not (Test-path $testDir -PathType Container))
@@ -24,13 +25,13 @@ Describe "Tests for user Key file permission" -Tags "CI" {
$server = $OpenSSHTestInfo["Target"]
$userName = "$env:USERNAME@$env:USERDOMAIN"
$keypassphrase = "testpassword"
-
- $systemAccount = New-Object System.Security.Principal.NTAccount("NT AUTHORITY", "SYSTEM")
- $adminsAccount = New-Object System.Security.Principal.NTAccount("BUILTIN","Administrators")
- $objUser = New-Object System.Security.Principal.NTAccount($ssouser)
- $pubKeyUserAccount = New-Object System.Security.Principal.NTAccount($pubKeyUser)
- $currentUser = New-Object System.Security.Principal.NTAccount($($env:USERDOMAIN), $($env:USERNAME))
- $everyone = New-Object System.Security.Principal.NTAccount("EveryOne")
+
+ $systemSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::LocalSystemSid)
+ $adminsSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::BuiltinAdministratorsSid)
+ $currentUserSid = Get-UserSID -User "$($env:USERDOMAIN)\$($env:USERNAME)"
+ $objUserSid = Get-UserSID -User $ssouser
+ $everyoneSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::WorldSid)
+ $pubKeyUserAccountSid = Get-UserSID -User $pubKeyUser
Add-PasswordSetting -Pass $keypassphrase
}
@@ -48,7 +49,7 @@ Describe "Tests for user Key file permission" -Tags "CI" {
BeforeAll {
$keyFileName = "sshtest_userPermTestkey_ed25519"
$keyFilePath = Join-Path $testDir $keyFileName
- Remove-Item -path "$keyFilePath*" -Force -ErrorAction Ignore
+ Remove-Item -path "$keyFilePath*" -Force -ErrorAction SilentlyContinue
ssh-keygen.exe -t ed25519 -f $keyFilePath -P $keypassphrase
$pubKeyUserProfilePath = Join-Path $pubKeyUserProfile .ssh
@@ -58,22 +59,22 @@ Describe "Tests for user Key file permission" -Tags "CI" {
$testAuthorizedKeyPath = Join-Path $pubKeyUserProfilePath authorized_keys
Copy-Item "$keyFilePath.pub" $testAuthorizedKeyPath -Force -ErrorAction SilentlyContinue
- Adjust-UserKeyFileACL -FilePath $testAuthorizedKeyPath -Owner $pubKeyUserAccount -OwnerPerms "Read, Write"
- Add-PermissionToFileACL -FilePath $testAuthorizedKeyPath -User "NT Service\sshd" -Perm "Read"
+ Repair-AuthorizedKeyPermission -FilePath $testAuthorizedKeyPath -confirm:$false
$tI=1
}
AfterAll {
if(Test-Path $testAuthorizedKeyPath) {
- Remove-Item $testAuthorizedKeyPath -Force -ErrorAction Ignore
+ Remove-Item $testAuthorizedKeyPath -Force -ErrorAction SilentlyContinue
}
if(Test-Path $pubKeyUserProfilePath) {
- Remove-Item $pubKeyUserProfilePath -Recurse -Force -ErrorAction Ignore
+ Remove-Item $pubKeyUserProfilePath -Recurse -Force -ErrorAction SilentlyContinue
}
$tC++
}
It "$tC.$tI-ssh with private key file -- positive (Secured private key owned by current user)" {
- Set-FileOwnerAndACL -FilePath $keyFilePath -Owner $currentUser -OwnerPerms "Read, Write"
+ Repair-FilePermission -FilePath $keyFilePath -Owners $currentUserSid -FullAccessNeeded $adminsSid,$systemSid,$currentUserSid -confirm:$false
+
#Run
$o = ssh -p $port -i $keyFilePath $pubKeyUser@$server echo 1234
$o | Should Be "1234"
@@ -81,7 +82,7 @@ Describe "Tests for user Key file permission" -Tags "CI" {
It "$tC.$tI-ssh with private key file -- positive(Secured private key owned by Administrators group and current user has no explicit ACE)" {
#setup to have local admin group as owner and grant it full control
- Set-FileOwnerAndACL -FilePath $keyFilePath -Owner $adminsAccount -OwnerPerms "FullControl"
+ Repair-FilePermission -FilePath $keyFilePath -Owners $adminsSid -FullAccessNeeded $adminsSid,$systemSid -confirm:$false
#Run
$o = ssh -p $port -i $keyFilePath $pubKeyUser@$server echo 1234
@@ -90,8 +91,7 @@ Describe "Tests for user Key file permission" -Tags "CI" {
It "$tC.$tI-ssh with private key file -- positive(Secured private key owned by Administrators group and current user has explicit ACE)" {
#setup to have local admin group as owner and grant it full control
- Set-FileOwnerAndACL -FilePath $keyFilePath -Owner $adminsAccount -OwnerPerms "FullControl"
- Add-PermissionToFileACL -FilePath $keyFilePath -User $currentUser -Perm "Read"
+ Repair-FilePermission -FilePath $keyFilePath -Owners $adminsSid -FullAccessNeeded $adminsSid,$systemSid -ReadAccessNeeded $currentUserSid -confirm:$false
#Run
$o = ssh -p $port -i $keyFilePath $pubKeyUser@$server echo 1234
@@ -100,8 +100,7 @@ Describe "Tests for user Key file permission" -Tags "CI" {
It "$tC.$tI-ssh with private key file -- positive (Secured private key owned by local system)" {
#setup to have local system as owner and grant it full control
- Set-FileOwnerAndACL -FilePath $keyFilePath -Owner $systemAccount -OwnerPerms "FullControl"
- Add-PermissionToFileACL -FilePath $keyFilePath -User $adminsAccount -Perm "Read"
+ Repair-FilePermission -FilePath $keyFilePath -Owners $systemSid -FullAccessNeeded $adminsSid,$systemSid -confirm:$false
#Run
$o = ssh -p $port -i $keyFilePath $pubKeyUser@$server echo 1234
@@ -109,11 +108,8 @@ Describe "Tests for user Key file permission" -Tags "CI" {
}
It "$tC.$tI-ssh with private key file -- negative(other account can access private key file)" {
- #setup to have current user as owner and grant it full control
- Set-FileOwnerAndACL -FilePath $keyFilePath -Owner $currentUser -OwnerPerms "Read, Write"
-
- #add ssouser to access the private key
- Add-PermissionToFileACL -FilePath $keyFilePath -User $objUser -Perm "Read"
+ #setup to have current user as owner and grant it full control
+ Repair-FilePermission -FilePath $keyFilePath -Owners $currentUserSid -FullAccessNeeded $currentUser,$adminsSid,$systemSid -ReadAccessNeeded $objUserSid -confirm:$false
#Run
$o = ssh -p $port -i $keyFilePath -E $logPath $pubKeyUser@$server echo 1234
@@ -123,9 +119,8 @@ Describe "Tests for user Key file permission" -Tags "CI" {
}
It "$tC.$tI-ssh with private key file -- negative(the private key has wrong owner)" {
- #setup to have ssouser as owner and grant it full control
- Set-FileOwnerAndACL -FilePath $keyFilePath -Owner $objUser -OwnerPerms "Read, Write"
- Add-PermissionToFileACL -FilePath $keyFilePath -User $adminsAccount -Perm "FullControl"
+ #setup to have ssouser as owner and grant it full control
+ Repair-FilePermission -FilePath $keyFilePath -Owners $objUserSid -FullAccessNeeded $objUserSid,$adminsSid,$systemSid -ReadAccessNeeded $objUserSid -confirm:$false
$o = ssh -p $port -i $keyFilePath -E $logPath $pubKeyUser@$server echo 1234
$LASTEXITCODE | Should Not Be 0
diff --git a/servconf.c b/servconf.c
index 39a00a1..32d6ea3 100644
--- a/servconf.c
+++ b/servconf.c
@@ -605,8 +605,9 @@ derelativise_path(const char *path)
return xstrdup("none");
expanded = tilde_expand_filename(path, getuid());
#ifdef WINDOWS
- /* Windows absolute paths have a drive letter followed by :*/
- if (*expanded != '\0' && expanded[1] == ':')
+ /* Windows absolute paths - \abc, /abc, c:\abc, c:/abc*/
+ if (*expanded == '/' || *expanded == '\\' ||
+ (*expanded != '\0' && expanded[1] == ':'))
#else /* !WINDOWS */
if (*expanded == '/')
#endif /* !WINDOWS */
diff --git a/session.c b/session.c
index 67720e7..1b40cb9 100644
--- a/session.c
+++ b/session.c
@@ -477,6 +477,9 @@ int do_exec_windows(Session *s, const char *command, int pty) {
*cmd = '\0';
}
+ /* load user profile */
+ mm_load_profile(s->pw->pw_name, ((INT_PTR)s->authctxt->auth_token) & 0xffffffff);
+
/* start the process */
{
memset(&si, 0, sizeof(STARTUPINFO));
@@ -492,7 +495,7 @@ int do_exec_windows(Session *s, const char *command, int pty) {
si.hStdError = (HANDLE)w32_fd_to_handle(pipeerr[1]);
si.lpDesktop = NULL;
- hToken = s->authctxt->methoddata;
+ hToken = s->authctxt->auth_token;
debug("Executing command: %s", exec_command);
UTF8_TO_UTF16_FATAL(exec_command_w, exec_command);
diff --git a/sftp.c b/sftp.c
index f30fb94..856de71 100644
--- a/sftp.c
+++ b/sftp.c
@@ -296,9 +296,14 @@ static void
local_do_shell(const char *args)
{
#ifdef WINDOWS
- /* execute via system call in Windows*/
- if (!*args) {
- args = (char *) getenv("ComSpec"); // get name of Windows cmd shell
+ /* execute via system call in Windows*/
+ char cmd_path[PATH_MAX] = { 0, };
+ if (!*args){
+ if (!GetSystemDirectory(cmd_path, sizeof(cmd_path)))
+ fatal("GetSystemDirectory failed");
+
+ strcat_s(cmd_path, PATH_MAX, "\\cmd.exe");
+ args = cmd_path;
} else {
convertToBackslash((char *) args);
}
diff --git a/sshd.c b/sshd.c
index 552f12e..f19275e 100644
--- a/sshd.c
+++ b/sshd.c
@@ -1765,9 +1765,7 @@ 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 */
- have_agent = 1;
-#endif
+
for (i = 0; i < options.num_host_key_files; i++) {
if (options.host_key_files[i] == NULL)
continue;