Sign in to follow this  
Followers 0

Set Acl permissions UDF

108 posts in this topic




Posted

Thank You, very useful

Thanks Again

Ciao.

Share this post


Link to post
Share on other sites

Posted

Definitely looks good :D , thanks a lot!

Share this post


Link to post
Share on other sites

Posted

You're welcome guys! It was my contribution to the community, after taking so much :D

Works much faster than SetAcl, and you can set the owner, clear the DACL and define all the desired permissions with one function call.

Share this post


Link to post
Share on other sites

Posted

I really like the look of this UDF, I was looking for something exactly like this earlier today for an automation script I was creating. This will finish it off exactly as I need to.

Thank you for this.

Share this post


Link to post
Share on other sites

Posted

You're welcome, BrewManNH.

If any of you find any bugs, please tell.

Share this post


Link to post
Share on other sites

Posted

Not yet tested, but it looks good. :D

Thanks a lot

Share this post


Link to post
Share on other sites

Posted

I fixed a bug and updated the file. Check the first post.

it is possible to add these function ...

Well, here they are:

 
#include 'Permissions.au3'
_InitiatePermissionResources()
FileWrite(@ScriptDir&'\test.txt','test')
Local $TI = TimerInit()
;************************************************************************************************
Local $ret = _GetObjectStringSecurityDescriptor(@ScriptDir&'\test.txt'); Put here the function to test
Local $ret2 = _ConvertStringSecurityDescriptorToSecurityDescriptor($ret)
;************************************************************************************************
Local $TD = TimerDiff($TI)
MsgBox(0,'','String security descriptor: '&$ret&@CRLF&'Stecurty descriptor pointer: '&$ret2&@CRLF&'   Time: '&Round($TD,2)&' miliseconds.')
FileDelete(@ScriptDir&'\test.txt')
 _ClosePermissionResources()
 
 Func  _GetObjectStringSecurityDescriptor($oName, $_SE_OBJECT_TYPE = $SE_FILE_OBJECT)
Local $SECURITY_INFORMATION = BitOR($DACL_SECURITY_INFORMATION,$OWNER_SECURITY_INFORMATION)
Local $pSecDescriptor = _GetObjectSecurityDescriptor($oName, $_SE_OBJECT_TYPE)
Local $strSecDescriptor = _ConvertSecurityDescriptorToStringSecurityDescriptor($pSecDescriptor)
DllCall($h__Kernel32Dll,'handle','LocalFree','handle',$pSecDescriptor)
Return $strSecDescriptor
EndFunc ;==>_GetObjectStringSecurityDescriptor
 
Func  _ConvertSecurityDescriptorToStringSecurityDescriptor(ByRef $pSecDescriptor)
Local $SECURITY_INFORMATION = BitOR($DACL_SECURITY_INFORMATION,$OWNER_SECURITY_INFORMATION)
Local $aRet = DllCall($h__Advapi32Dll,'bool','ConvertSecurityDescriptorToStringSecurityDescriptor', _
'ptr',$pSecDescriptor,'DWORD',1,'DWORD',$SECURITY_INFORMATION,'str*',0,'ptr',0)
If @error Then Return SetError(1,0,'')
Return $aRet[4]
EndFunc ;==>_ConvertSecurityDescriptorToStringSecurityDescriptor
 
Func  _ConvertStringSecurityDescriptorToSecurityDescriptor(ByRef $strSecDescriptor)
Local $aRet = DllCall($h__Advapi32Dll,'bool','ConvertStringSecurityDescriptorToSecurityDescriptor', _
'str',$strSecDescriptor,'DWORD',1,'ptr*',0,'ptr',0)
If @error Then Return SetError(1,0,0)
Return $aRet[3]
EndFunc ;==>_ConvertStringSecurityDescriptorToSecurityDescriptor
 
Func _GetObjectSecurityDescriptor($oName, $_SE_OBJECT_TYPE = $SE_FILE_OBJECT)
Local $SECURITY_INFORMATION = BitOR($DACL_SECURITY_INFORMATION,$OWNER_SECURITY_INFORMATION)
If $ResourcesState = 0 Then _InitiatePermissionResources()
If $_SE_OBJECT_TYPE = $SE_REGISTRY_KEY Then $oName = _Security_RegKeyName($oName)
Local $aRet = DllCall($h__Advapi32Dll,'DWORD','GetNamedSecurityInfo','str',$oName,'int',$_SE_OBJECT_TYPE,'DWORD',$SECURITY_INFORMATION,'ptr',0,'ptr',0,'ptr',0,'ptr',0,'ptr*',0)
If @error Then Return SetError(@error,0,0)
Return SetError($aRet[0],0,$aRet[8])
EndFunc ;==>_GetObjectSecurityDescriptor
 

