Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changes RegistryAccessEntry to correctly remove specific ACEs from ACLs and gracefully handle the App Packages Principal, Issues #37 and #38 #39

Merged
merged 7 commits into from
Jan 3, 2019
168 changes: 133 additions & 35 deletions DscResources/RegistryAccessEntry/RegistryAccessEntry.psm1
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Import-Module -Name (Join-Path -Path ( Split-Path $PSScriptRoot -Parent ) `
-ChildPath 'AccessControlResourceHelper\AccessControlResourceHelper.psm1') `
-Force
-Force

# Localized messages
data LocalizedData
Expand Down Expand Up @@ -53,10 +53,8 @@ Function Get-TargetResource
foreach ($Principal in $AccessControlList)
chasewilson marked this conversation as resolved.
Show resolved Hide resolved
{
$CimAccessControlEntries = New-Object -TypeName 'System.Collections.ObjectModel.Collection`1[Microsoft.Management.Infrastructure.CimInstance]'

$PrincipalName = $Principal.Principal
$ForcePrincipal = $Principal.ForcePrincipal

$Identity = Resolve-Identity -Identity $PrincipalName
$currentPrincipalAccess = $currentACL.Access.Where( {$_.IdentityReference -eq $Identity.Name})
foreach ($Access in $currentPrincipalAccess)
Expand Down Expand Up @@ -122,6 +120,7 @@ Function Set-TargetResource
}

$currentAcl = Get-Acl -Path $Path

if ($null -eq $currentAcl)
{
$currentAcl = New-Object -TypeName "System.Security.AccessControl.RegistrySecurity"
Expand All @@ -134,14 +133,11 @@ Function Set-TargetResource
$Principal = $AccessControlItem.Principal
$Identity = Resolve-Identity -Identity $Principal
$IdentityRef = New-Object System.Security.Principal.NTAccount($Identity.Name)

$ACLRules += ConvertTo-RegistryAccessRule -AccessControlList $AccessControlItem -IdentityRef $IdentityRef
}

$actualAce = $currentAcl.Access

$Results = Compare-RegistryRule -Expected $ACLRules -Actual $actualAce

$Expected = $Results.Rules
$AbsentToBeRemoved = $Results.Absent
$ToBeRemoved = $Results.ToBeRemoved
Expand All @@ -153,12 +149,9 @@ Function Set-TargetResource
$Principal = $AccessControlItem.Principal
$Identity = Resolve-Identity -Identity $Principal
$IdentityRef = New-Object System.Security.Principal.NTAccount($Identity.Name)

$actualAce = $currentAcl.Access.Where( {$_.IdentityReference -eq $Identity.Name})

$actualAce = $currentAcl.Access.Where( {$_.IdentityReference -eq $Identity.Name} )
$ACLRules = ConvertTo-RegistryAccessRule -AccessControlList $AccessControlItem -IdentityRef $IdentityRef
$Results = Compare-RegistryRule -Expected $ACLRules -Actual $actualAce

$Expected += $Results.Rules
$AbsentToBeRemoved += $Results.Absent

Expand All @@ -169,13 +162,27 @@ Function Set-TargetResource
}
}
$isInherited = 0
$isInherited += $AbsentToBeRemoved.Rule.Where( {$_.IsInherited -eq $true}).Count
$isInherited += $ToBeRemoved.Rule.Where( {$_.IsInherited -eq $true}).Count
$isInherited += $AbsentToBeRemoved.Rule.Where( {$_.IsInherited -eq $true} ).Count
$isInherited += $ToBeRemoved.Rule.Where( {$_.IsInherited -eq $true} ).Count

if ($isInherited -gt 0)
{
$currentAcl.SetAccessRuleProtection($true, $true)
Set-Acl -Path $Path -AclObject $currentAcl
$currentAcl = Get-Acl -Path $Path
}

<#
If currentAcl contains an Access Rule for the "APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES" principal
and has a RegistryRight that doesn't translate to a correct RegistryRights enum, then remove it and readd
the correctly translated Access Rule. This is a workaround for the translation issue with 'ALL APPLICATION PACKAGES'
#>
$allAppPackagePrincipal = 'APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES'
$registryRightsEnum = [enum]::GetValues([System.Security.AccessControl.RegistryRights])
$invalidRegRightEnumAllAppPackage = $currentAcl.Where( {$_.IdentityReference -eq $allAppPackagePrincipal -and $registryRightsEnum -notcontains $_.RegistryRights} )
if ($null -ne $invalidRegRightEnumAllAppPackage)
{
$currentAcl = Set-RegistryRightsAclAllAppPackages -AclObject $currentAcl
}

