1 #!powershell
2
3 # Copyright: (c) 2017, Noah Sparks <nsparks@outlook.com>
4 # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
5
6 #Requires -Module Ansible.ModuleUtils.Legacy
7 #Requires -Module Ansible.ModuleUtils.SID
8
9 $params = Parse-Args -arguments $args -supports_check_mode $true
10 $check_mode = Get-AnsibleParam -obj $params -name "_ansible_check_mode" -type "bool" -default $false
11
12 # module parameters
13 $path = Get-AnsibleParam -obj $params -name "path" -type "path" -failifempty $true -aliases "destination","dest"
14 $user = Get-AnsibleParam -obj $params -name "user" -type "str" -failifempty $true
15 $rights = Get-AnsibleParam -obj $params -name "rights" -type "list"
16 $inheritance_flags = Get-AnsibleParam -obj $params -name "inheritance_flags" -type "list" -default 'ContainerInherit','ObjectInherit'
17 $propagation_flags = Get-AnsibleParam -obj $params -name "propagation_flags" -type "str" -default "none" -ValidateSet 'InheritOnly','None','NoPropagateInherit'
18 $audit_flags = Get-AnsibleParam -obj $params -name "audit_flags" -type "list" -default 'success'
19 $state = Get-AnsibleParam -obj $params -name "state" -type "str" -default "present" -validateset 'present','absent'
20
21 #Make sure target path is valid
22 If (-not (Test-Path -Path $path) )
23 {
24 Fail-Json -obj $result -message "defined path ($path) is not found/invalid"
25 }
26
27 #function get current audit rules and convert to hashtable
Get-CurrentAuditRules($path)28 Function Get-CurrentAuditRules ($path) {
29 Try {
30 $ACL = Get-Acl $path -Audit
31 }
32 Catch {
33 Return "Unable to retrieve the ACL on $Path"
34 }
35
36 $HT = Foreach ($Obj in $ACL.Audit)
37 {
38 @{
39 user = $Obj.IdentityReference.ToString()
40 rights = ($Obj | Select-Object -expand "*rights").ToString()
41 audit_flags = $Obj.AuditFlags.ToString()
42 is_inherited = $Obj.IsInherited.ToString()
43 inheritance_flags = $Obj.InheritanceFlags.ToString()
44 propagation_flags = $Obj.PropagationFlags.ToString()
45 }
46 }
47
48 If (-Not $HT)
49 {
50 "No audit rules defined on $path"
51 }
52 Else {$HT}
53 }
54
55 $result = @{
56 changed = $false
57 current_audit_rules = Get-CurrentAuditRules $path
58 }
59
60 #Make sure identity is valid and can be looked up
61 Try {
62 $SID = Convert-ToSid $user
63 }
64 Catch {
65 Fail-Json -obj $result -message "Failed to lookup the identity ($user) - $($_.exception.message)"
66 }
67
68 #get the path type
69 $ItemType = (Get-Item $path).GetType()
70 switch ($ItemType)
71 {
72 ([Microsoft.Win32.RegistryKey]) {$registry = $true; $result.path_type = 'registry'}
73 ([System.IO.FileInfo]) {$file = $true; $result.path_type = 'file'}
74 ([System.IO.DirectoryInfo]) {$result.path_type = 'directory'}
75 }
76
77 #Get current acl/audit rules on the target
78 Try {
79 $ACL = Get-Acl $path -Audit
80 }
81 Catch {
82 Fail-Json -obj $result -message "Unable to retrieve the ACL on $Path - $($_.Exception.Message)"
83 }
84
85 #configure acl object to remove the specified user
86 If ($state -eq 'absent')
87 {
88 #Try and find an identity on the object that matches user
89 #We skip inherited items since we can't remove those
90 $ToRemove = ($ACL.Audit | Where-Object {$_.IdentityReference.Translate([System.Security.Principal.SecurityIdentifier]) -eq $SID -and
91 $_.IsInherited -eq $false}).IdentityReference
92
93 #Exit with changed false if no identity is found
94 If (-Not $ToRemove)
95 {
96 $result.current_audit_rules = Get-CurrentAuditRules $path
97 Exit-Json -obj $result
98 }
99
100 #update the ACL object if identity found
101 Try
102 {
103 $ToRemove | ForEach-Object { $ACL.PurgeAuditRules($_) }
104 }
105 Catch
106 {
107 $result.current_audit_rules = Get-CurrentAuditRules $path
108 Fail-Json -obj $result -message "Failed to remove audit rule: $($_.Exception.Message)"
109 }
110 }
111
112 Else
113 {
114 If ($registry)
115 {
116 $PossibleRights = [System.Enum]::GetNames([System.Security.AccessControl.RegistryRights])
117
118 Foreach ($right in $rights)
119 {
120 if ($right -notin $PossibleRights)
121 {
122 Fail-Json -obj $result -message "$right does not seem to be a valid REGISTRY right"
123 }
124 }
125
126 $NewAccessRule = New-Object System.Security.AccessControl.RegistryAuditRule($user,$rights,$inheritance_flags,$propagation_flags,$audit_flags)
127 }
128 Else
129 {
130 $PossibleRights = [System.Enum]::GetNames([System.Security.AccessControl.FileSystemRights])
131
132 Foreach ($right in $rights)
133 {
134 if ($right -notin $PossibleRights)
135 {
136 Fail-Json -obj $result -message "$right does not seem to be a valid FILE SYSTEM right"
137 }
138 }
139
140 If ($file -and $inheritance_flags -ne 'none')
141 {
142 Fail-Json -obj $result -message "The target type is a file. inheritance_flags must be changed to 'none'"
143 }
144
145 $NewAccessRule = New-Object System.Security.AccessControl.FileSystemAuditRule($user,$rights,$inheritance_flags,$propagation_flags,$audit_flags)
146 }
147
148 #exit here if any existing rule matches defined rule since no change is needed
149 #if we need to ignore inherited rules in the future, this would be where to do it
150 #Just filter out inherited rules from $ACL.Audit
151 Foreach ($group in $ACL.Audit | Where-Object {$_.IsInherited -eq $false})
152 {
153 If (
154 ($group | Select-Object -expand "*Rights") -eq ($NewAccessRule | Select-Object -expand "*Rights") -and
155 $group.AuditFlags -eq $NewAccessRule.AuditFlags -and
156 $group.IdentityReference.Translate([System.Security.Principal.SecurityIdentifier]) -eq $SID -and
157 $group.InheritanceFlags -eq $NewAccessRule.InheritanceFlags -and
158 $group.PropagationFlags -eq $NewAccessRule.PropagationFlags
159 )
160 {
161 $result.current_audit_rules = Get-CurrentAuditRules $path
162 Exit-Json -obj $result
163 }
164 }
165
166 #try and set the acl object. AddAuditRule allows for multiple entries to exist under the same
167 #identity...so if someone wanted success: write and failure: delete for example, that setup would be
168 #possible. The alternative is SetAuditRule which would instead modify an existing rule and not allow
169 #for setting the above example.
170 Try
171 {
172 $ACL.AddAuditRule($NewAccessRule)
173 }
174 Catch
175 {
176 Fail-Json -obj $result -message "Failed to set the audit rule: $($_.Exception.Message)"
177 }
178 }
179
180
181 #finally set the permissions
182 Try {
183 Set-Acl -Path $path -ACLObject $ACL -WhatIf:$check_mode
184 }
185 Catch {
186 $result.current_audit_rules = Get-CurrentAuditRules $path
187 Fail-Json -obj $result -message "Failed to apply audit change: $($_.Exception.Message)"
188 }
189
190 #exit here after a change is applied
191 $result.current_audit_rules = Get-CurrentAuditRules $path
192 $result.changed = $true
193 Exit-Json -obj $result
194