openssh-portable/regress/pesterTests/Setup.Tests.ps1

504 lines
21 KiB
PowerShell

If ($PSVersiontable.PSVersion.Major -le 2) {$PSScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path}
Import-Module $PSScriptRoot\CommonUtils.psm1 -Force
$suite = "Setup"
$tC = 1
$tI = 0
Describe "Setup Tests" -Tags "Setup" {
BeforeAll {
if($OpenSSHTestInfo -eq $null)
{
Throw "`$OpenSSHTestInfo is null. Please run Set-OpenSSHTestEnvironment to set test environments."
}
$windowsInBox = $OpenSSHTestInfo["WindowsInBox"]
$binPath = $OpenSSHTestInfo["OpenSSHBinPath"]
$dataPath = Join-path $env:ProgramData ssh
$systemSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::LocalSystemSid)
$adminsSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::BuiltinAdministratorsSid)
$usersSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::BuiltinUsersSid)
$authenticatedUserSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::AuthenticatedUserSid)
$trustedInstallerSid = Get-UserSID -User "NT SERVICE\TrustedInstaller"
$allApplicationPackagesSid = Get-UserSID -User "ALL APPLICATION PACKAGES"
$allRestrictedApplicationPackagesSid = Get-UserSID -User "ALL RESTRICTED APPLICATION PACKAGES"
$FSReadAccessPerm = ([System.UInt32] [System.Security.AccessControl.FileSystemRights]::ReadAndExecute.value__) -bor `
([System.UInt32] [System.Security.AccessControl.FileSystemRights]::Synchronize.value__)
$FSReadWriteAccessPerm = ([System.UInt32] [System.Security.AccessControl.FileSystemRights]::ReadAndExecute.value__) -bor `
([System.UInt32] [System.Security.AccessControl.FileSystemRights]::Write.value__) -bor `
([System.UInt32] [System.Security.AccessControl.FileSystemRights]::Modify.value__) -bor `
([System.UInt32] [System.Security.AccessControl.FileSystemRights]::Synchronize.value__)
$FSFullControlPerm = [System.UInt32] [System.Security.AccessControl.FileSystemRights]::FullControl.value__
$FSReadAndExecutePerm = ([System.UInt32] [System.Security.AccessControl.FileSystemRights]::ReadAndExecute.value__) -bor `
([System.UInt32] [System.Security.AccessControl.FileSystemRights]::Synchronize.value__)
$RegReadKeyPerm = ([System.UInt32] [System.Security.AccessControl.RegistryRights]::ReadKey.value__)
$RegFullControlPerm = [System.UInt32] [System.Security.AccessControl.RegistryRights]::FullControl.value__
#only validate owner and ACEs of the registry
function ValidateRegistryACL {
param([string]$RegPath, $Ownersid = $adminsSid, $IdAcls)
Test-Path -Path $RegPath | Should Be $true
$myACL = Get-ACL $RegPath
$OwnerSid = Get-UserSid -User $myACL.Owner
$OwnerSid.Equals($Ownersid) | Should Be $true
$myACL.Access | Should Not Be $null
$CAPABILITY_SID = "S-1-15-3-1024-1065365936-1281604716-3511738428-1654721687-432734479-3232135806-4053264122-3456934681"
$nonPropagate = $myACL.Access | ? {($_.PropagationFlags -eq ([System.Security.AccessControl.PropagationFlags]::None)) -and ($_.IdentityReference -ine $CAPABILITY_SID)}
foreach ($a in $nonPropagate) {
$findItem = $IdAcls | ? {
($a.IdentityReference -eq (Get-UserAccount -UserSid ($_.Identity))) -and `
($a.IsInherited -eq $_.IsInherited) -and `
($a.AccessControlType -eq ([System.Security.AccessControl.AccessControlType]::Allow)) -and `
(([System.Int32]$a.RegistryRights.value__) -eq ($_.RegistryRights))
}
$findItem | Should Not Be $null
}
foreach ($expected in $IdAcls) {
$findItem = $nonPropagate | ? {
((Get-UserAccount -UserSid ($expected.Identity)) -eq $_.IdentityReference) -and `
($expected.IsInherited -eq $_.IsInherited) -and `
($expected.RegistryRights -eq ([System.Int32]$_.RegistryRights.value__))
}
$findItem | Should Not Be $null
}
}
#only validate owner and ACEs of the file
function ValidateFileSystem {
param(
[string]$FilePath,
[bool]$IsDirectory = $false,
[switch]$IsDataFile,
$OwnerSid = $trustedInstallerSid)
if($IsDirectory)
{
Test-Path -Path $FilePath -PathType Container | Should Be $true
}
else
{
Test-Path -Path $FilePath -PathType Leaf | Should Be $true
}
$myACL = Get-ACL $FilePath
$currentOwnerSid = Get-UserSid -User $myACL.Owner
if(-not $windowsInBox) {return}
$currentOwnerSid.Equals($OwnerSid) | Should Be $true
$myACL.Access | Should Not Be $null
if($IsDirectory)
{
$identities = @($systemSid, $adminsSid)
}
elseif($IsDataFile)
{
$identities = @($systemSid, $adminsSid, $authenticatedUserSid)
}
else
{
$identities = @($systemSid, $adminsSid, $trustedInstallerSid, $allApplicationPackagesSid, $allRestrictedApplicationPackagesSid, $usersSid)
}
$identities | % {
$myACL.Access.IdentityReference -contains (Get-UserAccount -UserSid $_) | Should Be $true
}
foreach ($a in $myACL.Access) {
$id = Get-UserSid -User $a.IdentityReference
if($id -eq $null)
{
$idRefShortValue = ($a.IdentityReference.Value).split('\')[-1]
$id = Get-UserSID -User $idRefShortValue
}
$identities -contains $id | Should be $true
switch ($id)
{
{@($systemSid, $adminsSid) -contains $_}
{
if($IsDataFile)
{
([System.UInt32]$a.FileSystemRights.value__) | Should Be $FSFullControlPerm
}
else
{
([System.UInt32]$a.FileSystemRights.value__) | Should Be $FSReadAndExecutePerm
}
break;
}
{@($usersSid, $allApplicationPackagesSid, $allRestrictedApplicationPackagesSid, $authenticatedUserSid) -contains $_}
{
([System.UInt32]$a.FileSystemRights.value__) | Should Be $FSReadAndExecutePerm
break;
}
$trustedInstallerSid
{
([System.UInt32]$a.FileSystemRights.value__) | Should Be $FSFullControlPerm
break;
}
}
$a.AccessControlType | Should Be ([System.Security.AccessControl.AccessControlType]::Allow)
if($IsDirectory)
{
$a.InheritanceFlags | Should Be (([System.Security.AccessControl.InheritanceFlags]::ContainerInherit.value__ -bor `
[System.Security.AccessControl.InheritanceFlags]::ObjectInherit.value__))
}
else
{
$a.InheritanceFlags | Should Be ([System.Security.AccessControl.InheritanceFlags]::None)
}
$a.PropagationFlags | Should Be ([System.Security.AccessControl.PropagationFlags]::None)
}
}
}
Context "$tC - Validate Openssh binary files" {
BeforeAll {
$tI=1
$binaries = @(
@{
Name = 'sshd.exe'
},
@{
Name = 'ssh.exe'
},
@{
Name = 'ssh-agent.exe'
},
@{
Name = 'ssh-add.exe'
},
@{
Name = 'sftp.exe'
},
@{
Name = 'sftp-server.exe'
},
@{
Name = 'scp.exe'
},
@{
Name = 'ssh-shellhost.exe'
},
@{
Name = 'ssh-agent.exe'
},
@{
Name = 'ssh-keyscan.exe'
}
)
$dataFile = @(
@{
Name = 'sshd_config_default'
},
@{
Name = 'install-sshd.ps1'
},
@{
Name = 'uninstall-sshd.ps1'
},
@{
Name = 'FixHostFilePermissions.ps1'
},
@{
Name = 'FixUserFilePermissions.ps1'
},
@{
Name = 'OpenSSHUtils.psm1'
},
@{
Name = 'OpenSSHUtils.psd1'
},
@{
Name = 'openssh-events.man'
}
)
$dataFile1 = @(
@{
Name = "sshd_config"
}
@{
Name = "logs"
IsDirectory = $true
}
)
}
AfterAll{$tC++}
AfterEach { $tI++ }
It "$tC.$tI - Validate Openssh binary files--<Name>" -TestCases:$binaries{
param([string]$Name, [boolean]$IsDirectory = $false)
ValidateFileSystem -FilePath (join-path $binPath $Name)
}
It "$tC.$tI - Validate Openssh script files--<Name>" -TestCases:$dataFile {
param([string]$Name, [boolean]$IsDirectory = $false)
if(-not $WindowsInbox) { ValidateFileSystem -FilePath (join-path $binPath $Name) }
}
It "$tC.$tI - Validate data files--<Name>" -TestCases:$dataFile1 {
param([string]$Name, [boolean]$IsDirectory = $false)
if(-not (Test-Path $dataPath -PathType Container))
{
Start-Service sshd
}
ValidateFileSystem -FilePath (join-path $dataPath $Name) -IsDirectory $IsDirectory -OwnerSid $adminsSid -IsDataFile
}
}
Context "$tC - Validate Openssh registry entries" {
BeforeAll {
$tI=1
$servicePath = "HKLM:\SYSTEM\ControlSet001\Services"
$opensshRegPath = "HKLM:\SOFTWARE\OpenSSH"
$opensshACLs = @(
@{
Identity=$systemSid
IsInherited = $false
RegistryRights = $RegFullControlPerm
PropagationFlags = "None"
},
@{
Identity=$adminsSid
IsInherited = $false
RegistryRights = $RegFullControlPerm
PropagationFlags = "None"
},
@{
Identity=$authenticatedUserSid
IsInherited = $false
RegistryRights = $RegReadKeyPerm -bor ([System.UInt32] [System.Security.AccessControl.RegistryRights]::SetValue.value__)
PropagationFlags = "None"
}
)
}
AfterAll{$tC++}
AfterEach { $tI++ }
It "$tC.$tI - Validate Registry key ssh-agent\Description" {
$p = Get-ItemPropertyValue (Join-Path $servicePath "ssh-agent") -Name "Description"
$p | Should Not Be $null
}
It "$tC.$tI - Validate Registry key ssh-agent\ErrorControl" {
$p = Get-ItemPropertyValue (Join-Path $servicePath "ssh-agent") -Name "ErrorControl"
$p | Should Be 1
}
It "$tC.$tI - Validate Registry key ssh-agent\ImagePath" {
$p = Get-ItemPropertyValue (Join-Path $servicePath "ssh-agent") -Name "ImagePath"
$imagePath = (Join-Path $binPath "ssh-agent.exe").ToLower()
$p | Should Match "[`"]?$($imagePath.Replace("\", "\\"))[`"]?"
}
It "$tC.$tI - Validate Registry key ssh-agent\ObjectName" {
$p = Get-ItemPropertyValue (Join-Path $servicePath "ssh-agent") -Name "ObjectName"
$p | Should Be "LocalSystem"
}
It "$tC.$tI - Validate Registry key ssh-agent\Start" {
$p = Get-ItemPropertyValue (Join-Path $servicePath "ssh-agent") -Name "Start"
if($windowsInBox) {
$p | Should Be 4
}
else {
$p | Should Be 3
}
}
It "$tC.$tI - Validate Registry key ssh-agent\Type" {
$p = Get-ItemPropertyValue (Join-Path $servicePath "ssh-agent") -Name "Type"
$p | Should Be 16
}
It "$tC.$tI - Validate Registry key to ssh-agent\Security\Security" {
$p = Get-ItemPropertyValue (Join-Path $servicePath "ssh-agent\Security") -Name Security
$p.Gettype() | Should Be byte[]
}
It "$tC.$tI - Validate Registry key sshd\Description" {
$p = Get-ItemPropertyValue (Join-Path $servicePath "sshd") -Name "Description"
$p | Should not Be $null
}
It "$tC.$tI - Validate Registry key sshd\ErrorControl" {
$p = Get-ItemPropertyValue (Join-Path $servicePath "sshd") -Name "ErrorControl"
$p | Should Be 1
}
It "$tC.$tI - Validate Registry key sshd\ImagePath" {
$p = Get-ItemPropertyValue (Join-Path $servicePath "sshd") -Name "ImagePath"
$imagePath = (Join-Path $binPath "sshd.exe").ToLower()
$p | Should Match "[`"]?$($imagePath.Replace("\", "\\"))[`"]?"
}
It "$tC.$tI - Validate Registry key sshd\ObjectName" {
$p = Get-ItemPropertyValue (Join-Path $servicePath "sshd") -Name "ObjectName"
$p | Should Be "LocalSystem"
}
It "$tC.$tI - Validate Registry key sshd\Start" {
$p = Get-ItemPropertyValue (Join-Path $servicePath "sshd") -Name "Start"
$p | Should Be 3
}
It "$tC.$tI - Validate Registry key sshd\Type" {
$p = Get-ItemPropertyValue (Join-Path $servicePath "sshd") -Name "Type"
$p | Should Be 16
}
It "$tC.$tI - Validate Registry openssh entry" {
ValidateRegistryACL -RegPath $opensshRegPath -IdAcls $opensshACLs
}
It "$tC.$tI - Validate Registry openssh\agent entry" {
$agentPath = Join-Path $opensshRegPath "Agent"
if(Test-Path $agentPath -PathType Container)
{
ValidateRegistryACL -RegPath $agentPath -IdAcls $opensshACLs
}
elseif((-not $windowsInBox) -or ((Get-Service ssh-agent).StartType -ne ([System.ServiceProcess.ServiceStartMode]::Disabled)))
{
Start-Service ssh-agent
ValidateRegistryACL -RegPath $agentPath -IdAcls $opensshACLs
}
}
}
Context "$tC - Validate service settings" {
BeforeAll {
$tI=1
}
AfterAll{$tC++}
AfterEach { $tI++ }
It "$tC.$tI - Validate properties of ssh-agent service" {
$sshdSvc = Get-service ssh-agent
if($windowsInBox) {
$sshdSvc.StartType | Should Be ([System.ServiceProcess.ServiceStartMode]::Disabled)
}
else {
$sshdSvc.StartType | Should Be ([System.ServiceProcess.ServiceStartMode]::Manual)
}
$sshdSvc.ServiceType | Should Be ([System.ServiceProcess.ServiceType]::Win32OwnProcess)
$sshdSvc.ServiceName | Should Be "ssh-agent"
$sshdSvc.DisplayName | Should BeLike "OpenSSH*"
$sshdSvc.Name | Should Be "ssh-agent"
($sshdSvc.DependentServices).Count | Should Be 0
($sshdSvc.ServicesDependedOn).Count | Should Be 0
($sshdSvc.RequiredServices).Count | Should Be 0
}
It "$tC.$tI - Validate properties of sshd service" {
$sshdSvc = Get-service sshd
$sshdSvc.StartType | Should Be ([System.ServiceProcess.ServiceStartMode]::Manual)
$sshdSvc.ServiceType | Should Be ([System.ServiceProcess.ServiceType]::Win32OwnProcess)
$sshdSvc.ServiceName | Should Be "sshd"
$sshdSvc.DisplayName | Should BeLike "OpenSSH*"
$sshdSvc.Name | Should Be "sshd"
($sshdSvc.DependentServices).Count | Should Be 0
($sshdSvc.ServicesDependedOn).Count | Should Be 0
($sshdSvc.RequiredServices).Count | Should Be 0
}
It "$tC.$tI - Validate RequiredPrivileges of ssh-agent" {
$a = sc.exe qprivs ssh-agent 256
$p = @($a | % { if($_ -match "Se[\w]+Privilege" ) {$start = $_.IndexOf("Se");$_.Substring($start, $_.length-$start)}})
$p.count | Should Be 1
$p[0] | Should Be "SeImpersonatePrivilege"
}
It "$tC.$tI - Validate RequiredPrivileges of sshd" {
$expected = @("SeAssignPrimaryTokenPrivilege", "SeTcbPrivilege", "SeBackupPrivilege", "SeRestorePrivilege", "SeImpersonatePrivilege")
$a = sc.exe qprivs sshd 256
$p = $a | % { if($_ -match "Se[\w]+Privilege" ) {$start = $_.IndexOf("Se");$_.Substring($start, $_.length-$start)}}
$expected | % {
$p -contains $_ | Should be $true
}
$p | % {
$expected -contains $_ | Should be $true
}
}
It "$tC.$tI - Validate security access to ssh-agent service" {
$a = @(sc.exe sdshow ssh-agent)
$b = $a[-1] -split "[D|S]:"
$expected_dacl_aces = @("(A;;CCLCSWRPWPDTLOCRRC;;;SY)", "(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)", "(A;;CCLCSWLOCRRC;;;IU)", "(A;;CCLCSWLOCRRC;;;SU)", "(A;;RP;;;AU)")
$c = @($b | ? { -not [string]::IsNullOrWhiteSpace($_) })
$dacl = $c[0]
$dacl_aces = $dacl -split "(\([;|\w]+\))"
$actual_dacl_aces = $dacl_aces | ? { -not [string]::IsNullOrWhiteSpace($_) }
$expected_dacl_aces | % {
$actual_dacl_aces -contains $_ | Should be $true
}
$actual_dacl_aces | % {
$expected_dacl_aces -contains $_ | Should be $true
}
<# ignore sacl for now
if($c.Count -gt 1) {
$c[1] | Should Be "(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)"
}#>
}
It "$tC.$tI - Validate security access to sshd service" {
$a = @(sc.exe sdshow sshd)
$b = $a[-1] -split "[D|S]:"
$expected_dacl_aces = @("(A;;CCLCSWRPWPDTLOCRRC;;;SY)", "(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)", "(A;;CCLCSWLOCRRC;;;IU)", "(A;;CCLCSWLOCRRC;;;SU)")
$c = @($b | ? { -not [string]::IsNullOrWhiteSpace($_) })
$dacl = $c[0]
$dacl_aces = $dacl -split "(\([;|\w]+\))"
$actual_dacl_aces = $dacl_aces | ? { -not [string]::IsNullOrWhiteSpace($_) }
$expected_dacl_aces | % {
$actual_dacl_aces -contains $_ | Should be $true
}
$actual_dacl_aces | % {
$expected_dacl_aces -contains $_ | Should be $true
}
<# ignore sacl for now
if($c.Count -gt 1) {
$c[1] | Should Be "(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)"
}#>
}
}
Context "$tC - Validate Firewall settings" {
BeforeAll {
$firwallRuleName = "OpenSSH-Server-In-TCP"
$tI=1
}
AfterAll{$tC++}
AfterEach { $tI++ }
It "$tC.$tI - Validate Firewall settings" -skip:(!$windowsInBox) {
$rule = Get-NetFirewallRule -Name $firwallRuleName
$rule.Group | Should BeLike "OpenSSH*"
$rule.Description | Should BeLike "*OpenSSH*"
$rule.DisplayName | Should BeLike "OpenSSH*"
$rule.Enabled | Should Be $true
$rule.Profile.ToString() | Should Be 'Any'
$rule.Direction.ToString() | Should Be 'Inbound'
$rule.Action.ToString() | Should Be 'Allow'
$rule.StatusCode | Should Be 65536
$fwportFilter = $rule | Get-NetFirewallPortFilter
$fwportFilter.Protocol | Should Be 'TCP'
$fwportFilter.LocalPort | Should Be 22
$fwportFilter.RemotePort | Should Be 'Any'
}
}
}