I'm writing a logging service that may collect privileges of a process and I'm trying to understand attributes for each process privilege. Let me explain with this code:
HANDLE hToken;
if(OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &hToken))
{
DWORD dwSize = 0;
if(!GetTokenInformation(hToken, TokenPrivileges, NULL, dwSize, &dwSize) &&
::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
BYTE* pb = new (std::nothrow) BYTE[dwSize];
if(pb)
{
TOKEN_PRIVILEGES* pTPs = (TOKEN_PRIVILEGES*)pb;
DWORD dwSize2;
if(GetTokenInformation(hToken, TokenPrivileges, pTPs, dwSize, &dwSize2) &&
dwSize2 <= dwSize)
{
for(UINT i = 0; i < pTPs->PrivilegeCount; i++)
{
//Analyze privilege attributes to understand if it's enabled or disabled?
DWORD dwPrivAttr = pTPs->Privileges[i].Attributes;
//...
}
}
delete[] pb;
}
}
CloseHandle(hToken);
}
So let's see the structure of TOKEN_PRIVILEGES and LUID_AND_ATTRIBUTES
in particular:
#define SE_PRIVILEGE_ENABLED_BY_DEFAULT (0x00000001L)
#define SE_PRIVILEGE_ENABLED (0x00000002L)
#define SE_PRIVILEGE_REMOVED (0X00000004L)
#define SE_PRIVILEGE_USED_FOR_ACCESS (0x80000000L)
It looks like it is defined as a bitmask, but that brings up the following questions of interpreting these flags:
What is the difference between
ENABLED
andENABLED_BY_DEFAULT
?What is
SE_PRIVILEGE_USED_FOR_ACCESS
and how can it be used?What if both
SE_PRIVILEGE_ENABLED
andSE_PRIVILEGE_REMOVED
are set? Or, reset?I just ran a simple test and for my process the
SeShutdownPrivilege
privilege had those attributes set as0
. So what is that supposed to mean?
I'm more confused over this structure, but I'll keep it at just these points for now.
Thank you!
What some of us may need to be told explicitly is that privileges have THREE possible states, not just two. As I began researching this stuff, I thought that a process would either have, or not have a privilege. But it turns out that even if the process has a privilege, it can be in a disabled state. In other words, disabled != doesn't have it.
The rest follows logically. If a privilege is not present in the process' access token, the process does not have that privilege. And vice versa, if the process does not have a privilege, the privilege will not be present in the token.
If the process has the privilege, the process can enable or disable it at will, right? Why is this useful? All right, I can guess that this allows you to call library functions without fully knowing what they do, and have them fail if they do more than you thought... Odd though.
To take your questions in order:
ENABLED_BY_DEFAULT
means the privilege is one of those that is enabled when the process starts. If you haveENABLED
but notENABLED_BY_DEFAULT
then the process has enabled the privilege explicitly. If you haveENABLED_BY_DEFAULT
but notENABLED
then the process has disabled the privilege explicitly.According to the documentation,
SE_PRIVILEGE_USED_FOR_ACCESS
is set whenever the privilege is actually used. You might use this for troubleshooting, e.g., to detect that you are setting privileges that you are not actually using, or to determine experimentally which privileges a particular system call needs. (I've never checked whether this actually behaves as documented, though I have no reason to think otherwise.)If both
SE_PRIVILEGE_ENABLED
andSE_PRIVILEGE_REMOVED
are set, you've found a bug in Windows. :-)If neither
SE_PRIVILEGE_ENABLED
norSE_PRIVILEGE_REMOVED
are set, then the privilege is present in the token, and has not been removed, but is not currently enabled. You can enable it (or remove it) with AdjustTokenPrivileges().If the attribute is zero, then the privilege is present in the token but is not currently enabled, has not been removed, was not enabled by default, and has never been used by the process.