A properly constructed security descriptor contains Access Control Entries (ACEs) in a specified order. This is known as the canonical order. You can see the proper ordering by referring to Order of ACEs in a DACL. Notably, deny ACEs take precedence over allow ACEs.
File permissions precedence
Hi,
By setting , via Win32 API , following permissions on a file
Everyone group : deny GENERIC_READ , GENERIC_WRITE , GENERIC_EXECUTE
Onwer User : allow GENERIC_READ , GENERIC_WRITE , GENERIC_EXECUTE
then , when trying to acces to file ( i.e. for editing ) error coe 05 (access denied) is returned .
It looks like the group permissions has precedence on user permissions.
Is it right ?
(By setting Everyone group : allow GENERIC_READ , GENERIC_WRITE , GENERIC_EXECUTE , error 0x05 disappears)
Thx for help.
Regards,
J.P.
Windows API - Win32
-
Deleted
This comment has been deleted due to a violation of our Code of Conduct. The comment was manually reported or identified through automated detection before action was taken. Please refer to our Code of Conduct for more information.
Sign in to comment
-
RLWA32 45,701 Reputation points
2024-07-24T18:47:43.7833333+00:00 -
RLWA32 45,701 Reputation points
2024-07-25T11:27:34.8666667+00:00 And as an afterthought, group permissions do not take precedence over user permissions.
-
Jean-Pierre Ribeauville 80 Reputation points
2024-07-25T12:24:05.7433333+00:00 What I've checked is :
Everyone group precedes user owner of the file : by disabling permissions for Everyone then file is no more accessible even by the owner of the file .
My understanding is that "EveryOne" group on Windows has not the same meaning as "Others" group in Unix world. -
RLWA32 45,701 Reputation points
2024-07-25T13:13:23.4366667+00:00 disabling permissions for Everyone then file is no more accessible even by the owner of the file .
I don't know what this means. Be specific. Did you remove permissions from an access allowed ace or use an access denied ace?
Also, read this -- How AccessCheck Works
-
Jean-Pierre Ribeauville 80 Reputation points
2024-07-25T13:44:44.7033333+00:00 I did that by using two different ways (result is identical) :
use an access denied ace via win32 API or by right clicking in File Properties and disabling these permissions for Everyone group. -
RLWA32 45,701 Reputation points
2024-07-25T15:48:53.1233333+00:00 As we've already seen a deny ACE takes precedence over an allow ACE so that is a non-issue.
On the other hand, if the security descriptor includes an ACE that grants access to the file owner then the presence of an ACE for the Everyone group that does not grant any access has no effect.
Security descriptor for a file owned by rlwa32 -
Demonstration of user RLWA32 accessing the file -
So your earlier comment doesn't make sense to me. Perhaps you are doing something different from what I expect from your comment.
-
Jean-Pierre Ribeauville 80 Reputation points
2024-07-26T07:51:14.4966667+00:00 Hi,
Thx for explanation.
J.P. -
RLWA32 45,701 Reputation points
2024-07-26T08:11:39.4533333+00:00 You're welcome. Has my Answer and related comments resolved your question about how Windows uses security descriptors?
-
Jean-Pierre Ribeauville 80 Reputation points
2024-07-26T08:18:10.2066667+00:00 I'm not able to get None in the Everyone Access column
On my side , I'm only able to see an Everyone line if I allow Read at least -
RLWA32 45,701 Reputation points
2024-07-26T08:46:23.9966667+00:00 I'm not able to get None in the Everyone Access column
I wrote a small program that created the security descriptor using the Windows API. Then the program created a new file and specified that it should have that security descriptor.
If the security settings for the file are subsequently edited using the file's properties->security UI then the editor removes the Everyone ace.
-
Jean-Pierre Ribeauville 80 Reputation points
2024-07-26T09:14:29.1633333+00:00 O.K.
I'll do it in the same way .
Setting these ACES , in the security descriptor :
grfAccessPermission = GENERIC_ALL , grfAccessMode=SET_ACCESS for the owner
grfAccessPermission =GENERIC_ALL , grfAccessMode=DENY_ACESS for EveryOne
Is it correct ?
Thx -
Jean-Pierre Ribeauville 80 Reputation points
2024-07-26T09:18:39.36+00:00 O.K.
I"ll do it in the same way :
Setting these ACES in the file security descriptor
grfAccessPermissions = GENERIC_ALL , grfAccessMode =SET_ACCESS for the owner
grfAccessPermissions =GENERIC_ALL , grfAccessMode =DENY_ACCESS for EveryOner
Am I right ?
Thx -
RLWA32 45,701 Reputation points
2024-07-26T09:34:02.5833333+00:00 This is what is used in the EXPLICIT_ACCESSW structure for Everyone -
ea[0].grfAccessMode = GRANT_ACCESS; ea[0].grfAccessPermissions = 0; ea[0].grfInheritance = NO_INHERITANCE; ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID; ea[0].Trustee.ptstrName = reinterpret_cast<LPWCH>(everyone);
-
RLWA32 45,701 Reputation points
2024-07-26T09:57:22.82+00:00 Would you like me to post the sample program for you to reference?
-
Jean-Pierre Ribeauville 80 Reputation points
2024-07-26T11:10:13.4066667+00:00 Sure.
It would be great
Thx -
RLWA32 45,701 Reputation points
2024-07-26T11:26:22.7+00:00 Sample code follows -
#define WIN32_LEAN_AND_MEAN #include <Windows.h> #include <AclAPI.h> #include <stdio.h> int main() { SECURITY_DESCRIPTOR descriptor{}; PACL pDacl{}; PTOKEN_USER ptu{}; BYTE system[SECURITY_MAX_SID_SIZE]{}, everyone[SECURITY_MAX_SID_SIZE]{}; DWORD cbsystem{ SECURITY_MAX_SID_SIZE }, cbeveryone{ SECURITY_MAX_SID_SIZE }; DWORD ReturnLength{}, result{}; EXPLICIT_ACCESSW ea[3]{}; SECURITY_ATTRIBUTES sa{ sizeof sa, &descriptor, FALSE }; HANDLE hFile{}, hHeap{}; hHeap = GetProcessHeap(); GetTokenInformation(GetCurrentProcessToken(), TokenUser, nullptr, 0, &ReturnLength); ptu = static_cast<PTOKEN_USER>(HeapAlloc(hHeap, HEAP_ZERO_MEMORY, ReturnLength)); if (!ptu) { printf_s("Memory allocation failed!"); goto exit; } if (!GetTokenInformation(GetCurrentProcessToken(), TokenUser, ptu, ReturnLength, &ReturnLength)) { printf_s("GetTokenInformation failed with %d\n", GetLastError()); goto exit; } if (!CreateWellKnownSid(WinLocalSystemSid, nullptr, system, &cbsystem) || !CreateWellKnownSid(WinWorldSid, nullptr, everyone, &cbeveryone)) { printf_s("CreateWellKnownSid failed with %d\n", GetLastError()); goto exit; } ea[0].grfAccessMode = GRANT_ACCESS; ea[0].grfAccessPermissions = 0; ea[0].grfInheritance = NO_INHERITANCE; ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID; ea[0].Trustee.ptstrName = reinterpret_cast<LPWCH>(everyone); ea[1].grfAccessMode = GRANT_ACCESS; ea[1].grfAccessPermissions = GENERIC_ALL; ea[1].grfInheritance = NO_INHERITANCE; ea[1].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID; ea[1].Trustee.ptstrName = reinterpret_cast<LPWCH>(system); ea[2].grfAccessMode = GRANT_ACCESS; ea[2].grfAccessPermissions = GENERIC_ALL; ea[2].grfInheritance = NO_INHERITANCE; ea[2].Trustee.TrusteeType = TRUSTEE_IS_USER; ea[2].Trustee.TrusteeForm = TRUSTEE_IS_SID; ea[2].Trustee.ptstrName = reinterpret_cast<LPWCH>(ptu->User.Sid); result = SetEntriesInAclW(ARRAYSIZE(ea), ea, nullptr, &pDacl); if (result != ERROR_SUCCESS) { printf_s("SetEntriesInAclW failed with %d\n", result); goto exit; } if (!InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION)) { printf_s("InitializeSecurityDescriptor failed with %d\n", GetLastError()); goto exit; } if (!SetSecurityDescriptorDacl(&descriptor, TRUE, pDacl, FALSE)) { printf_s("SetSecurityDescriptorDacl failed with %d\n", GetLastError()); goto exit; } if (!SetSecurityDescriptorOwner(&descriptor, ptu->User.Sid, FALSE)) { printf_s("SetSecurityDescriptorOwner failed with %d\n", GetLastError()); goto exit; } if (!SetSecurityDescriptorControl(&descriptor, SE_DACL_PROTECTED, SE_DACL_PROTECTED)) { printf_s("SetSecurityDescriptorControl failed with %d\n", GetLastError()); goto exit; } hFile = CreateFileW(L"Testfile.txt", GENERIC_ALL, 0, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile != INVALID_HANDLE_VALUE) { CHAR szText[]{ "This is a test\r\n" }; DWORD written{}; WriteFile(hFile, szText, sizeof szText, &written, nullptr); CloseHandle(hFile); } exit: if (ptu) HeapFree(hHeap, 0, ptu); if (pDacl) LocalFree(pDacl); return 0; }
When you run the sample makes sure that the file does not already exist. The security descriptor is only applied upon new file creation.
-
Jean-Pierre Ribeauville 80 Reputation points
2024-07-26T13:47:11.54+00:00 Thx a lot for all these infos.
I think I would not have been able to understand how it works without your help.
Up to me to work on that.
Have a good day.
Regards,
J.P. -
RLWA32 45,701 Reputation points
2024-07-28T10:17:58.9833333+00:00 If your question has been answered and your issue resolved you could accept the answer for the benefit of others that have similar questions about how file permissions work.
Sign in to comment -