Question

I've been trying to get this call to cooperate, but to no success.

I'm trying to get the SID value for the current user in order to get the User's account rights (using LsaEnumerateAccountRights). Although I'm lost as to why My call to GetTokenInformation is returning false. No error in retrieving the process token.

Here is my work so far on the subject:

    HANDLE h_Process;
HANDLE h_Token;
HANDLE h_retToken;

TOKEN_USER tp;
DWORD cb = sizeof(TOKEN_USER);
PDWORD ret;

DWORD dw_TokenLength;

h_Process = GetCurrentProcess();

if (OpenProcessToken(h_Process, TOKEN_READ, &h_Token) == FALSE)
{
    printf("Error: Couldn't open the process token\n");
    return -1;
}

if (GetTokenInformation(h_Token, TokenUser, &tp, cb, &dw_TokenLength) == FALSE)
{
    printf("Error: Could not retrieve Token User information");
    return -1;
}

And along with it, I might as well ask a follow up question that I have not yet encountered, how to retrieve the SID from the formed TOKEN_USER structure?

I apologize ahead of time for such a simple question, I'm just stumped and would like some help to continue. All the questions related to this one are far more complicated and give little insight to my current problem.

Thanks in advance, Jon

Was it helpful?

Solution

According to the documentation For GetTokenInformation, if the function fails you can retrieve more information via a call to GetLastError.

Return Value

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

So you need to implement some checking for the extended error:

if (!GetTokenInformation(h_Token, TokenUser, &tp, cb, &dw_TokenLength))
{
    int lastError = GetLastError();

    // Should be a switch, of course. Omitted for brevity
    if (lastError == ERROR_INSUFFICIENT_BUFFER) 
    {
        //
    }
}  

As a general rule of thumb when using WinAPI functions that have varying buffer requirements, you typically

  • Call the function with a NULL buffer to determine the buffer size needed (in this case, returned in the ReturnLength parameter)
  • Allocate a buffer of the indicated size
  • Call the function again, passing the allocated buffer, to obtain the information

OTHER TIPS

The first thing to understand is that Win32 UM (user mode) APIs that result into system calls generally require that you provide the buffer up front. This has to do with the fact that the kernel can access UM heap allocations, and UM cannot access KM allocations.

These calls typically follow a convention where you call once to get the required buffer size, and then call again with an allocated buffer that is large enough. It is even better though if you can create a reasonably sized buffer upfront. System calls can be expensive because of the context switching that it causes, so going from 2 calls to 1 can be a big performance improvement if it is a hot path.

Here is a sample of what you need. This has a loop that will try forever, but it is also common to just try twice. If the needed buffer is <= 128, it will only call once.

DWORD bytesReturned = 128;
LPVOID tokenUser = nullptr;
auto cleanup = ScopeExit([&]() 
{
    LocalFree(tokenUser);
});
for (;;) {
    tokenUser = LocalAlloc(LMEM_FIXED, bytesReturned);
    THROW_HR_IF_NULL(E_OUTOFMEMORY, tokenUser);
    if (!GetTokenInformation(token.get(), TokenUser, &tokenUser, bytesReturned, &bytesReturned))
    {
        if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
        {
            LocalFree(tokenUser);
            tokenUser = nullptr;
            continue;
        }
        THROW_HR(HRESULT_FROM_WIN32(GetLastError()));
    }
    break;
}

The other big problem with your code is that you are passing in a reference to TOKEN_USER tp. The API actually just takes a PVOID. The SID's buffer will just be in tokenUser's buffer. You will need to cast it to a TOKEN_USER* to correctly access the memory.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top