2017-02-27 303 views
2

我正在嘗試創建基本上充當本地Web服務器的服務。理論上,用戶將通過在瀏覽器中通過本地主機訪問URI來使用REST API,即http://localhost:2017/path/to/function/call將連接到該服務並執行一個功能。如何獲取在C++中使用我的服務的用戶的SID和用戶名

我的問題是如何獲取調用該服務的帳戶的SID和用戶名?

我已經實現了幾個解決方案,但它們返回服務的SID和用戶名,而不是使用它的用戶。

OJSon* UnifiedStreamingService::getUserDetails() 
{ 

    OJSon* result = OJSon::create(); 
    if(result) 
    { 
     /* 
     HANDLE hToken = NULL; 
     ULONG id = WTSGetActiveConsoleSessionId(); 

     BOOL bRet = WTSQueryUserToken(id, &hToken); 
     if (bRet == false) 
     { 
      DWORD error = GetLastError(); 
      printf("ERROR: %d", error); 
     } 
     */ 
     HANDLE hToken = NULL; 
     if (! OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) 
     { 
      //_tprintf(_T("OpenProcessToken failed. GetLastError returned: %d\n"), GetLastError()); 
      return NULL; 
     } 

     // Get the size of the memory buffer needed for the SID 
     DWORD dwBufferSize = 0; 
     if (! GetTokenInformation(hToken, TokenUser, NULL, 0, &dwBufferSize) && (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) 
     { 
      //_tprintf(_T("GetTokenInformation failed. GetLastError returned: %d\n"), GetLastError()); 
      // Cleanup 
      CloseHandle(hToken); 
      hToken = NULL; 

      return NULL; 
     } 
     // Allocate buffer for user token data 
     std::vector<BYTE> buffer; 
     buffer.resize(dwBufferSize); 
     PTOKEN_USER pTokenUser = reinterpret_cast<PTOKEN_USER>(&buffer[0]); 
     // Retrieve the token information in a TOKEN_USER structure 
     if (! GetTokenInformation( 
       hToken, 
       TokenUser, 
       pTokenUser, 
       dwBufferSize, 
       &dwBufferSize)) 
     { 
      //_tprintf(_T("2 GetTokenInformation failed. GetLastError returned: %d\n"), GetLastError()); 
      // Cleanup 
      CloseHandle(hToken); 
      hToken = NULL; 

      return NULL; 
     } 
     // Check if SID is valid 
     if (! IsValidSid(pTokenUser->User.Sid)) 
     { 
      //_tprintf(_T("The owner SID is invalid.\n")); 
      // Cleanup 
      CloseHandle(hToken); 
      hToken = NULL; 

      return NULL; 
     } 
     // add the name 
     OString* name = lookupAccountSid(pTokenUser->User.Sid); 
     if(name) 
     { 
      result->setKey(&OString("name"), name); 
      SAFEDELETE(name); 
     } 
     // add the SID 
     OString* sid = convertSidToString(pTokenUser->User.Sid); 
     if(sid) 
     { 
      result->setKey(&OString("SID"), sid); 
      SAFEDELETE(sid); 
     } 
     // Cleanup 
     CloseHandle(hToken); 
     hToken = NULL; 

    } 
    return result; 
} 

OString* UnifiedStreamingService::convertSidToString(PSID pSID) 
{ 
    OString* result = NULL; 

    if(pSID) 
    { 
     // Get string corresponding to SID 
     LPTSTR pszSID = NULL; 
     if (! ConvertSidToStringSid(pSID, &pszSID)) 
     { 
      return NULL; 
     } 
     result = new OString(pszSID); 
     // Release buffer allocated by ConvertSidToStringSid API 
     LocalFree(pszSID); 
     pszSID = NULL; 
    } 

    return result; 
} 

OString* UnifiedStreamingService::lookupAccountSid(PSID pSID) 
{ 
DWORD dwSize = 256; 
DWORD dwResult = 0; 
SID_NAME_USE SidType; 
LPTSTR lpName = new TCHAR[dwSize]; 
LPWSTR lpDomain = new TCHAR[dwSize]; 
OString* result = NULL; 

    if(!LookupAccountSid(NULL, pSID, lpName, &dwSize, lpDomain, &dwSize, &SidType)) 
    { 
     dwResult = GetLastError(); 
     return NULL; 
    } 

    OString* pDomain = new OString(lpDomain); 
    OString* pName = new OString(lpName); 
    if(pDomain && pName) 
    { 
     result = OString::createByFormat(&OString("%s\\%s"), pDomain, pName); 

     SAFEDELETE(pDomain); 
     SAFEDELETE(pName); 
    } 

    delete[] lpDomain; 
    delete[] lpName; 

    return result; 
} 
+1

TCP/IP是匿名的,你將需要在你的服務器中實現驗證,即提示輸入用戶名和密碼。 –

+0

不確定有關確切的條件,但如果您需要唯一登錄用戶的SID,則可以使用WTSGetActiveConsoleSessionId和WTSQueryUserToken獲取用戶令牌,然後使用GetTokenInformation獲取SID。但是您需要適當的訪問權限來執行此操作。 – KonstantinL

+0

@KonstantinL我確實嘗試了這種技術,但它導致了服務的SID和用戶名。你知道什麼訪問權限才能使其返回用戶的SID和/或用戶名嗎? – David

回答

0

任務可以通過使用WTSGetActiveConsoleSessionId和WTSQueryUserToken來獲得用戶令牌,然後讓SID與GetTokenInformation來完成。 附加要求是服務在本地系統帳戶下運行,授予SE_TCB_NAME權限(== SeTcbPrivilege)。請求WTSQueryUserToken需要SE_TCB_NAME。請注意,其他帳戶通常沒有SE_TCB_NAME的權限!

+0

好的,OP明確表示用戶會使用'localhost' URL,這樣這個答案可以接受。但是您至少應警告您在服務運行的計算機上提供當前會話的URL **。因此,如果來自machineA的clientA連接到由userB運行的machineB的服務(您將獲得userB),它將不會給出預期的結果。如果在machineB上的userC下運行的計劃任務連接到machineB上的服務:仍然可以獲得userB –

+0

此方法不考慮:1)具有多個用戶同時登錄的服務器計算機; 2)沒有用戶登錄(服務不需要用戶登錄),或3)遠程登錄的機器。而不是使用'WTSGetActiveConsoleSessionId()',而應考慮使用'WTSEnumerateSessions()'來查找'WTSActive'狀態下的會話(用戶登錄)。 –

+0

@RemyLebeau這些都是我需要考慮到這樣其他方案我試圖使用你的建議但因此執行LookupAccountSid失敗,錯誤代碼87(ERROR_INVALID_PARAMETER)和ConvertSidToStringSid失敗,錯誤代碼1337(ERROR_INVALID_SID_STRUCTURE)的方法。你有任何想法可能會導致此? – David

相關問題