2017-02-27 10 views
2

本質的にローカルWebサーバーとして機能するサービスを作成しようとしています。理論的には、ユーザーはブラウザでlocalhostを使用して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

@ ConstantinLこの手法を試しましたが、サービスのSIDとユーザー名がありました。ユーザーのSIDおよび/またはユーザー名を返すために必要なアクセス権を知っていますか? – David

答えて

0

タスクは、ユーザーがトークンを取得するWTSGetActiveConsoleSessionIdとWTSQueryUserTokenを使用して、GetTokenInformationでSIDを取得することによって達成することができます。 追加の要件は、SE_TCB_NAME privelege(== SeTcbPrivilege)を付与するローカルシステムアカウントでサービスが実行されていることです。 SE_TCB_NAMEはWTSQueryUserTokenが必要です。他のアカウントには通常SE_TCB_NAME特権がありません。

+0

OK、OPは、ユーザーが 'localhost' URLを使用すると明示的に言ったので、この答えは受け入れられるかもしれません。しかし、サービスが実行されているマシンであれば**現在のセッションのURL **を与えていることを少なくとも警告する必要があります。したがって、machineAのclientAがuserBが実行しているmachineBのサービスに接続すると(userBを取得すると)期待される結果は得られません。 machineB上のuserCの下で実行されているスケジュールされたタスクがmachineBのサービスに接続していない場合:まだget userB –

+0

このアプローチでは、1)複数のユーザーが同時にログインしているサーバーマシン、2)ログインしていないユーザー(サービスはユーザーにログインする必要はありません)、または3)マシンがリモートにログインしていることを示します。 'WTSGetActiveConsoleSessionId()'を使うのではなく 'WTSEnumerateSessions()'を使って、 'WTSActive'状態(ログインしたユーザ)のセッションを探してください。 –

+0

@RemyLebeauこれは、私が考慮する必要がある追加のシナリオですので、LookUpAccountSidはエラーコード87(ERROR_INVALID_PARAMETER)で失敗し、ConvertSidToStringSidはエラーコード1337(ERROR_INVALID_SID_STRUCTURE)で失敗します。何が原因かもしれないか考えていますか? – David

関連する問題