I don't know why you need these functions, but if you're planning on using them to set the DACL permissions, let me tell you you don't need them.

You can easily edit the DACL by calling the _SetObjectPermissions function.

Imagine you want to give yourself all granted access to a file, but give everyone else only read and execute access. This can be very useful if you have kids, and you want them to be able to read and execute your files, but you don't want them to edit or delete them.

Take a look at this code:

#include 'Permissions.au3'
_InitiatePermissionResources()
Local $File = @ScriptDir&'\test.txt'
FileWrite($File,'test')
Local $TI = TimerInit()
 
Local $aPerm[2][3]
$aPerm[0][0] = @UserName
$aPerm[0][1] = 1
$aPerm[0][2] = $GENERIC_ALL
$aPerm[1][0] = 'Everyone'
$aPerm[1][1] = 1
$aPerm[1][2] = $GENERIC_READ+$GENERIC_EXECUTE
Local $ret = _SetObjectPermissions($File,$aPerm,$SE_FILE_OBJECT,@UserName,1,1)
Local $TD = TimerDiff($TI)
MsgBox(0,'','Function return value: '&$ret&@CRLF&'   Time: '&Round($TD,2)&' miliseconds.')
_ClosePermissionResources()
 

You just have to create an array with the permissions you want to set:

$array[0][0] - First ace user name or Sid string

$array[0][1] - 1 or 0,whether to grant or deny the permissions defined in the access mask. ($array[0][2])

$array[0][2] - One or more access mask values. e.g. $GENERIC_READ+$GENERIC_EXECUTE

$array[1][0] - Second ace user name or Sid string

$array[1][1] - 1 or 0,whether to grant or deny the permissions defined in the access mask. ($array[1][2])

$array[1][2] - One or more access mask values. e.g. $GENERIC_READ+$GENERIC_EXECUTE

And so on. You can add how many aces you want. The access denied aces have priority over the allowed ones.

Then you can set the owner, clear the DACL and recurse containers and objects (for folders and registry keys), When recursing, the child objects will automatically inherit the permissions from the parent one.

Don't know what else you can do by modifying the security descriptor.

Share this post


Link to post
Share on other sites

Posted (edited)

Thank you very much, i needed those functions because I want to have a backup of the security of the registry\file\service (save all the inf file), to give users the possibility to restore the original settings, using Secedit.exe (the way that Microsoft sets everything in windows ect ect)

Sorry again for my English

Ciao

Edited by DXRW4E

Share this post


Link to post
Share on other sites

Posted (edited)

I wanted to ask, even for one thing, using the _ConvertSecurityDescriptorToStringSecurityDescriptor, or this line $a = "O:BUD:PAI(A;;FA;;;BU)(A;;0x1200a9;;;WD)"

after using the _ConvertStringSecurityDescriptorToSecurityDescriptor($a), how can I use that to set the _WriteDaclToObject, I'm doing wrong or something?, This is interesting because I shall be able to keep all the original settings, and add admin only right, for example "O:BUD:PAI(A;;FA;;;BU)(A;;0x1200a9;;;WD)(A;;FA;;;BA)" (This explains all about it http://msdn.microsoft.com/en-us/magazine/cc982153.aspx)

I know from experience that this is not the safest way, because if "TrustedInstaller" and present, even if you have full admin right, sometimes "TrustedInstaller" still does not let you do everything there (for example if you want to work with files in "C:\Windows\WinSxS" and better remove remaining TrustedInstaller), so the best way and _SetObjectPermissions, However i am interested also this other way using the _ConvertStringSecurityDescriptorToSecurityDescriptor

sorry for the trouble

Thanks again, Ciao.

Edited by DXRW4E

Share this post


Link to post
Share on other sites

Posted

after using the _ConvertStringSecurityDescriptorToSecurityDescriptor($a), how can I use that to set the _WriteDaclToObject,

You have to get the DACL from the security descriptor. I'll take a look at the function and post back in a while.

Share this post


Link to post
Share on other sites

Posted

Ok Here it is:

#include 'Permissions.au3'
_InitiatePermissionResources()
FileWrite(@ScriptDir&'\test.txt','test')
Local $TI = TimerInit()
;************************************************************************************************
Local $ret1 = _GetObjectSecurityDescriptor(@ScriptDir&'\test.txt')
Local $ret2 = _ConvertSecurityDescriptorToStringSecurityDescriptor($ret1)
Local $ret3 = _ConvertStringSecurityDescriptorToSecurityDescriptor($ret2)
Local $ret4 = _GetSecurityDescriptorOwner($ret3)
Local $ret5 = _GetSecurityDescriptorDacl($ret3)
;************************************************************************************************
Local $TD = TimerDiff($TI)
MsgBox(0,'','Security descriptor pointer: '&$ret1&@CRLF& _
'Converted to string: '&$ret2&@CRLF& _
'Re-converted to pointer to security descriptor: '&$ret3&@CRLF& _
'Owner SID: '&$ret4&@CRLF& _
'Pointer to the DACL: '&$ret5&@CRLF& _
'   Time: '&Round($TD,2)&' miliseconds.')
FileDelete(@ScriptDir&'\test.txt')
 _ClosePermissionResources()
 
