Here is the minimal code for reference
ULONG result = GetSecurityInfo(Hfile
, SE_FILE_OBJECT
, OWNER_SECURITY_INFORMATION |GROUP_SECURITY_INFORMATION| DACL_SECURITY_INFORMATION
, &sidowner
, &sidgroup
, &pdacl
, NULL
, &psd);
This is how I extracted the access control entries from DACL
BOOL b = GetAce(pdacl, i, (LPVOID*)&ace);
if (((ACCESS_ALLOWED_ACE*)ace)->Header.AceType == ACCESS_ALLOWED_ACE_TYPE) {
sid = (PSID)&((ACCESS_ALLOWED_ACE*)ace)->SidStart;
LookupAccountSid(NULL, sid, oname, &namelen, doname, &domainnamelen, &peUse);
wcout << "domianName/AccoutName : " << doname << "/" << oname << endl;
mask = ((ACCESS_ALLOWED_ACE*)ace)->Mask;
cout << "Allowed" << endl;
}
output:
domianName/AccoutName : BUILTIN/Administrators
Allowed
DELETE
FILE_GENERIC_READ
FILE_GENERIC_WRITE
FILE_GENERIC_EXECUTE
READ_CONTROL
WRITE_DAC
WRITE_OWNER
SYNCHRONIZE
domianName/AccoutName : BUILTIN/Administrators
Allowed
DELETE
FILE_GENERIC_READ
FILE_GENERIC_WRITE
FILE_GENERIC_EXECUTE
READ_CONTROL
WRITE_DAC
WRITE_OWNER
SYNCHRONIZE
domianName/AccoutName : BUILTIN/Administrators
Allowed
DELETE
FILE_GENERIC_READ
FILE_GENERIC_WRITE
FILE_GENERIC_EXECUTE
READ_CONTROL
SYNCHRONIZE
domianName/AccoutName : BUILTIN/Users
Allowed
FILE_GENERIC_READ
FILE_GENERIC_WRITE
FILE_GENERIC_EXECUTE
READ_CONTROL
SYNCHRONIZE
As we can see from the above output Administrators have multiple entries and ACE of "System" and "Authenticated users" are not found. "Users" only have read rights in file properties but in the output, it is printed that the "Users" have "Write access" as well.
I did a lot of research and read through many books but nothing seems to give a clear-cut answer
edit:
Here's the output using the CACLS
command.
C:\Users\Administrator>cacls e:/hello.txt
e:\hello.txt BUILTIN\Administrators:F
NT AUTHORITY\SYSTEM:F
NT AUTHORITY\Authenticated Users:C
BUILTIN\Users:R
CodePudding user response:
The first part of the question:
The reason why the program prints the name same account name repeatedly is because the LookupAccountSid
function does not have enough data area. since the namelen
and domainlen
are IN\OUT
arguments the function returns the size of the domain name and account name every time after execution. So to solve this the namelen
and domainlen
have to be reassigned every time.
LookupAccountSid(NULL, sid, oname, &namelen, doname, &domainnamelen, &peUse);
wcout << "domianName/AccoutName : " << doname << "/" << oname << endl;
namelen = 100; domainnamelen = 100; //This should solve the problem
Here is the link to the docs for the LookupAccountSid function
The second part of the question
The reason why the output from the program shows the users have FILE_GENERIC_WRITE
permission even though the CACLS
seem to show that users only have read and execute permission to the given file path is that in the program the code that checks if the users have the write permissions
is done by the following.
if (FILE_GENERIC_WRITE & ace->Mask) {
wcout << " FILE_GENERIC_WRITE" << "\n";
}
The problem is the FILE_GENERIC_WRITE
consists of multiple permissions like STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE
and when the code is written like this (FILE_GENERIC_WRITE & ace->Mask)
it only checks if at least one of the permissions is present or not.
A special thanks to @user253751 and @Werner Henze for patiently explaining the solution