如何在C ++中获取使用我的服务的用户的SID和用户名

时间:2017-02-27 10:38:27

标签: c++ windows winapi

我正在尝试创建一个基本上充当本地Web服务器的服务。理论上,用户将通过浏览器中的localhost访问URI来使用REST API,即http://localhost:2017/path/to/function/call将连接到服务并执行函数。

我的问题是如何获取调用该服务的帐户的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 个答案:

答案 0 :(得分:0)

可以使用WTSGetActiveConsoleSessionId和WTSQueryUserToken来获取用户令牌,然后使用GetTokenInformation获取SID来完成任务。 附加要求是服务在本地系统帐户下运行,该帐户授予SE_TCB_NAME privelege(== SeTcbPrivilege)。 WTSQueryUserToken需要SE_TCB_NAME。请注意,其他帐户通常没有SE_TCB_NAME privelege!