Func _GetSecurityDescriptorOwner(ByRef $pSecDescriptor)
If Not IsPtr($pSecDescriptor) Then Return SetError(1,0,0)
Local $aRet = DllCall($h__Advapi32Dll,'bool','GetSecurityDescriptorOwner', _
'ptr',$pSecDescriptor,'ptr*',0,'bool*',0)
If @error Then Return SetError(@error,0,0)
Return _SidToStringSid($aRet[2])
EndFunc ;==>_GetSecurityDescriptorDacl
 
 Func _GetSecurityDescriptorDacl(ByRef $pSecDescriptor)
If Not IsPtr($pSecDescriptor) Then Return SetError(1,0,0)
Local $aRet = DllCall($h__Advapi32Dll,'bool','GetSecurityDescriptorDacl', _
'ptr',$pSecDescriptor,'bool*',0,'ptr*',0,'bool*',0)
If @error Then Return SetError(@error,0,0)
If Not $aRet[2] Then Return SetError(1,0,0)
Return $aRet[3]
EndFunc ;==>_GetSecurityDescriptorDacl
 
 Func  _GetObjectStringSecurityDescriptor($oName, $_SE_OBJECT_TYPE = $SE_FILE_OBJECT)
Local $SECURITY_INFORMATION = BitOR($DACL_SECURITY_INFORMATION,$OWNER_SECURITY_INFORMATION)
Local $pSecDescriptor = _GetObjectSecurityDescriptor($oName, $_SE_OBJECT_TYPE)
Local $strSecDescriptor = _ConvertSecurityDescriptorToStringSecurityDescriptor($pSecDescriptor)
DllCall($h__Kernel32Dll,'handle','LocalFree','handle',$pSecDescriptor)
Return $strSecDescriptor
EndFunc ;==>_GetObjectStringSecurityDescriptor
 
Func  _ConvertSecurityDescriptorToStringSecurityDescriptor(ByRef $pSecDescriptor)
If Not IsPtr($pSecDescriptor) Then Return SetError(1,0,0)
Local $SECURITY_INFORMATION = BitOR($DACL_SECURITY_INFORMATION,$OWNER_SECURITY_INFORMATION)
Local $aRet = DllCall($h__Advapi32Dll,'bool','ConvertSecurityDescriptorToStringSecurityDescriptor', _
'ptr',$pSecDescriptor,'DWORD',1,'DWORD',$SECURITY_INFORMATION,'str*',0,'ptr',0)
If @error Then Return SetError(1,0,'')
Return $aRet[4]
EndFunc ;==>_ConvertSecurityDescriptorToStringSecurityDescriptor
 
Func  _ConvertStringSecurityDescriptorToSecurityDescriptor(ByRef $strSecDescriptor)
If Not IsString($strSecDescriptor) Then Return SetError(1,0,0)
Local $aRet = DllCall($h__Advapi32Dll,'bool','ConvertStringSecurityDescriptorToSecurityDescriptor', _
'str',$strSecDescriptor,'DWORD',1,'ptr*',0,'ptr',0)
If @error Then Return SetError(1,0,0)
Return $aRet[3]
EndFunc ;==>_ConvertStringSecurityDescriptorToSecurityDescriptor
 
Func _GetObjectSecurityDescriptor($oName, $_SE_OBJECT_TYPE = $SE_FILE_OBJECT)
Local $SECURITY_INFORMATION = BitOR($DACL_SECURITY_INFORMATION,$OWNER_SECURITY_INFORMATION)
If $ResourcesState = 0 Then _InitiatePermissionResources()
If $_SE_OBJECT_TYPE = $SE_REGISTRY_KEY Then $oName = _Security_RegKeyName($oName)
Local $aRet = DllCall($h__Advapi32Dll,'DWORD','GetNamedSecurityInfo','str',$oName,'int',$_SE_OBJECT_TYPE, _
'DWORD',$SECURITY_INFORMATION,'ptr',0,'ptr',0,'ptr',0,'ptr',0,'ptr*',0)
If @error Then Return SetError(@error,0,0)
Return SetError($aRet[0],0,$aRet[8])
EndFunc ;==>_GetObjectSecurityDescriptor

Now that I know why you need the functions, I'm finding this very interesting, because it allows to make a full backup of the security descriptor, and restore it later. No need for secedit.

When I have more time, I'll document the functions and add them to the UDF.

Share this post


Link to post
Share on other sites

Posted (edited)

