From 9d733203d6326c1f188f42f9b40f3222e3778bb7 Mon Sep 17 00:00:00 2001 From: Tess Gauthier Date: Fri, 4 Feb 2022 19:22:59 -0500 Subject: [PATCH] fix folder permissions for programdata\ssh during server install (#549) --- contrib/win32/openssh/OpenSSHUtils.psm1 | 84 +++++++++++++++++++++++-- contrib/win32/openssh/install-sshd.ps1 | 8 +++ 2 files changed, 87 insertions(+), 5 deletions(-) diff --git a/contrib/win32/openssh/OpenSSHUtils.psm1 b/contrib/win32/openssh/OpenSSHUtils.psm1 index e70afd0d7..a4fbc77bd 100644 --- a/contrib/win32/openssh/OpenSSHUtils.psm1 +++ b/contrib/win32/openssh/OpenSSHUtils.psm1 @@ -43,6 +43,8 @@ $everyoneSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKno $currentUserSid = Get-UserSID -User "$($env:USERDOMAIN)\$($env:USERNAME)" +$authenticatedUserSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::AuthenticatedUserSid) + #Taken from P/Invoke.NET with minor adjustments. $definition = @' using System; @@ -268,6 +270,33 @@ function Repair-UserSshConfigPermission Repair-FilePermission -Owners $UserSid,$adminsSid,$systemSid -AnyAccessOK $UserSid @psBoundParameters } +<# + .Synopsis + Repair-SSHFolderPermission + Repair the file owner and permission of ssh folder & any files inside it +#> +function Repair-SSHFolderPermission +{ + [CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact="High")] + param ( + [parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string]$sshProgDataPath) + + # SSH Folder - owner: System or Admins; full access: System, Admins; read or readandexecute/synchronize permissible: Authenticated Users + Repair-FilePermission -FilePath $sshProgDataPath -Owners $adminsSid, $systemSid -FullAccessNeeded $adminsSid,$systemSid -ReadAndExecuteAccessOK $authenticatedUserSid + # Files in SSH Folder (excluding private key files) + # owner: System or Admins; full access: System, Admins; read/readandexecute/synchronize permissable: Authenticated Users + $privateKeyFiles = @("ssh_host_dsa_key", "ssh_host_ecdsa_key", "ssh_host_ed25519_key", "ssh_host_rsa_key") + Get-ChildItem -Path (Join-Path $sshProgDataPath '*') -Recurse -Exclude ($privateKeyFiles) -Force | ForEach-Object { + Repair-FilePermission -FilePath $_.FullName -Owners $adminsSid, $systemSid -FullAccessNeeded $adminsSid, $systemSid -ReadAndExecuteAccessOK $authenticatedUserSid + } + # Private key files - owner: System or Admins; full access: System, Admins + Get-ChildItem -Path (Join-Path $sshProgDataPath '*') -Recurse -Include $privateKeyFiles -Force | ForEach-Object { + Repair-FilePermission -FilePath $_.FullName -Owners $adminsSid, $systemSid -FullAccessNeeded $systemSid, $adminsSid + } +} + <# .Synopsis Repair-FilePermissionInternal @@ -285,10 +314,11 @@ function Repair-FilePermission [System.Security.Principal.SecurityIdentifier[]] $AnyAccessOK = $null, [System.Security.Principal.SecurityIdentifier[]] $FullAccessNeeded = $null, [System.Security.Principal.SecurityIdentifier[]] $ReadAccessOK = $null, - [System.Security.Principal.SecurityIdentifier[]] $ReadAccessNeeded = $null + [System.Security.Principal.SecurityIdentifier[]] $ReadAccessNeeded = $null, + [System.Security.Principal.SecurityIdentifier[]] $ReadAndExecuteAccessOK = $null ) - if(-not (Test-Path $FilePath -PathType Leaf)) + if(-not (Test-Path $FilePath)) { Write-host "$FilePath not found" -ForegroundColor Yellow return @@ -319,7 +349,8 @@ function Repair-FilePermissionInternal { [System.Security.Principal.SecurityIdentifier[]] $AnyAccessOK = $null, [System.Security.Principal.SecurityIdentifier[]] $FullAccessNeeded = $null, [System.Security.Principal.SecurityIdentifier[]] $ReadAccessOK = $null, - [System.Security.Principal.SecurityIdentifier[]] $ReadAccessNeeded = $null + [System.Security.Principal.SecurityIdentifier[]] $ReadAccessNeeded = $null, + [System.Security.Principal.SecurityIdentifier[]] $ReadAndExecuteAccessOK = $null ) $acl = Get-Acl $FilePath @@ -353,6 +384,7 @@ function Repair-FilePermissionInternal { $ReadAccessPerm = ([System.UInt32] [System.Security.AccessControl.FileSystemRights]::Read.value__) -bor ` ([System.UInt32] [System.Security.AccessControl.FileSystemRights]::Synchronize.value__) + $ReadAndExecuteAccessPerm = $ReadAccessPerm -bor ([System.UInt32] [System.Security.AccessControl.FileSystemRights]::ReadAndExecute.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 @@ -455,6 +487,48 @@ function Repair-FilePermissionInternal { #ignore those accounts listed in the AnyAccessOK list. continue; } + # Handle ReadAndExecuteAccessOK list and make sure they are only granted Read or ReadAndExecute & Synchronize access + elseif($ReadAndExecuteAccessOK -contains $IdentityReferenceSid) + { + # checks if user access is already either: Read or ReadAndExecute & Synchronize + if (-not ($a.AccessControlType.Equals([System.Security.AccessControl.AccessControlType]::Allow)) -or ` + (-not (([System.UInt32]$a.FileSystemRights.value__) -band (-bnot $ReadAndExecuteAccessPerm)))) + { + continue; + } + + 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.FileSystemRights)'." + $prompt = "Shall I make it ReadAndExecute, and Synchronize only?" + $description = "Set'$($a.IdentityReference)' Read access only to '$FilePath'. " + + if($pscmdlet.ShouldProcess($description, $prompt, $caption)) + { + $needChange = $true + $ace = New-Object System.Security.AccessControl.FileSystemAccessRule ` + ($IdentityReferenceSid, "ReadAndExecute, Synchronize", "None", "None", "Allow") + + $acl.SetAccessRule($ace) + Write-Host "'$($a.IdentityReference)' now has ReadAndExecute, Synchronize access to '$FilePath'. " -ForegroundColor Green + } + else + { + $health = $false + if(-not $PSBoundParameters.ContainsKey("WhatIf")) + { + Write-Host "'$($a.IdentityReference)' still has these access to '$FilePath': '$($a.FileSystemRights)'." -ForegroundColor Yellow + } + } + } #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 -contains $everyoneSid) -or ($realReadAcessOKList -contains $IdentityReferenceSid)) @@ -649,7 +723,7 @@ function Remove-RuleProtection [string]$FilePath ) $message = "Need to remove the inheritance before repair the rules." - $prompt = "Shall I remove the inheritace?" + $prompt = "Shall I remove the inheritance?" $description = "Remove inheritance of '$FilePath'." if($pscmdlet.ShouldProcess($description, $prompt, $message)) @@ -734,4 +808,4 @@ function Enable-Privilege { $type[0]::EnablePrivilege($Privilege, $Disable) } -Export-ModuleMember -Function Repair-FilePermission, Repair-SshdConfigPermission, Repair-SshdHostKeyPermission, Repair-AuthorizedKeyPermission, Repair-UserKeyPermission, Repair-UserSshConfigPermission, Enable-Privilege, Get-UserAccount, Get-UserSID, Repair-AdministratorsAuthorizedKeysPermission, Repair-ModuliFilePermission +Export-ModuleMember -Function Repair-FilePermission, Repair-SshdConfigPermission, Repair-SshdHostKeyPermission, Repair-AuthorizedKeyPermission, Repair-UserKeyPermission, Repair-UserSshConfigPermission, Enable-Privilege, Get-UserAccount, Get-UserSID, Repair-AdministratorsAuthorizedKeysPermission, Repair-ModuliFilePermission, Repair-SSHFolderPermission diff --git a/contrib/win32/openssh/install-sshd.ps1 b/contrib/win32/openssh/install-sshd.ps1 index 59da1df62..94a3ba1f8 100644 --- a/contrib/win32/openssh/install-sshd.ps1 +++ b/contrib/win32/openssh/install-sshd.ps1 @@ -2,6 +2,7 @@ # @friism - Fixed issue with invalid SDDL on Set-Acl # @manojampalam - removed ntrights.exe dependency # @bingbing8 - removed secedit.exe dependency +# @tessgauthier - added permissions check for %programData%/ssh $ErrorActionPreference = 'Stop' @@ -84,6 +85,13 @@ if (Test-Path $moduliPath -PathType Leaf) Repair-ModuliFilePermission -FilePath $moduliPath @psBoundParameters -confirm:$false } +# If %programData%/ssh folder already exists, verify and, if necessary and approved by user, fix permissions +$sshProgDataPath = Join-Path $env:ProgramData "ssh" +if (Test-Path $sshProgDataPath) +{ + Repair-SSHFolderPermission -sshProgDataPath $sshProgDataPath +} + #register etw provider wevtutil im `"$etwman`"