GetTokenInformation的基础知识

时间:2014-01-24 00:43:09

标签: c++ token rights

我一直试图接受这种合作,但没有成功。

我正在尝试获取当前用户的SID值以获取用户的帐户权限(使用LsaEnumerateAccountRights)。虽然我迷失了为什么我对GetTokenInformation的调用返回false。检索进程令牌时没有错误。

这是我迄今为止关于这个主题的工作:

    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;
}

与此同时,我不妨问一个我尚未遇到的跟进问题,如何从形成的TOKEN_USER结构中检索SID?

我提前为这么简单的问题道歉,我只是难过,希望继续帮助。与此相关的所有问题都要复杂得多,并且对我当前的问题几乎没有任何了解。

提前致谢,                    乔恩

2 个答案:

答案 0 :(得分:1)

根据documentation For GetTokenInformation,如果功能失败,您可以通过致电GetLastError来检索更多信息。

  

返回值

     

如果函数成功,则返回值为非零值。

     

如果函数失败,则返回值为零。要获取扩展错误信息,请致电GetLastError

因此,您需要对扩展错误执行一些检查:

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) 
    {
        //
    }
}  

作为使用具有不同缓冲要求的WinAPI函数的一般经验法则,通常

  • 使用NULL缓冲区调用该函数以确定所需的缓冲区大小(在这种情况下,在ReturnLength参数中返回)
  • 分配指定大小的缓冲区
  • 再次调用该函数,传递分配的缓冲区,以获取信息

答案 1 :(得分:0)

首先要了解的是,导致系统调用的Win32 UM(用户模式)API通常要求您预先提供缓冲区。这与内核可以访问UM堆分配,UM无法访问KM分配这一事实有关。

这些调用通常遵循一种惯例,在该约定中,您调用一次以获取所需的缓冲区大小,然后使用足够大的已分配缓冲区再次调用。如果你可以预先创建一个合理大小的缓冲区,那就更好了。由于它引起的上下文切换,系统调用可能很昂贵,因此如果它是一个热门路径,从2个调用到1可以大大提高性能。

以下是您需要的示例。这有一个循环,将永远尝试,但它也是常见的只是尝试两次。如果所需的缓冲区是< = 128,它只会调用一次。

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;
}

您的代码的另一个大问题是您传递了对TOKEN_USER tp的引用。 The API actually just takes a PVOID。 SID的缓冲区将位于tokenUser的缓冲区中。您需要将其强制转换为TOKEN_USER *才能正确访问内存。