【问题标题】:How to get the SID and User Name of the user utilising my service in C++如何在 C++ 中使用我的服务获取用户的 SID 和用户名
【发布时间】:2017-02-27 10:38:27
【问题描述】:

我正在尝试创建一个基本上充当本地 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;
}

【问题讨论】:

  • TCP/IP 是匿名的,您需要在您的服务器中实现身份验证,即提示输入用户名和密码。
  • 不确定确切的条件,但如果您需要唯一登录用户的 SID,您可以使用 WTSGetActiveConsoleSessionId 和 WTSQueryUserToken 获取用户令牌,然后使用 GetTokenInformation 获取 SID。但您需要适当的访问权限才能执行此操作。
  • @KonstantinL 我确实尝试过这种技术,但它导致了服务的 SID 和用户名。您知道需要什么访问权限才能使其返回用户的 SID 和/或用户名吗?
  • 嗯.. 出了点问题。如果权限不足,您应该获得零句柄,而不是服务句柄。你能展示你的代码吗?
  • @KonstantinL 您好,我已附上我当前的代码。

标签: c++ windows winapi


【解决方案1】:

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

【讨论】:

  • 好的,OP 明确表示用户会使用localhost URL,所以这个答案是可以接受的。但是您至少应该警告您正在提供当前会话的 URL(如果有)在服务运行的机器上。因此,如果来自 machineA 的 clientA 连接到由 userB 运行的 machineB 的服务(您将获得 userB),它将不会给出预期的结果。如果机器B上的用户C下运行的计划任务也连接到机器B上的服务:仍然获取用户B
  • 这种方法不考虑:1)服务器机器有多个用户同时登录,2)根本没有用户登录(服务不需要用户登录) , 或 3) 远程登录的机器。与其使用WTSGetActiveConsoleSessionId(),不如考虑使用WTSEnumerateSessions(),寻找处于WTSActive 状态的会话(用户已登录)。
  • @RemyLebeau 这些是我需要考虑的其他情况,因此我尝试使用您建议的方法,但是因此 LookUpAccountSid 失败并出现错误代码 87 (ERROR_INVALID_PARAMETER),并且 ConvertSidToStringSid 失败并出现错误代码 1337 (ERROR_INVALID_SID_STRUCTURE) .您知道是什么原因造成的吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-01
  • 2011-10-28
相关资源
最近更新 更多