Open jborean93 opened 4 years ago
From @dagwieers on Oct 05, 2018 13:20
needs_contributor
Hello, What exactly "reset" should mean?
Based on the context of icacls it would be
Replaces ACLs with default inherited ACLs for all matching files.
So your first option.
Well this may be dangerous when used on system folders like %SystemRoot% or %ProgramFiles% and so on...
Should the solution use the Linux mindset: "You're the root (Admin), you should know what you're doing", or the Microsoft one: "Let me protect from yourself" ?
@jborean93 I've implemented the reset functionality in my win_acl version. See additional improvements in my issue: #110 It still needs extensive testing, and the documentation part of the new state value. Let me know how to contribute. here is the win_acl.ps1 content:
#!powershell
# Copyright: (c) 2015, Phil Schwartz <schwartzmx@gmail.com>
# Copyright: (c) 2015, Trond Hindenes
# Copyright: (c) 2015, Hans-Joachim Kliemeck <git@kliemeck.de>
# Revorked the logic to more exact handle of rights and proper return values,
# Added state='reset' option to reset the ACL to the inherited ACEs only.
# https://github.com/ansible-collections/ansible.windows/issues/18
# Added support of environment variables for Path
# https://github.com/ansible/ansible/issues/68597
# Laszlo Papp <laca@placa.me>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#Requires -Module Ansible.ModuleUtils.Legacy
#Requires -Module Ansible.ModuleUtils.PrivilegeUtil
#Requires -Module Ansible.ModuleUtils.SID
$ErrorActionPreference = "Stop"
# win_acl module (File/Resources Permission Additions/Removal)
#Functions
function Get-UserSID {
param(
[String]$AccountName
)
$userSID = $null
$searchAppPools = $false
if ($AccountName.Split("\").Count -gt 1) {
if ($AccountName.Split("\")[0] -eq "IIS APPPOOL") {
$searchAppPools = $true
$AccountName = $AccountName.Split("\")[1]
}
}
if ($searchAppPools) {
Import-Module -Name WebAdministration
$testIISPath = Test-Path -LiteralPath "IIS:"
if ($testIISPath) {
$appPoolObj = Get-ItemProperty -LiteralPath "IIS:\AppPools\$AccountName"
$userSID = $appPoolObj.applicationPoolSid
}
}
else {
$userSID = Convert-ToSID -account_name $AccountName
}
return $userSID
}
$params = Parse-Args $args
Function SetPrivilegeTokens() {
# Set privilege tokens only if admin.
# Admins would have these privs or be able to set these privs in the UI Anyway
$adminRole=[System.Security.Principal.WindowsBuiltInRole]::Administrator
$myWindowsID=[System.Security.Principal.WindowsIdentity]::GetCurrent()
$myWindowsPrincipal=new-object System.Security.Principal.WindowsPrincipal($myWindowsID)
if ($myWindowsPrincipal.IsInRole($adminRole)) {
# Need to adjust token privs when executing Set-ACL in certain cases.
# e.g. d:\testdir is owned by group in which current user is not a member and no perms are inherited from d:\
# This also sets us up for setting the owner as a feature.
# See the following for details of each privilege
# https://msdn.microsoft.com/en-us/library/windows/desktop/bb530716(v=vs.85).aspx
$privileges = @(
"SeRestorePrivilege", # Grants all write access control to any file, regardless of ACL.
"SeBackupPrivilege", # Grants all read access control to any file, regardless of ACL.
"SeTakeOwnershipPrivilege" # Grants ability to take owernship of an object w/out being granted discretionary access
)
foreach ($privilege in $privileges) {
$state = Get-AnsiblePrivilege -Name $privilege
if ($state -eq $false) {
Set-AnsiblePrivilege -Name $privilege -Value $true
}
}
}
}
$result = @{
changed = $false
msg = ""
}
$path = (New-Object -ComObject Wscript.Shell).ExpandEnvironmentStrings(Get-AnsibleParam -obj $params -name "path" -type "str" -failifempty $true)
# We mount the HKCR, HKU, and HKCC registry hives so PS can access them.
# Network paths have no qualifiers so we use -EA SilentlyContinue to ignore that
$path_qualifier = Split-Path -Path $path -Qualifier -ErrorAction SilentlyContinue
if ($path_qualifier -eq "HKCR:" -and (-not (Test-Path -LiteralPath HKCR:\))) {
New-PSDrive -Name HKCR -PSProvider Registry -Root HKEY_CLASSES_ROOT > $null
}
if ($path_qualifier -eq "HKU:" -and (-not (Test-Path -LiteralPath HKU:\))) {
New-PSDrive -Name HKU -PSProvider Registry -Root HKEY_USERS > $null
}
if ($path_qualifier -eq "HKCC:" -and (-not (Test-Path -LiteralPath HKCC:\))) {
New-PSDrive -Name HKCC -PSProvider Registry -Root HKEY_CURRENT_CONFIG > $null
}
If (-Not (Test-Path -LiteralPath $path)) {
Fail-Json -obj $result -message "$path does not exist on the host"
}
$path_item = Get-Item -LiteralPath $path -Force
$state = Get-AnsibleParam -obj $params -name "state" -type "str" -default "present" -validateset "absent","present","reset"
if($state -eq 'reset'){
SetPrivilegeTokens
if(!(Get-Item $path).PSParentPath){
Fail-Json -obj $result -message "$path is a root folder! Cannot reset ACL!"
}
try
{
$objACL = Get-ACL -LiteralPath $path
if($objACL.AreAccessRulesProtected){
$result.changed=$true
$objacl.SetAccessRuleProtection($false,$false)
If ($path_item.PSProvider.Name -eq "Registry") {
Set-ACL -LiteralPath $path -AclObject $objACL
} else {
(Get-Item -LiteralPath $path).SetAccessControl($objACL)
}
$objACL = Get-ACL -LiteralPath $path
}
$changed=$false
$objACL.Access|?{!$_.isinherited}|%{
$result.changed=$true
$changed=$true
[void]$objACL.RemoveAccessRule($_)
}
if($changed){
If ($path_item.PSProvider.Name -eq "Registry") {
Set-ACL -LiteralPath $path -AclObject $objACL
} else {
(Get-Item -LiteralPath $path).SetAccessControl($objACL)
}
}
Exit-Json -obj $result
} catch {
Fail-Json -obj $result -message "an exception occurred when resetting the ACL - $($_.Exception.Message)"
}
}
$user = Get-AnsibleParam -obj $params -name "user" -type "str" -failifempty $true
$rights = Get-AnsibleParam -obj $params -name "rights" -type "str" -failifempty $true
$type = Get-AnsibleParam -obj $params -name "type" -type "str" -failifempty $true -validateset "allow","deny"
$inherit = Get-AnsibleParam -obj $params -name "inherit" -type "str"
$propagation = Get-AnsibleParam -obj $params -name "propagation" -type "str" -default "None" -validateset "InheritOnly","None","NoPropagateInherit"
# Reset:
# Test that the user/group is resolvable on the local machine
$sid = Get-UserSID -AccountName $user
if (!$sid) {
Fail-Json -obj $result -message "$user is not a valid user or group on the host machine or domain"
}
If (Test-Path -LiteralPath $path -PathType Leaf) {
$inherit = "None"
}
ElseIf ($null -eq $inherit) {
$inherit = "ContainerInherit, ObjectInherit"
}
# Bug in Set-Acl, Get-Acl where -LiteralPath only works for the Registry provider if the location is in that root
# qualifier. We also don't have a qualifier for a network path so only change if not null
if ($null -ne $path_qualifier) {
Push-Location -LiteralPath $path_qualifier
}
$myMessage=""
Try {
SetPrivilegeTokens
$PathType='FileSystem'
If ($path_item.PSProvider.Name -eq "Registry") {$PathType='Registry'}
$InheritanceFlag = [System.Security.AccessControl.InheritanceFlags]$inherit
$PropagationFlag = [System.Security.AccessControl.PropagationFlags]$propagation
If ($type -eq "deny") {
$objType =[System.Security.AccessControl.AccessControlType]::Deny
}
Else {
$objType =[System.Security.AccessControl.AccessControlType]::Allow
}
$objUser = New-Object System.Security.Principal.SecurityIdentifier($sid)
$objACE = New-Object System.Security.AccessControl."$($PathType)AccessRule" ($objUser, $Rights, $InheritanceFlag, $PropagationFlag, $objType)
$objACL = Get-ACL -LiteralPath $path
$objOldRules=$objACL.AccessToString
$objRights=$null
if($PathType -eq 'Registry'){
$objRights=[System.Security.AccessControl.RegistryRights]$rights
}else{
$objRights=[System.Security.AccessControl.FileSystemRights]$rights
}
Try {
$ar=$null
If ($state -eq "present"){
$objACL.AddAccessRule($objACE)
} else {
[void]$objACL.RemoveAccessRule($objACE)
$objACL.GetAccessRules($true, $true, [System.Security.Principal.SecurityIdentifier])|?{
($_.IdentityReference.Value -eq $sid) -and
(($_.PropagationFlags -band [System.Security.AccessControl.PropagationFlags]'InheritOnly') -ne
[System.Security.AccessControl.PropagationFlags]'InheritOnly') -and
($_.AccessControlType -eq $objType)
}|%{
if(!$ar){$ar=$_."$($PathType)Rights"}else{$ar=$ar -bor $_."$($PathType)Rights"}
}
}
$myMessage="Actual rights: "
$objACL.GetAccessRules($true, $true, [System.Security.Principal.SecurityIdentifier])|?{$_.IdentityReference.Value -eq $sid}|%{
$myMessage += "$($_.AccessControlType): $($_."$($PathType)Rights"): $(if($_.IsInherited){'Inherited,'}) $($_.InheritanceFlags); "
}
if($objOldRules -eq $objACL.AccessToString){
$result.changed = $false
$result.msg=$myMessage
} else {
If ($path_item.PSProvider.Name -eq "Registry") {
Set-ACL -LiteralPath $path -AclObject $objACL
} else {
(Get-Item -LiteralPath $path).SetAccessControl($objACL)
}
$result.changed = $true
$myMessage=$myMessage.Replace('Actual rights: ','New rights: ')
$result.msg=$myMessage
}
if(($ar) -and (([int]($ar -band $objRights).value__) -ne 0 ) -and ($state -ne "present")){
$result.stderr="$user still has $ar rights!"
$result.msg=$myMessage
Fail-Json -obj $result -message "$user still has $ar rights! $myMessage"
}
}
Catch {
Fail-Json -obj $result -message "an exception occurred when adding the specified rule - $($_.Exception.Message)"
}
}
Catch {
Fail-Json -obj $result -message "an error occurred when attempting to $state $rights permission(s) on $path for $user - $($_.Exception.Message)"
}
Finally {
# Make sure we revert the location stack to the original path just for cleanups sake
if ($null -ne $path_qualifier) {
Pop-Location
}
}
Exit-Json -obj $result
@placame the short answer is that you fork this repository in GitHub, make your changes, and submit a pull request.
For the longer answer and more details, see https://github.com/ansible-collections/ansible.windows#contributing-to-this-collection
From @SagarKodam on Oct 05, 2018 13:09
SUMMARY
win_acl can be used to set ACL to files and folders, but cannot be used to reset the permissions.
ISSUE TYPE
COMPONENT NAME
win_acl
ADDITIONAL INFORMATION
Copied from original issue: ansible/ansible#46540