diff --git a/lib/ansible/modules/windows/win_acl.ps1 b/lib/ansible/modules/windows/win_acl.ps1 index 9cd5e8c372d..0bc4b96e18f 100644 --- a/lib/ansible/modules/windows/win_acl.ps1 +++ b/lib/ansible/modules/windows/win_acl.ps1 @@ -91,6 +91,18 @@ $state = Get-AnsibleParam -obj $params -name "state" -type "str" -default "prese $inherit = Get-AnsibleParam -obj $params -name "inherit" -type "str" $propagation = Get-AnsibleParam -obj $params -name "propagation" -type "str" -default "None" -validateset "InheritOnly","None","NoPropagateInherit" +# We mount the HKCR, HKU, and HKCC registry hives so PS can access them +$path_qualifier = Split-Path -Path $path -Qualifier +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 file or directory does not exist on the host" } @@ -108,9 +120,14 @@ 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. +Push-Location -LiteralPath $path_qualifier + Try { SetPrivilegeTokens - If ($path -match "^HK(CC|CR|CU|LM|U):\\") { + $path_item = Get-Item -LiteralPath $path -Force + If ($path_item.PSProvider.Name -eq "Registry") { $colRights = [System.Security.AccessControl.RegistryRights]$rights } Else { @@ -128,7 +145,7 @@ Try { } $objUser = New-Object System.Security.Principal.SecurityIdentifier($sid) - If ($path -match "^HK(CC|CR|CU|LM|U):\\") { + If ($path_item.PSProvider.Name -eq "Registry") { $objACE = New-Object System.Security.AccessControl.RegistryAccessRule ($objUser, $colRights, $InheritanceFlag, $PropagationFlag, $objType) } Else { @@ -153,7 +170,7 @@ Try { $ruleIdentity = $rule.IdentityReference.Translate([System.Security.Principal.SecurityIdentifier]) } - If ($path -match "^HK(CC|CR|CU|LM|U):\\") { + If ($path_item.PSProvider.Name -eq "Registry") { If (($rule.RegistryRights -eq $objACE.RegistryRights) -And ($rule.AccessControlType -eq $objACE.AccessControlType) -And ($ruleIdentity -eq $objACE.IdentityReference) -And ($rule.IsInherited -eq $objACE.IsInherited) -And ($rule.InheritanceFlags -eq $objACE.InheritanceFlags) -And ($rule.PropagationFlags -eq $objACE.PropagationFlags)) { $match = $true Break @@ -198,7 +215,13 @@ Try { } } Catch { + $result.exception = ($_ | Out-String) + $result.test = ($pwd.Path) 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 + Pop-Location +} Exit-Json -obj $result diff --git a/test/integration/targets/win_acl/defaults/main.yml b/test/integration/targets/win_acl/defaults/main.yml index 959a36ce423..53532202ac5 100644 --- a/test/integration/targets/win_acl/defaults/main.yml +++ b/test/integration/targets/win_acl/defaults/main.yml @@ -1,2 +1,4 @@ --- test_acl_path: '{{ win_output_dir }}\win_acl .ÅÑŚÌβŁÈ [$!@^&test(;)]' +# Use HKU as that path is not automatically loaded in the PSProvider making our test more complex +test_acl_reg_path: HKU:\.DEFAULT\Ansible Test .ÅÑŚÌβŁÈ [$!@^&test(;)] diff --git a/test/integration/targets/win_acl/tasks/main.yml b/test/integration/targets/win_acl/tasks/main.yml index 56cac985fc5..d322fb893a1 100644 --- a/test/integration/targets/win_acl/tasks/main.yml +++ b/test/integration/targets/win_acl/tasks/main.yml @@ -7,6 +7,15 @@ - absent - directory +- name: ensure we start with a clean reg path + win_regedit: + path: '{{ test_acl_reg_path }}' + delete_key: yes + state: '{{ item }}' + with_items: + - absent + - present + - block: - name: run tests include_tasks: tests.yml @@ -16,3 +25,9 @@ win_file: path: '{{ test_acl_path }}' state: absent + + - name: cleanup testing reg path + win_regedit: + path: '{{ test_acl_reg_path }}' + delete_key: yes + state: absent diff --git a/test/integration/targets/win_acl/tasks/tests.yml b/test/integration/targets/win_acl/tasks/tests.yml index de438b2a48d..68601dc8ba3 100644 --- a/test/integration/targets/win_acl/tasks/tests.yml +++ b/test/integration/targets/win_acl/tasks/tests.yml @@ -3,15 +3,24 @@ - name: get register cmd that will get ace info set_fact: test_ace_cmd: | + # Overcome bug in Set-Acl/Get-Acl for registry paths and -LiteralPath + New-PSDrive -Name HKU -PSProvider Registry -Root HKEY_USERS > $null + Push-Location -LiteralPath (Split-Path -Path $path -Qualifier) + $rights_key = if ((Get-Item -LiteralPath $path -Force).PSProvider.Name -eq "Registry") { + "RegistryRights" + } else { + "FileSystemRights" + } $ace_list = (Get-Acl -LiteralPath $path).Access | Where-Object { $_.IsInherited -eq $false } | ForEach-Object { @{ - rights = $_.FileSystemRights.ToString() + rights = $_."$rights_key".ToString() type = $_.AccessControlType.ToString() identity = $_.IdentityReference.Value.ToString() inheritance_flags = $_.InheritanceFlags.ToString() propagation_flags = $_.PropagationFlags.ToString() } } + Pop-Location ConvertTo-Json -InputObject @($ace_list) - name: add write rights to Guest @@ -161,3 +170,151 @@ assert: that: - not remove_deny_right_again is changed + +- name: add write rights to Guest - registry + win_acl: + path: '{{ test_acl_reg_path }}' + type: allow + user: Guests + rights: WriteKey + register: allow_right_reg + +- name: get result of add write rights to Guest - registry + win_shell: '$path = ''{{ test_acl_reg_path }}''; {{ test_ace_cmd }}' + register: allow_right_reg_actual + +- name: assert add write rights to Guest - registry + assert: + that: + - allow_right_reg is changed + - (allow_right_reg_actual.stdout|from_json)|count == 1 + - (allow_right_reg_actual.stdout|from_json)[0].identity == 'BUILTIN\Guests' + - (allow_right_reg_actual.stdout|from_json)[0].inheritance_flags == 'ContainerInherit, ObjectInherit' + - (allow_right_reg_actual.stdout|from_json)[0].propagation_flags == 'None' + - (allow_right_reg_actual.stdout|from_json)[0].rights == 'WriteKey' + - (allow_right_reg_actual.stdout|from_json)[0].type == 'Allow' + +- name: add write rights to Guest (idempotent) - registry + win_acl: + path: '{{ test_acl_reg_path }}' + type: allow + user: Guests + rights: WriteKey + register: allow_right_reg_again + +- name: assert add write rights to Guest (idempotent) - registry + assert: + that: + - not allow_right_reg_again is changed + +- name: remove write rights from Guest - registry + win_acl: + path: '{{ test_acl_reg_path }}' + type: allow + user: Guests + rights: WriteKey + state: absent + register: remove_right_reg + +- name: get result of remove write rights from Guest - registry + win_shell: '$path = ''{{ test_acl_reg_path }}''; {{ test_ace_cmd }}' + register: remove_right_reg_actual + +- name: assert remove write rights from Guest - registry + assert: + that: + - remove_right_reg is changed + - remove_right_reg_actual.stdout_lines == ["[", "", "]"] + +- name: remove write rights from Guest (idempotent) - registry + win_acl: + path: '{{ test_acl_reg_path }}' + type: allow + user: Guests + rights: WriteKey + state: absent + register: remove_right_reg_again + +- name: assert remote write rights from Guest (idempotent) - registry + assert: + that: + - not remove_right_reg_again is changed + +- name: add deny write rights to Guest - registry + win_acl: + path: '{{ test_acl_reg_path }}' + type: deny + user: Guests + rights: WriteKey + inherit: ContainerInherit + propagation: NoPropagateInherit + state: present + register: add_deny_right_reg + +- name: get result of add deny write rights to Guest - registry + win_shell: '$path = ''{{ test_acl_reg_path }}''; {{ test_ace_cmd }}' + register: add_deny_right_reg_actual + +- name: assert add deny write rights to Guest - registry + assert: + that: + - add_deny_right_reg is changed + - (add_deny_right_reg_actual.stdout|from_json)|count == 1 + - (add_deny_right_reg_actual.stdout|from_json)[0].identity == 'BUILTIN\Guests' + - (add_deny_right_reg_actual.stdout|from_json)[0].inheritance_flags == 'ContainerInherit' + - (add_deny_right_reg_actual.stdout|from_json)[0].propagation_flags == 'NoPropagateInherit' + - (add_deny_right_reg_actual.stdout|from_json)[0].rights == 'WriteKey' + - (add_deny_right_reg_actual.stdout|from_json)[0].type == 'Deny' + +- name: add deny write rights to Guest (idempotent) - registry + win_acl: + path: '{{ test_acl_reg_path }}' + type: deny + user: Guests + rights: WriteKey + inherit: ContainerInherit + propagation: NoPropagateInherit + state: present + register: add_deny_right_reg_again + +- name: assert add deny write rights to Guest (idempotent) - registry + assert: + that: + - not add_deny_right_reg_again is changed + +- name: remove deny write rights from Guest - registry + win_acl: + path: '{{ test_acl_reg_path }}' + type: deny + user: Guests + rights: WriteKey + inherit: ContainerInherit + propagation: NoPropagateInherit + state: absent + register: remove_deny_right_reg + +- name: get result of remove deny write rights from Guest - registry + win_shell: '$path = ''{{ test_acl_reg_path }}''; {{ test_ace_cmd }}' + register: remove_deny_right_reg_actual + +- name: assert remove deny write rights from Guest - registry + assert: + that: + - remove_deny_right_reg is changed + - remove_deny_right_reg_actual.stdout_lines == ["[", "", "]"] + +- name: remove deny write rights from Guest (idempotent) - registry + win_acl: + path: '{{ test_acl_reg_path }}' + type: deny + user: Guests + rights: WriteKey + inherit: ContainerInherit + propagation: NoPropagateInherit + state: absent + register: remove_deny_right_reg_again + +- name: assert remove deny write rights from Guest (idempotent) - registry + assert: + that: + - not remove_deny_right_reg_again is changed