Thanks so much for all the support

When you add function to UDF,better if you add a direct fuction as the _GetObjectStringSecurityDescriptor (ScriptDir @ & '\ test.txt'), for example add _SetObjectStringSecurityDescriptor(ScriptDir @ & '\ test.txt,',"O:BUD:PAI(A;;FA;;;BU)(A;;0x1200a9;;;WD)(A;;FA;;;BA)"), I do not know, see for yourself how and best

Ciao.

Edited by DXRW4E

Share this post


Link to post
Share on other sites

Posted

Very complex, perfect!

Thanks for sharing...

João Carlos.

Share this post


Link to post
Share on other sites

Posted

I've always found calling icacls.exe very simple for changing permissions. Is the main difference between the UDF and icacls that icacls is restricted to modifying only files and folders?

Share this post


Link to post
Share on other sites

Posted

No, this is also much faster, and makes your script independent from external exes, which can be disabled or infected.

Also AFAIK you can't set ownership using icacls.

Share this post


Link to post
Share on other sites

Posted

I added the security descriptor functions to the UDF and updated. see the first post.

Share this post


Link to post
Share on other sites

Posted

Thank You

Share this post


Link to post
Share on other sites

Posted

I updated again. This time I didn't change the code, just some faults in the comments.

The _SetObjectPermissions function now supports setting the inheritance too, but remember you cannot create an ace with the flag $INHERIT_ONLY_ACE. This type of aces are automatically added from the parent upon the object's creation.

Better use the flags $OBJECT_INHERIT_ACE (1), $CONTAINER_INHERIT_ACE ( 2), $SUB_CONTAINERS_AND_OBJECTS_INHERIT (3) and $NO_PROPAGATE_INHERIT_ACE (4)

Share this post


Link to post
Share on other sites

Posted

this is exactly what I've been looking for, thank you for sharing!

Share this post


Link to post
Share on other sites

Posted

Great work!

Share this post


Link to post
Share on other sites

Posted

I love the UDF, but I'm having a tough time using it to add permissions. I have a Win2k8 machine that I'm trying to add the users to the Windows directory. Its owner is "Trusted Installer". Every time I execute the code below, it wipes out the current permissions and adds only the ones I specify in the array. This works great on other folders, but I can't seem to simply add two users to the permissions without clearing the rest.

What am I doing wrong?

#include <permissions.au3>
Dim $aPerm[2][3]
$aPerm[0][0] = "Authenticated Users"
$aPerm[0][1] = 1
$aPerm[0][2] = $GENERIC_ALL
$aPerm[1][0] = "Network Service"
$aPerm[1][1] = 1
$aPerm[1][2] = $GENERIC_ALL
$file = @WindowsDir
$setPerms = _SetObjectPermissions($file, $aPerm, $SE_FILE_OBJECT, "", 0, 1)

Share this post


Link to post
Share on other sites

Posted

FredAI,

Thank you for creating this solution, I really appreciate it!

Would it be possible for you to post two additional examples?

Specifically, I'm having difficulty assigning file object permissions for specific domain users/groups. I use the function included herein to obtain the domain name. If the @LogonDomain and $Domain variables do not match I'd like to add the 'DOMAINDomain Users' group, for example, to the DACL permissions array. I'm assuming the answer involves looking up the SID?

The second example I'm looking for would be code showing how to modify thread permissions, specifically Terminate, Suspend/Resume, and Change Owner. I'm guess looking up the Pid is involved?

$Domain = _DomainComputerBelongs()
MsgBox(0 , @LogonDomain , 'Domain: ' & $ComputerDomain)

Func _DomainComputerBelongs($strComputer = "localhost")
$Domain = ''
$wbemFlagReturnImmediately = 0x10
$wbemFlagForwardOnly = 0x20
$objWMIService = ObjGet("winmgmts:" & $strComputer & "rootCIMV2")
If Not IsObj($objWMIService) Then Return SetError(1, 0, '')
  $colItems = $objWMIService.ExecQuery("SELECT * FROM Win32_ComputerSystem", "WQL", $wbemFlagReturnImmediately + $wbemFlagForwardOnly)
If IsObj($colItems) then
  For $objItem In $colItems
   $Domain = $objItem.Domain
  Next
Endif
Return $Domain
EndFunc

Hi.

I've been working on this for a while. I think now it's good enough to post it here.

Functions to do most everything with the DACL and ownership on all types of objects: Files or folders, Registry keys, services, Kernel and WMI objects, etc.

Thanks!!

Share this post


Link to post
Share on other sites

Posted

You'll have to use the SID string instead of the group's name. The only groups you may use the names are "Administrators", "System" and "Everyone". However, for users (not groups) you may use the name string.

Take a look here: http://support.microsoft.com/kb/243330

It will give you the SID strings for the groups you need.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0