foreach ($Rule in $AbsentToBeRemoved.Rule)
Expand Down Expand Up @@ -269,14 +276,11 @@ Function Test-TargetResource
$Principal = $AccessControlItem.Principal
$Identity = Resolve-Identity -Identity $Principal
$IdentityRef = New-Object System.Security.Principal.NTAccount($Identity.Name)

$ACLRules += ConvertTo-RegistryAccessRule -AccessControlList $AccessControlItem -IdentityRef $IdentityRef
}

$actualAce = $currentAcl.Access

$Results = Compare-RegistryRule -Expected $ACLRules -Actual $actualAce

$Expected = $Results.Rules
$AbsentToBeRemoved = $Results.Absent
$ToBeRemoved = $Results.ToBeRemoved
Expand All @@ -288,21 +292,16 @@ Function Test-TargetResource
$Principal = $AccessControlItem.Principal
$Identity = Resolve-Identity -Identity $Principal
$IdentityRef = New-Object System.Security.Principal.NTAccount($Identity.Name)

$ACLRules = ConvertTo-RegistryAccessRule -AccessControlList $AccessControlItem -IdentityRef $IdentityRef

$actualAce = $currentAcl.Access.Where( {$_.IdentityReference -eq $Identity.Name})

$actualAce = $currentAcl.Access.Where( {$_.IdentityReference -eq $Identity.Name} )
$Results = Compare-RegistryRule -Expected $ACLRules -Actual $actualAce

$Expected += $Results.Rules
$AbsentToBeRemoved += $Results.Absent

if ($AccessControlItem.ForcePrinciPal)
{
$ToBeRemoved += $Results.ToBeRemoved
}

}
}

Expand Down Expand Up @@ -373,11 +372,12 @@ Function Compare-RegistryRule
$ToBeRemoved = @()
$AbsentToBeRemoved = @()

$PresentRules = $Expected.Where( {$_.Ensure -eq 'Present'}).Rules
$AbsentRules = $Expected.Where( {$_.Ensure -eq 'Absent'}).Rules
$PresentRules = $Expected.Where( {$_.Ensure -eq 'Present'} ).Rules
$AbsentRules = $Expected.Where( {$_.Ensure -eq 'Absent'} ).Rules

