2015-01-15 04:25:22 +00:00
#!powershell
2018-07-17 21:29:05 +00:00
# Copyright: (c) 2015, Phil Schwartz <schwartzmx@gmail.com>
# Copyright: (c) 2015, Trond Hindenes
# Copyright: (c) 2015, Hans-Joachim Kliemeck <git@kliemeck.de>
2017-09-10 21:34:51 +00:00
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
2017-10-23 18:40:54 +00:00
# Requires -Module Ansible.ModuleUtils.Legacy
# Requires -Module Ansible.ModuleUtils.SID
2017-09-10 21:34:51 +00:00
2018-07-18 19:37:07 +00:00
$ErrorActionPreference = " Stop "
2015-01-15 04:25:22 +00:00
# win_acl module (File/Resources Permission Additions/Removal)
2016-11-07 21:07:53 +00:00
2017-09-10 21:34:51 +00:00
#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 ]
2015-07-14 23:35:28 +00:00
}
}
2016-11-07 21:07:53 +00:00
2017-09-10 21:34:51 +00:00
if ( $searchAppPools ) {
Import-Module -Name WebAdministration
$testIISPath = Test-Path -Path " IIS: "
if ( $testIISPath ) {
$appPoolObj = Get-ItemProperty -Path " IIS:\AppPools\ $AccountName "
$userSID = $appPoolObj . applicationPoolSid
2015-07-14 23:35:28 +00:00
}
}
2017-09-10 21:34:51 +00:00
else {
$userSID = Convert-ToSID -account_name $AccountName
2016-11-07 21:07:53 +00:00
}
2016-12-08 14:38:05 +00:00
2017-09-10 21:34:51 +00:00
return $userSID
2015-07-14 23:35:28 +00:00
}
2017-03-06 20:56:17 +00:00
# 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.
$AdjustTokenPrivileges = @"
using System ;
using System . Runtime . InteropServices ;
namespace Ansible {
public class TokenManipulator {
[ DllImport ( " advapi32.dll " , ExactSpelling = true , SetLastError = true ) ]
internal static extern bool AdjustTokenPrivileges ( IntPtr htok , bool disall ,
ref TokPriv1Luid newst , int len , IntPtr prev , IntPtr relen ) ;
[ DllImport ( " kernel32.dll " , ExactSpelling = true ) ]
internal static extern IntPtr GetCurrentProcess ( ) ;
[ DllImport ( " advapi32.dll " , ExactSpelling = true , SetLastError = true ) ]
internal static extern bool OpenProcessToken ( IntPtr h , int acc ,
ref IntPtr phtok ) ;
[ DllImport ( " advapi32.dll " , SetLastError = true ) ]
internal static extern bool LookupPrivilegeValue ( string host , string name ,
ref long pluid ) ;
[ StructLayout ( LayoutKind . Sequential , Pack = 1 ) ]
internal struct TokPriv1Luid
{
public int Count ;
public long Luid ;
public int Attr ;
}
internal const int SE_PRIVILEGE_DISABLED = 0x00000000 ;
internal const int SE_PRIVILEGE_ENABLED = 0x00000002 ;
internal const int TOKEN_QUERY = 0x00000008 ;
internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020 ;
public static bool AddPrivilege ( string privilege ) {
try {
bool retVal ;
TokPriv1Luid tp ;
IntPtr hproc = GetCurrentProcess ( ) ;
IntPtr htok = IntPtr . Zero ;
retVal = OpenProcessToken ( hproc , TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY , ref htok ) ;
tp . Count = 1 ;
tp . Luid = 0 ;
tp . Attr = SE_PRIVILEGE_ENABLED ;
retVal = LookupPrivilegeValue ( null , privilege , ref tp . Luid ) ;
retVal = AdjustTokenPrivileges ( htok , false , ref tp , 0 , IntPtr . Zero , IntPtr . Zero ) ;
return retVal ;
}
catch ( Exception ex ) {
throw ex ;
}
}
public static bool RemovePrivilege ( string privilege ) {
try {
bool retVal ;
TokPriv1Luid tp ;
IntPtr hproc = GetCurrentProcess ( ) ;
IntPtr htok = IntPtr . Zero ;
retVal = OpenProcessToken ( hproc , TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY , ref htok ) ;
tp . Count = 1 ;
tp . Luid = 0 ;
tp . Attr = SE_PRIVILEGE_DISABLED ;
retVal = LookupPrivilegeValue ( null , privilege , ref tp . Luid ) ;
retVal = AdjustTokenPrivileges ( htok , false , ref tp , 0 , IntPtr . Zero , IntPtr . Zero ) ;
return retVal ;
}
catch ( Exception ex ) {
throw ex ;
}
}
}
}
" @
2018-07-18 19:37:07 +00:00
$params = Parse-Args $args
2018-05-22 21:12:32 +00:00
$_remote_tmp = Get-AnsibleParam $params " _ansible_remote_tmp " -type " path " -default $env:TMP
$original_tmp = $env:TMP
$original_temp = $env:TEMP
$env:TMP = $_remote_tmp
$env:TEMP = $_remote_tmp
2017-03-06 20:56:17 +00:00
add-type $AdjustTokenPrivileges
2018-05-22 21:12:32 +00:00
$env:TMP = $original_tmp
$env:TEMP = $original_temp
2017-03-06 20:56:17 +00:00
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 ) ) {
# See the following for details of each privilege
# https://msdn.microsoft.com/en-us/library/windows/desktop/bb530716(v=vs.85).aspx
[ void][Ansible.TokenManipulator ] :: AddPrivilege ( " SeRestorePrivilege " ) #Grants all write access control to any file, regardless of ACL.
[ void][Ansible.TokenManipulator ] :: AddPrivilege ( " SeBackupPrivilege " ) #Grants all read access control to any file, regardless of ACL.
[ void][Ansible.TokenManipulator ] :: AddPrivilege ( " SeTakeOwnershipPrivilege " ) #Grants ability to take owernship of an object w/out being granted discretionary access
}
}
2017-04-13 18:34:33 +00:00
$result = @ {
changed = $false
}
2015-10-17 22:00:47 +00:00
2018-07-18 19:37:07 +00:00
$path = Get-AnsibleParam -obj $params -name " path " -type " str " -failifempty $true
$user = Get-AnsibleParam -obj $params -name " user " -type " str " -failifempty $true
$rights = Get-AnsibleParam -obj $params -name " rights " -type " str " -failifempty $true
2015-10-17 22:00:47 +00:00
2018-07-18 19:37:07 +00:00
$type = Get-AnsibleParam -obj $params -name " type " -type " str " -failifempty $true -validateset " allow " , " deny "
$state = Get-AnsibleParam -obj $params -name " state " -type " str " -default " present " -validateset " absent " , " present "
2015-10-17 22:00:47 +00:00
2018-07-18 19:37:07 +00:00
$inherit = Get-AnsibleParam -obj $params -name " inherit " -type " str "
$propagation = Get-AnsibleParam -obj $params -name " propagation " -type " str " -default " None " -validateset " InheritOnly " , " None " , " NoPropagateInherit "
2015-10-17 22:00:47 +00:00
If ( -Not ( Test-Path -Path $path ) ) {
2018-07-18 19:37:07 +00:00
Fail-Json -obj $result -message " $path file or directory does not exist on the host "
2015-01-15 04:25:22 +00:00
}
2015-10-17 22:00:47 +00:00
# Test that the user/group is resolvable on the local machine
2017-09-10 21:34:51 +00:00
$sid = Get-UserSID -AccountName $user
if ( ! $sid ) {
2018-07-18 19:37:07 +00:00
Fail-Json -obj $result -message " $user is not a valid user or group on the host machine or domain "
2015-01-15 04:25:22 +00:00
}
2015-10-17 22:00:47 +00:00
If ( Test-Path -Path $path -PathType Leaf ) {
$inherit = " None "
2015-01-15 04:25:22 +00:00
}
2015-10-17 22:00:47 +00:00
ElseIf ( $inherit -eq " " ) {
$inherit = " ContainerInherit, ObjectInherit "
2015-01-15 04:25:22 +00:00
}
2017-03-06 20:56:17 +00:00
2015-01-15 04:25:22 +00:00
Try {
2017-03-06 20:56:17 +00:00
SetPrivilegeTokens
2017-03-02 06:38:27 +00:00
If ( $path -match " ^HK(CC|CR|CU|LM|U):\\ " ) {
2017-03-06 20:56:17 +00:00
$colRights = [ System.Security.AccessControl.RegistryRights ] $rights
2017-03-02 06:38:27 +00:00
}
Else {
2017-03-06 20:56:17 +00:00
$colRights = [ System.Security.AccessControl.FileSystemRights ] $rights
2017-03-02 06:38:27 +00:00
}
2017-03-06 20:56:17 +00:00
2015-01-15 04:25:22 +00:00
$InheritanceFlag = [ System.Security.AccessControl.InheritanceFlags ] $inherit
$PropagationFlag = [ System.Security.AccessControl.PropagationFlags ] $propagation
2017-09-10 21:34:51 +00:00
2015-10-17 22:00:47 +00:00
If ( $type -eq " allow " ) {
2015-01-15 04:25:22 +00:00
$objType = [ System.Security.AccessControl.AccessControlType ] :: Allow
}
Else {
$objType = [ System.Security.AccessControl.AccessControlType ] :: Deny
}
2017-09-10 21:34:51 +00:00
2015-10-15 10:01:11 +00:00
$objUser = New-Object System . Security . Principal . SecurityIdentifier ( $sid )
2017-03-02 06:38:27 +00:00
If ( $path -match " ^HK(CC|CR|CU|LM|U):\\ " ) {
2017-03-06 20:56:17 +00:00
$objACE = New-Object System . Security . AccessControl . RegistryAccessRule ( $objUser , $colRights , $InheritanceFlag , $PropagationFlag , $objType )
2017-03-02 06:38:27 +00:00
}
Else {
2017-03-06 20:56:17 +00:00
$objACE = New-Object System . Security . AccessControl . FileSystemAccessRule ( $objUser , $colRights , $InheritanceFlag , $PropagationFlag , $objType )
2017-03-02 06:38:27 +00:00
}
2015-07-15 16:42:27 +00:00
$objACL = Get-ACL $path
2017-09-10 21:34:51 +00:00
2015-06-18 22:25:05 +00:00
# Check if the ACE exists already in the objects ACL list
$match = $false
2017-07-11 00:01:55 +00:00
# Workaround to handle special use case 'APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES' and
# 'APPLICATION PACKAGE AUTHORITY\ALL RESTRICTED APPLICATION PACKAGES'- can't translate fully qualified name (win32 API bug/oddity)
# 'ALL APPLICATION PACKAGES' exists only on Win2k12 and Win2k16 and 'ALL RESTRICTED APPLICATION PACKAGES' exists only in Win2k16
$specialIdRefs = " ALL APPLICATION PACKAGES " , " ALL RESTRICTED APPLICATION PACKAGES "
ForEach ( $rule in $objACL . Access ) {
$idRefShortValue = ( $rule . IdentityReference . Value ) . split ( '\' ) [ -1 ]
if ( $idRefShortValue -in $specialIdRefs ) {
$ruleIdentity = ( New-Object Security . Principal . NTAccount $idRefShortValue ) . Translate ( [ Security.Principal.SecurityIdentifier ] )
}
else {
2017-03-06 20:56:17 +00:00
$ruleIdentity = $rule . IdentityReference . Translate ( [ System.Security.Principal.SecurityIdentifier ] )
2017-07-11 00:01:55 +00:00
}
If ( $path -match " ^HK(CC|CR|CU|LM|U):\\ " ) {
2017-03-06 20:56:17 +00:00
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
}
2017-07-11 00:01:55 +00:00
} else {
2017-09-10 21:34:51 +00:00
If ( ( $rule . FileSystemRights -eq $objACE . FileSystemRights ) -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 ) ) {
2017-03-06 20:56:17 +00:00
$match = $true
Break
}
}
2017-03-02 06:38:27 +00:00
}
2015-10-17 22:00:47 +00:00
If ( $state -eq " present " -And $match -eq $false ) {
2015-01-15 04:25:22 +00:00
Try {
$objACL . AddAccessRule ( $objACE )
2015-07-15 16:42:27 +00:00
Set-ACL $path $objACL
2017-04-13 18:34:33 +00:00
$result . changed = $true
2015-01-15 04:25:22 +00:00
}
Catch {
2018-07-18 19:37:07 +00:00
Fail-Json -obj $result -message " an exception occurred when adding the specified rule - $( $_ . Exception . Message ) "
2015-01-15 04:25:22 +00:00
}
}
2015-10-17 22:00:47 +00:00
ElseIf ( $state -eq " absent " -And $match -eq $true ) {
2015-01-15 04:25:22 +00:00
Try {
$objACL . RemoveAccessRule ( $objACE )
2015-07-15 16:42:27 +00:00
Set-ACL $path $objACL
2017-04-13 18:34:33 +00:00
$result . changed = $true
2015-01-15 04:25:22 +00:00
}
Catch {
2018-07-18 19:37:07 +00:00
Fail-Json -obj $result -message " an exception occurred when removing the specified rule - $( $_ . Exception . Message ) "
2015-01-15 04:25:22 +00:00
}
}
2015-06-18 22:25:05 +00:00
Else {
# A rule was attempting to be added but already exists
If ( $match -eq $true ) {
2018-07-18 19:37:07 +00:00
Exit-Json -obj $result -message " the specified rule already exists "
2015-06-18 22:25:05 +00:00
}
# A rule didn't exist that was trying to be removed
Else {
2018-07-18 19:37:07 +00:00
Exit-Json -obj $result -message " the specified rule does not exist "
2017-09-10 21:34:51 +00:00
}
2015-06-18 22:25:05 +00:00
}
2015-01-15 04:25:22 +00:00
}
Catch {
2018-07-18 19:37:07 +00:00
Fail-Json -obj $result -message " an error occurred when attempting to $state $rights permission(s) on $path for $user - $( $_ . Exception . Message ) "
2015-01-15 04:25:22 +00:00
}
2017-09-10 21:34:51 +00:00
2018-07-18 19:37:07 +00:00
Exit-Json -obj $result