2014-01-24 96 views
0

我一直試圖讓這個電話合作,但沒有成功。GetTokenInformation的基礎

我想獲取當前用戶的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; 
} 

並與它一起,我還不如問我還沒有遇到一個跟進的問題,如何從形成檢索SID TOKEN_USER結構?

對於這樣一個簡單的問題,我提前道歉,我只是難住,希望能夠繼續幫助。所有與這個問題有關的問題都要複雜得多,並且對我目前的問題沒有多大的瞭解。

在此先感謝,喬恩

回答

1

按照documentation For GetTokenInformation,如果函數失敗,您可以通過給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 .

所以你需要實現擴展錯誤一些檢查:

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
  • 分配所指示的大小
  • 呼叫的功能的緩衝器再次,通過分配的緩衝區,以獲得信息
+0

那麼,好的呼叫緩衝區不足。爲什麼會發生這種錯誤?我遇到了這個問題,並且注意到顯然需要對這個方法進行兩次調用([link](http://stackoverflow.com/questions/3670984/gettokeninformation-first-call-what-for)),不明白需要兩個電話。此外,爲什麼DWORD cb = sizeof(TOKEN_USER)沒有提供足夠的內存分配/緩衝區? – Jon

+1

發生錯誤是因爲緩衝區不足。 :-)它的內容不夠大。我再次向您推薦文檔。如果函數失敗,則將'ReturnLength'參數設置爲所需緩衝區的大小,以便分配足夠的內存並再次調用該函數。許多具有可變緩衝區要求的API調用的一般規則是「使用NULL緩衝區調用函數一次,以確定所需的緩衝區大小,分配內存,然後再次調用它以實際檢索信息」。 –

+0

我會盡量回答你的實際問題。 Windows經常這樣做的原因是「首先調用大小」是struct結構版本的變化。當你編譯時,編譯器知道它的結構是什麼時候(編譯器)被釋放。在編譯器之前或之後的操作系統上運行應用程序時,該結構可能已由MS更改並具有更多或更少的字段。這隻能在運行時才能知道,所以這就是爲什麼他們會返回該代碼並讓您再次嘗試。你不會知道多餘的字節是什麼,所以你通常會忽略它們。 – user2957811

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 *才能正確訪問內存。