foreach ($refrenceObject in $PresentRules)
{
$match = $Actual.Where( {
$match = $Actual.Where({
$_.RegistryRights -eq $refrenceObject.RegistryRights -and
$_.InheritanceFlags -eq $refrenceObject.InheritanceFlags -and
$_.PropagationFlags -eq $refrenceObject.PropagationFlags -and
Expand All @@ -402,7 +402,7 @@ Function Compare-RegistryRule

foreach ($refrenceObject in $Actual)
{
$match = @($Expected.Rules).Where( {
$match = @($Expected.Rules).Where({
$_.RegistryRights -eq $refrenceObject.RegistryRights -and
$_.InheritanceFlags -eq $refrenceObject.InheritanceFlags -and
$_.PropagationFlags -eq $refrenceObject.PropagationFlags -and
Expand All @@ -419,7 +419,7 @@ Function Compare-RegistryRule

foreach ($refrenceObject in $AbsentRules)
{
$match = $Actual.Where( {
$match = $Actual.Where({
$_.RegistryRights -eq $refrenceObject.RegistryRights -and
$_.InheritanceFlags -eq $refrenceObject.InheritanceFlags -and
$_.PropagationFlags -eq $refrenceObject.PropagationFlags -and
Expand Down Expand Up @@ -501,17 +501,14 @@ Function Get-RegistryRuleInheritenceName
"0-0"
{
return "This Key Only"

}
"1-0"
{
return "This Key and Subkeys"

}
"1-2"
{
return "Subkeys Only"

}
}

Expand All @@ -520,17 +517,17 @@ Function Get-RegistryRuleInheritenceName

<#
.SYNOPSIS
Takes a Rule object and converts the Principle Name to a SID
Takes a Rule object and converts the Principle Name to a SID

.PARAMETER Rule
A single Registry Access Rule to be converted
A single Registry Access Rule to be converted

.EXAMPLE
$sidRule = ConvertTo-SidIdentityRegistryAccessRule -Rule $Rule
$sidRule = ConvertTo-SidIdentityRegistryAccessRule -Rule $Rule

.NOTES
This function was created to address translation issues with accounts such as
'APPLICATION PACKAGE AUTHORITY\ALL RESTRICTED APPLICATION PACKAGES'.
This function was created to address translation issues with accounts such as
'APPLICATION PACKAGE AUTHORITY\ALL RESTRICTED APPLICATION PACKAGES'.
#>

function ConvertTo-SidIdentityRegistryAccessRule
Expand All @@ -554,7 +551,108 @@ function ConvertTo-SidIdentityRegistryAccessRule
}

$SID = $Principal.Translate([System.Security.Principal.SecurityIdentifier])
chasewilson marked this conversation as resolved.
Show resolved Hide resolved
$SIDRule = New-Object System.Security.AccessControl.RegistryAccessRule($SID, $Rule.RegistryRights.value__, $Rule.InheritanceFlags.value__, $Rule.PropagationFlags.value__, $Rule.AccessControlType.value__)
$SIDRule = [System.Security.AccessControl.RegistryAccessRule]::new($SID, $Rule.RegistryRights.value__, $Rule.InheritanceFlags.value__, $Rule.PropagationFlags.value__, $Rule.AccessControlType.value__)

return $SIDRule
}

<#
.SYNOPSIS
Takes an ACL that contains the APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES principles with
an invalid RegistryRights enumeration and replaces them with their correct versions.

.PARAMETER AclObject
An ACL that contains APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES as the IdentityReference and
an invalid RegistryRights value, i.e.: -2147483648 (Generic Read) or 268435456 (Full Control)

.EXAMPLE
$modifiedAcl = Set-AllAppPackagesRegistryRightsAcl -AclObject $currentAcl

.NOTES
This function was created to address translation / ACE removal issues with the
'APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES' principal.
#>
function Set-RegistryRightsAclAllAppPackages
{
[CmdletBinding()]
[OutputType([System.Security.AccessControl.RegistrySecurity])]
Param
(
[Parameter(Mandatory = $true)]
[System.Security.AccessControl.RegistrySecurity]
$AclObject
)

$data = @{
IdentityReference = 'APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES'
RegistryRightEnums = [enum]::GetValues([System.Security.AccessControl.RegistryRights])
RegistryRights = @{
FullControl = 268435456
ReadKey = -2147483648
}
}

$allAppPackagesRegistryRule = $AclObject.Access.Where( {$_.IdentityReference -eq $data['IdentityReference']} )

<#
In order to remove the invalid RegistryRights ACEs, the RemoveAccessRuleAll method will be used, removing either Allow or Deny entries
for a given SID/Account. The result is AclObject will not have any 'ALL APPLICATION PACKAGES' Access Rules, until they are reapplied in the
second switch statement. The "ReadKey" RegistryRight is ignored when using the RemoveAccessRuleAll method, any RegistryRight would
work. The RemoveAccessRuleAll method evaluates the SID/Account and AccessControlType only, everything else in the AccessRule is ignored.
#>
switch ($allAppPackagesRegistryRule.AccessControlType | Select-Object -Unique)
{
'Allow'
{
$removeAllRule = [System.Security.AccessControl.RegistryAccessRule]::new('ALL APPLICATION PACKAGES', 'ReadKey', 0, 0, 'Allow')
$AclObject.RemoveAccessRuleAll($removeAllRule)
}

'Deny'
{
$removeAllRule = [System.Security.AccessControl.RegistryAccessRule]::new('ALL APPLICATION PACKAGES', 'ReadKey', 0, 0, 'Deny')
$AclObject.RemoveAccessRuleAll($removeAllRule)
}
}

switch ($allAppPackagesRegistryRule)
{
{
$_.IdentityReference -eq $data['IdentityReference'] -and $_.RegistryRights -eq $data['RegistryRights']['FullControl']
}
{
$newRegistryAccessRule = [System.Security.AccessControl.RegistryAccessRule]::new(
'ALL APPLICATION PACKAGES',
'FullControl',
$_.InheritanceFlags,
$_.PropagationFlags,
$_.AccessControlType
)
$AclObject.AddAccessRule($newRegistryAccessRule)
}

{
$_.IdentityReference -eq $data['IdentityReference'] -and $_.RegistryRights -eq $data['RegistryRights']['ReadKey']
}
{
$newRegistryAccessRule = [System.Security.AccessControl.RegistryAccessRule]::new(
'ALL APPLICATION PACKAGES',
'ReadKey',
$_.InheritanceFlags,
$_.PropagationFlags,
$_.AccessControlType
)
$AclObject.AddAccessRule($newRegistryAccessRule)
}
}

$validAccessRules = $allAppPackagesRegistryRule.Where( {$_.IdentityReference -eq $data['IdentityReference'] -and $data['RegistryRightEnums'] -contains $_.RegistryRights} )

foreach ($validAccessRule in $validAccessRules)
{
$convertedValidSidRule = ConvertTo-SidIdentityRegistryAccessRule -Rule $validAccessRule
[void]$AclObject.AddAccessRule($convertedValidSidRule)
}

return $AclObject
}
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Please check out common DSC Resources [contributing guidelines](

* **[String] ObjectType:** Specifies the object type name that identifies the type of child object that can inherit this access rule.

* [String] ForcePrincipal: Indicates whether the rights for this principal should be forced. Will remove any rights not explicitly defined in the configuration for the principal.
* **[String] ForcePrincipal:** Indicates whether the rights for this principal should be forced. Will remove any rights not explicitly defined in the configuration for the principal.

#### ActiveDirectoryAccessRule Examples

Expand All @@ -78,9 +78,9 @@ Please check out common DSC Resources [contributing guidelines](

* **[String] InheritedObjectType:** Specifies the object type name that identifies the type of child object that can inherit this access rule.

* [String] ForcePrincipal: Indicates whether the rights for this principal should be forced. Will remove any rights not explicitly defined in the configuration for the principal.
* **[String] ForcePrincipal:** Indicates whether the rights for this principal should be forced. Will remove any rights not explicitly defined in the configuration for the principal.

* [Boolean] Force: Indicates whether the rights defined should be enforced. Will remove any rights not explicitly defined in the configuration for the path.
* **[Boolean] Force:** Indicates whether the rights defined should be enforced. Will remove any rights not explicitly defined in the configuration for the path.

#### ActiveDirectoryAuditRule Examples

Expand All @@ -105,9 +105,9 @@ Please check out common DSC Resources [contributing guidelines](

* **[String] Inheritance:** Indicates the inheritance type of the permission entry.

* [String] ForcePrincipal: Indicates whether the rights for this principal should be forced. Will remove any rights not explicitly defined in the configuration for the principal.
* **[String] ForcePrincipal:** Indicates whether the rights for this principal should be forced. Will remove any rights not explicitly defined in the configuration for the principal.

* [Boolean] Force: Indicates whether the rights defined should be enforced. Will remove any rights not explicitly defined in the configuration for the path.
* **[Boolean] Force:** Indicates whether the rights defined should be enforced. Will remove any rights not explicitly defined in the configuration for the path.

#### NtfsAccessEntry Examples

Expand All @@ -132,9 +132,9 @@ Please check out common DSC Resources [contributing guidelines](

* **[String] Inheritance:** Indicates the inheritance type of the permission entry. _{ This Key Only | This Key and Subkeys | SubKeys Only }_

* [String] ForcePrincipal: Indicates whether the rights for this principal should be forced. Will remove any rights not explicitly defined in the configuration for the principal.
* **[String] ForcePrincipal:** Indicates whether the rights for this principal should be forced. Will remove any rights not explicitly defined in the configuration for the principal.

* [Boolean] Force: Indicates whether the rights defined should be enforced. Will remove any rights not explicitly defined in the configuration for the path.
* **[Boolean] Force:** Indicates whether the rights defined should be enforced. Will remove any rights not explicitly defined in the configuration for the path.

#### RegistryAccessEntry Examples

Expand Down
Loading