问题
I am attempting to create a service that will essentially act as a local web server. In theory users will use a REST API by visiting URIs through localhost in a browser i.e. http://localhost:2017/path/to/function/call will connect to the service and execute a function.
My question is how do I get the SID and User Name of the account that called the service?
I have implemented a couple of solutions but they return the SID and User Name of the service and not the user using it.
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:
The task can be accomplished by using WTSGetActiveConsoleSessionId and WTSQueryUserToken to get user token and then getting SID with GetTokenInformation. The additional requirement is the service is running under Local System account which grants SE_TCB_NAME privelege (== SeTcbPrivilege). SE_TCB_NAME required by WTSQueryUserToken. Note that the other accounts usually have no SE_TCB_NAME privelege!
来源:https://stackoverflow.com/questions/42483572/how-to-get-the-sid-and-user-name-of-the-user-utilising-my-service-in-c