WinApi : Set File Permission (32bits/64bits)

Windows specific forum
tatanas
Enthusiast
Enthusiast
Posts: 260
Joined: Wed Nov 06, 2019 10:28 am
Location: France

WinApi : Set File Permission (32bits/64bits)

Post by tatanas »

Hi,

I'm trying to set permission on a file with WinApi. It works fine in 32 bits but not in 64 bits.
It seems the problem come from the EXPLICIT_ACCESS structure size (https://stackoverflow.com/questions/589 ... riesinacla).

Here is the code :

Code: Select all

; #include <Accctrl.h>
; #include <Aclapi.h>

#GRANT_ACCESS = 1
#NO_INHERITANCE = 0
#TRUSTEE_IS_SID = 0
#TRUSTEE_IS_WELL_KNOWN_GROUP = 5
#SECURITY_WORLD_SID_AUTHORITY = 1
#DACL_SECURITY_INFORMATION = 4

Structure NTAUTHORITY
	NtAuthority.b[6]
EndStructure

Structure TRUSTEE
	*pMultipleTrustee
	MultipleTrusteeOperation.l
	TrusteeForm.l
	TrusteeType.l
	*ptstrName
EndStructure

Structure EXPLICIT_ACCESS
	grfAccessPermissions.l
	grfAccessMode.l
	grfInheritance.l
	Trustee.TRUSTEE
EndStructure


Procedure SetFilePermission(FileName.s)
	Protected Security_Nt_Authority.NTAUTHORITY
	Security_Nt_Authority\NtAuthority[5] = #SECURITY_WORLD_SID_AUTHORITY
		
	; Create a well-known SID For the Everyone group.
	Protected *pEveryoneSID = #Null
	If Not AllocateAndInitializeSid_(@Security_Nt_Authority, 1, #SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, @*pEveryoneSID)
		Debug "erreur AllocateAndInitializeSid_ : " + GetLastError_()
	EndIf
	
	; Initialize an EXPLICIT_ACCESS Structure For an ACE.
	Protected Dim ea.EXPLICIT_ACCESS(0)
	ea(0)\grfAccessPermissions = $FFFFFFFF ; all access
	ea(0)\grfAccessMode = #GRANT_ACCESS
	ea(0)\grfInheritance= #NO_INHERITANCE
	ea(0)\Trustee\TrusteeForm = #TRUSTEE_IS_SID
	ea(0)\Trustee\TrusteeType = #TRUSTEE_IS_WELL_KNOWN_GROUP
	ea(0)\Trustee\MultipleTrusteeOperation = 0
	ea(0)\Trustee\ptstrName = *pEveryoneSID


   ; Create a new ACL that contains the new ACEs.
	Protected *pACL = #Null
   ret = SetEntriesInAcl_(1, @ea(), #Null, @*pACL)
	If ret <> #ERROR_SUCCESS
		Debug "erreur SetEntriesInAcl_ : " + ret ; 87 invalid parameter
		ProcedureReturn 0
	EndIf

   ; Initialize a security descriptor.  
	Protected *pSD.SECURITY_DESCRIPTOR = AllocateMemory(#SECURITY_DESCRIPTOR_MIN_LENGTH)
	If Not InitializeSecurityDescriptor_(*pSD, #SECURITY_DESCRIPTOR_REVISION)
		Debug "erreur InitializeSecurityDescriptor_ : " + GetLastError_()
		ProcedureReturn 0
	EndIf

   ; Add the ACL To the security descriptor. 
   If Not SetSecurityDescriptorDacl_(*pSD, 
            #True, ;    // bDaclPresent flag   
            *pACL, 
            #False) ;   // Not a Default DACL 
		Debug "erreur SetSecurityDescriptorDacl_ : " + GetLastError_()
		ProcedureReturn 0
	EndIf

   ; Change the security attributes
   If Not SetFileSecurity_(FileName, #DACL_SECURITY_INFORMATION, *pSD)
		Debug "erreur SetFileSecurity_ : " + GetLastError_()
		ProcedureReturn 0
	EndIf

   If *pEveryoneSID : FreeSid_(*pEveryoneSID) : EndIf
   If *pACL : LocalFree_(*pACL) : EndIf
   If *pSD : FreeMemory(*pSD) : EndIf
EndProcedure


If CreateFile(0, "c:\test.txt")
	CloseFile(0)

	SetFilePermission("c:\test.txt")
EndIf
Thanks for your time
Windows 10 Pro x64
PureBasic 6.20 x64
Axolotl
Addict
Addict
Posts: 832
Joined: Wed Dec 31, 2008 3:36 pm

Re: WinApi : Set File Permission (32bits/64bits)

Post by Axolotl »

If your assumption is correct, then it is probably due to the size of the typedef enums. (i.e. ACCESS_MODE and TRUSTEE)
I would probably check the sizes of the enum based data with a c-compiler if i had one......
Unfortunately I can't help at this point.
Just because it worked doesn't mean it works.
PureBasic 6.04 (x86) and <latest stable version and current alpha/beta> (x64) on Windows 11 Home. Now started with Linux (VM: Ubuntu 22.04).
User avatar
luis
Addict
Addict
Posts: 3895
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: WinApi : Set File Permission (32bits/64bits)

Post by luis »

Hi

Code: Select all

Structure TRUSTEE Align #PB_Structure_AlignC
	*pMultipleTrustee
	MultipleTrusteeOperation.l
	TrusteeForm.l
	TrusteeType.l
	*ptstrName
EndStructure

Structure EXPLICIT_ACCESS Align #PB_Structure_AlignC
	grfAccessPermissions.l
	grfAccessMode.l
	grfInheritance.l
	Trustee.TRUSTEE
EndStructure
"Have you tried turning it off and on again ?"
tatanas
Enthusiast
Enthusiast
Posts: 260
Joined: Wed Nov 06, 2019 10:28 am
Location: France

Re: WinApi : Set File Permission (32bits/64bits)

Post by tatanas »

I tried your solution Luis. There is no error 87 from SetEntriesInAcl() like before, unfortunately the permission isn't apply.
The problem could come from grfAccessPermissions from EXPLICIT_ACCESS which can't accept $FFFFFFFF (all rights) if we keep it as LONG. But if we change it to INTEGER, the error comes back...
Windows 10 Pro x64
PureBasic 6.20 x64
tatanas
Enthusiast
Enthusiast
Posts: 260
Joined: Wed Nov 06, 2019 10:28 am
Location: France

Re: WinApi : Set File Permission (32bits/64bits)

Post by tatanas »

I found a workaround. It's working fine in 64 bits :

Code: Select all

; https://binaryworld.net/Main/CodeDetail.aspx?CodeId=3659

#SE_FILE_OBJECT = 1

#GRANT_ACCESS = 1
#NO_INHERITANCE = 0
#TRUSTEE_IS_SID = 0
#TRUSTEE_IS_WELL_KNOWN_GROUP = 5
#SECURITY_WORLD_SID_AUTHORITY = 1
#DACL_SECURITY_INFORMATION = 4

#READ_CONTROL = $20000
#GENERIC_READ = $80000000
#GENERIC_WRITE = $40000000
#STANDARD_RIGHTS_ALL = $1F0000
#ALL_ACCESS = $FFFFFFFF


Structure TRUSTEE Align #PB_Structure_AlignC
	*pMultipleTrustee
	MultipleTrusteeOperation.l
	TrusteeForm.l
	TrusteeType.l
	*ptstrName
EndStructure

Structure EXPLICIT_ACCESS Align #PB_Structure_AlignC
	grfAccessPermissions.i
	grfAccessMode.l
	grfInheritance.l
	Trustee.TRUSTEE
EndStructure


Procedure SetFilePermission(FileName.s, TrusteeName.s, Permissions.i)

	Protected ea.EXPLICIT_ACCESS
	Protected pOldDACL.i
	Protected *pSecDesc = #Null
	Protected *pNewDACL = #Null
	Protected result.i
	
	result = GetNamedSecurityInfo_(FileName, #SE_FILE_OBJECT, #DACL_SECURITY_INFORMATION, #Null, #Null, @pOldDACL, #Null, @*pSecDesc)
	If result <> #ERROR_SUCCESS
		Debug "GetNamedSecurityInfo_ Error : " + result
		ProcedureReturn 0
	EndIf
	
   BuildExplicitAccessWithName_(@ea, TrusteeName, Permissions, #GRANT_ACCESS, #CONTAINER_INHERIT_ACE | #OBJECT_INHERIT_ACE)

	result = SetEntriesInAcl_(1, @ea, pOldDACL, @*pNewDACL)
	If result <> #ERROR_SUCCESS
		Debug "SetEntriesInAcl_ Error : " + result
		ProcedureReturn 0
	EndIf

   result = SetNamedSecurityInfo_(FileName, #SE_FILE_OBJECT, #DACL_SECURITY_INFORMATION, #Null, #Null, *pNewDACL, #Null)
   If result <> #ERROR_SUCCESS
		Debug "SetNamedSecurityInfo_ Error : " + result
		ProcedureReturn 0
	EndIf

	LocalFree_(*pNewDACL)
	LocalFree_(*pSecDesc)

	ProcedureReturn 1

EndProcedure


If CreateFile(0, "c:\test.txt")
	CloseFile(0)

	SetFilePermission("c:\test.txt", "Tout le monde", #GENERIC_WRITE | #GENERIC_READ)
EndIf
Windows 10 Pro x64
PureBasic 6.20 x64
User avatar
luis
Addict
Addict
Posts: 3895
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: WinApi : Set File Permission (32bits/64bits)

Post by luis »

tatanas wrote: Tue Jun 20, 2023 7:01 am I tried your solution Luis. There is no error 87 from SetEntriesInAcl() like before, unfortunately the permission isn't apply.
Are you sure ? I've just tried compiled to 64 bits and it creates the file with "everyone" as group and all permissions enabled.
Tried 32 bits and seems to do the same, so I thought it was OK.
Isn't that what it is supposed to do ?
I'm also using Win 10 x64. The only thing I've changed beyond the structure is putting the file under temp, else can't be created in my C: root.
tatanas wrote: Tue Jun 20, 2023 7:01 amThe problem could come from grfAccessPermissions from EXPLICIT_ACCESS which can't accept $FFFFFFFF (all rights) if we keep it as LONG.
Sure it can. It's 32 bit. PB interpret it as a signed long but it's not important to the API reading from it.
You can set all bits to 1 in it nevertheless. Just try it and print it using Hex().

Your last code instead doesn't work for me and I get this error:

SetEntriesInAcl_ Error : 1332
"Have you tried turning it off and on again ?"
tatanas
Enthusiast
Enthusiast
Posts: 260
Joined: Wed Nov 06, 2019 10:28 am
Location: France

Re: WinApi : Set File Permission (32bits/64bits)

Post by tatanas »

Did you change the "Tout le monde" Windows group by your own language version ?
I replace the grfAccessPermissions.i by Long and you're right it works too.
Windows 10 Pro x64
PureBasic 6.20 x64
User avatar
luis
Addict
Addict
Posts: 3895
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: WinApi : Set File Permission (32bits/64bits)

Post by luis »

tatanas wrote: Tue Jun 20, 2023 11:35 am Did you change the "Tout le monde" Windows group by your own language version ?
Evidently no, I did but maybe I made a typo. I'm sorry. Works now. Or at least I don't get the error.
But your last code seems to just be adding "everyone" not to replace everything else.
And now that I notice... doesn't set all the permission to enabled like the original code, I have only read and write.

Still, the original one with just the alignment changed worked for me.
Was supposed to add the "everyone" group or to replace everything with the "everyone" group ?
Because both 32 and 64 seem to do the latter so I assumed that was what you wanted to do.
Anyway, both the 32 bits and the 64 bits were giving the same result on my PC.
"Have you tried turning it off and on again ?"
tatanas
Enthusiast
Enthusiast
Posts: 260
Joined: Wed Nov 06, 2019 10:28 am
Location: France

Re: WinApi : Set File Permission (32bits/64bits)

Post by tatanas »

It was supposed to add the "everyone" group. So it works as it should for both of us :).
Thanks for your help.
Windows 10 Pro x64
PureBasic 6.20 x64
Post Reply