548 lines
12 KiB
C++
548 lines
12 KiB
C++
//=================================================================
|
|
|
|
//
|
|
|
|
// ImpersonateConnectedUser.cpp -- Class to perform impersonation of
|
|
|
|
// a connected user.
|
|
|
|
//
|
|
|
|
// Copyright (c) 1999-2001 Microsoft Corporation, All Rights Reserved
|
|
//
|
|
// Revisions: 05/21/99 a-peterc Created
|
|
//
|
|
// Notes: This class maps the logon luid ( AuthenticationId )
|
|
// of the running thread to a process that also has the same
|
|
// AuthenticationId. The class then impersonates the process
|
|
// on the running thread.
|
|
//
|
|
// Additional routines are available to allow custom
|
|
// looping across all AuthenticationIds. This is useful when
|
|
// targeting for example a Terminal Server in which information
|
|
// across all AuthenticationIds may be required.
|
|
//
|
|
//=================================================================
|
|
#include "precomp.h"
|
|
#include <tchar.h>
|
|
#include <winerror.h>
|
|
|
|
#include "ImpersonateConnectedUser.h"
|
|
#include <cominit.h>
|
|
|
|
#ifdef NTONLY
|
|
|
|
/*=================================================================
|
|
Function: CImpersonateConnectedUser(),~CImpersonateConnectedUser()
|
|
|
|
Description: contructor and destructor
|
|
|
|
Arguments:
|
|
|
|
Notes:
|
|
Returns:
|
|
Inputs:
|
|
Outputs:
|
|
Caveats:
|
|
Raid:
|
|
History: a-peterc 21-May-1999 Created
|
|
=================================================================*/
|
|
CImpersonateConnectedUser::CImpersonateConnectedUser( BOOL t_fRecacheHive /*=TRUE*/ ) :
|
|
|
|
m_fImpersonatingUser( FALSE ),
|
|
m_hProcessToken( NULL ),
|
|
m_fRecacheHive( t_fRecacheHive )
|
|
{
|
|
// Cache the current thread token
|
|
if ( !OpenThreadToken ( GetCurrentThread(),
|
|
TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE, TRUE,
|
|
&m_hThreadToken ) )
|
|
{
|
|
m_hThreadToken = NULL ;
|
|
}
|
|
|
|
// validate multimap process iterator
|
|
m_ProcessIter = m_oProcessMap.end() ;
|
|
}
|
|
|
|
//
|
|
CImpersonateConnectedUser::~CImpersonateConnectedUser()
|
|
{
|
|
FlushCachedHive() ;
|
|
|
|
End() ;
|
|
|
|
if( m_hThreadToken )
|
|
{
|
|
CloseHandle ( m_hThreadToken ) ;
|
|
}
|
|
|
|
// Clear the luid / process map
|
|
m_oProcessMap.clear();
|
|
}
|
|
|
|
/*=================================================================
|
|
Functions: Begin(), End()
|
|
|
|
Description: Provides for impersonation against the running thread.
|
|
|
|
Arguments:
|
|
|
|
Notes:
|
|
Returns:
|
|
Inputs:
|
|
Outputs:
|
|
Caveats:
|
|
Raid:
|
|
History: a-peterc 21-May-1999 Created
|
|
=================================================================*/
|
|
BOOL CImpersonateConnectedUser::Begin()
|
|
{
|
|
CProcessID t_Process ;
|
|
|
|
__int64 t_ThreadLogonID = GetLogonID( m_hThreadToken ) ;
|
|
|
|
if( t_ThreadLogonID )
|
|
{
|
|
if( FindProcessesBy( t_ThreadLogonID ) )
|
|
{
|
|
// For each process associated with this logon ID
|
|
// attempt to impersonate the process onto the thread.
|
|
|
|
BeginProcessEnum() ;
|
|
|
|
while( GetNextProcess( t_Process ) )
|
|
{
|
|
if( ImpersonateLogonOfProcess( t_Process.dwProcessId ) )
|
|
{
|
|
return TRUE ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return FALSE ;
|
|
}
|
|
|
|
//
|
|
BOOL CImpersonateConnectedUser::End()
|
|
{
|
|
// reverts to whomever this thread was
|
|
// impersonating, i.e. DCOM client or someone else ...
|
|
if( m_hProcessToken )
|
|
{
|
|
CloseHandle( m_hProcessToken ) ;
|
|
m_hProcessToken = NULL ;
|
|
}
|
|
|
|
if( m_fImpersonatingUser )
|
|
{
|
|
ResetImpersonation() ;
|
|
|
|
m_fImpersonatingUser = FALSE ;
|
|
}
|
|
return TRUE ;
|
|
}
|
|
|
|
/*=================================================================
|
|
Functions: BeginProcessEnum(), GetNextProcess( CProcessID &a_oProcess )
|
|
|
|
Description: Provides for custom impersonation across multiple logons.
|
|
|
|
Arguments:
|
|
|
|
Notes: used with FindProcessesBy() and ImpersonateLogonOfProcess()
|
|
Returns:
|
|
Inputs:
|
|
Outputs:
|
|
Caveats:
|
|
Raid:
|
|
History: a-peterc 21-May-1999 Created
|
|
=================================================================*/
|
|
void CImpersonateConnectedUser::BeginProcessEnum()
|
|
{
|
|
m_ProcessIter = m_oProcessMap.begin() ;
|
|
}
|
|
|
|
//
|
|
BOOL CImpersonateConnectedUser::GetNextProcess( CProcessID &a_oProcess )
|
|
{
|
|
if ( m_ProcessIter == m_oProcessMap.end() )
|
|
{
|
|
return FALSE ;
|
|
}
|
|
else
|
|
{
|
|
a_oProcess.luid = m_ProcessIter->first ;
|
|
a_oProcess.dwProcessId = m_ProcessIter->second ;
|
|
++m_ProcessIter ;
|
|
return TRUE ;
|
|
}
|
|
}
|
|
|
|
/*=================================================================
|
|
Functions: ImpersonateLogonOfProcess
|
|
|
|
Description: Provides for impersonation against a targeted process.
|
|
|
|
Arguments:
|
|
|
|
Notes:
|
|
Returns:
|
|
Inputs:
|
|
Outputs:
|
|
Caveats:
|
|
Raid:
|
|
History: a-peterc 21-May-1999 Created
|
|
=================================================================*/
|
|
BOOL CImpersonateConnectedUser::ImpersonateLogonOfProcess( DWORD &a_dwProcessID )
|
|
{
|
|
HANDLE t_hProcess = NULL ;
|
|
|
|
try
|
|
{
|
|
if( m_hProcessToken = GetProcessToken( a_dwProcessID ) )
|
|
{
|
|
if( !ImpersonateLoggedOnUser ( m_hProcessToken ) )
|
|
{
|
|
CloseHandle( m_hProcessToken ) ;
|
|
m_hProcessToken = NULL ;
|
|
|
|
// reset to baseline context
|
|
ResetImpersonation() ;
|
|
}
|
|
else
|
|
{
|
|
m_fImpersonatingUser = TRUE ;
|
|
|
|
RecacheHive() ;
|
|
}
|
|
}
|
|
}
|
|
catch( ... )
|
|
{
|
|
End() ;
|
|
|
|
if( t_hProcess )
|
|
{
|
|
CloseHandle( t_hProcess ) ;
|
|
}
|
|
throw ;
|
|
}
|
|
|
|
return m_hProcessToken ? TRUE : FALSE ;
|
|
}
|
|
|
|
/*=================================================================
|
|
Functions: ResetImpersonation
|
|
|
|
Description: Restores the impersonation on the thread to the original state .
|
|
|
|
Arguments:
|
|
|
|
Notes:
|
|
Returns:
|
|
Inputs:
|
|
Outputs:
|
|
Caveats:
|
|
Raid:
|
|
History: a-peterc 21-May-1999 Created
|
|
=================================================================*/
|
|
void CImpersonateConnectedUser::ResetImpersonation()
|
|
{
|
|
// reset the original impersonation token
|
|
if ( m_hThreadToken )
|
|
{
|
|
if (!ImpersonateLoggedOnUser ( m_hThreadToken ))
|
|
{
|
|
throw CFramework_Exception(L"ImpersonateLoggedOnUser failed", GetLastError());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
HRESULT hr = WbemCoImpersonateClient() ;
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
throw CFramework_Exception(L"WbemCoImpersonateClient failed", hr);
|
|
}
|
|
}
|
|
|
|
RecacheHive() ;
|
|
}
|
|
|
|
/*=================================================================
|
|
Functions: GetLogonID
|
|
|
|
Description: Retrieves a logon luid for a process ot thread token.
|
|
|
|
Arguments:
|
|
|
|
Notes:
|
|
Returns:
|
|
Inputs:
|
|
Outputs:
|
|
Caveats:
|
|
Raid:
|
|
History: a-peterc 21-May-1999 Created
|
|
=================================================================*/
|
|
__int64 CImpersonateConnectedUser::GetLogonID( HANDLE a_hToken )
|
|
{
|
|
// get the session logon ID
|
|
TOKEN_STATISTICS t_oTokenStats ;
|
|
DWORD t_dwReturnLength ;
|
|
|
|
if( GetTokenInformation(
|
|
a_hToken, // handle of access token
|
|
TokenStatistics, // type of information to retrieve
|
|
&t_oTokenStats, // address of retrieved information
|
|
sizeof( t_oTokenStats ),// size of information buffer
|
|
&t_dwReturnLength ) ) // address of required buffer size
|
|
{
|
|
return *(__int64*)(&t_oTokenStats.AuthenticationId) ;
|
|
}
|
|
|
|
return NULL ;
|
|
}
|
|
|
|
/*=================================================================
|
|
Functions: GetProcessToken
|
|
|
|
Description: Retrieves a process token for a specific process.
|
|
|
|
Arguments:
|
|
|
|
Notes:
|
|
Returns:
|
|
Inputs:
|
|
Outputs:
|
|
Caveats:
|
|
Raid:
|
|
History: a-peterc 21-May-1999 Created
|
|
=================================================================*/
|
|
HANDLE CImpersonateConnectedUser::GetProcessToken( DWORD a_dwProcessID )
|
|
{
|
|
HANDLE t_hProcess = NULL ;
|
|
HANDLE t_hProcessToken = NULL ;
|
|
|
|
try
|
|
{
|
|
// Handle for this process
|
|
if ( ( t_hProcess = OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, a_dwProcessID ) ) != NULL )
|
|
{
|
|
// Token for this process. TOKEN_QUERY | TOKEN_DUPLICATE only as
|
|
// as Winmgmt(Local system) can't open the token of the
|
|
// shell process (with all access rights) if the logged-in user is an Admin.
|
|
|
|
if ( !OpenProcessToken( t_hProcess, TOKEN_QUERY | TOKEN_DUPLICATE , &t_hProcessToken ) )
|
|
{
|
|
t_hProcessToken = NULL ;
|
|
}
|
|
|
|
CloseHandle ( t_hProcess ) ;
|
|
t_hProcess = NULL ;
|
|
}
|
|
}
|
|
catch( ... )
|
|
{
|
|
if( t_hProcess )
|
|
{
|
|
CloseHandle ( t_hProcess ) ;
|
|
}
|
|
throw ;
|
|
}
|
|
|
|
return t_hProcessToken ;
|
|
}
|
|
|
|
/*=================================================================
|
|
Functions: FindProcessesBy
|
|
|
|
Description: Locates and builds a process map either by luid or if
|
|
the argument is NULL builds a process map for all processes.
|
|
|
|
Arguments:
|
|
|
|
Notes:
|
|
Returns:
|
|
Inputs:
|
|
Outputs:
|
|
Caveats:
|
|
Raid:
|
|
History: a-peterc 21-May-1999 Created
|
|
=================================================================*/
|
|
BOOL CImpersonateConnectedUser::FindProcessesBy( __int64 a_luid )
|
|
{
|
|
BOOL t_fReturn = FALSE;
|
|
|
|
CPSAPI *t_psapi = (CPSAPI*) CResourceManager::sm_TheResourceManager.GetResource ( guidPSAPI, NULL ) ;
|
|
|
|
if( !t_psapi )
|
|
{
|
|
return FALSE ;
|
|
}
|
|
|
|
DWORD *t_pdwProcessIds = NULL;
|
|
HANDLE t_hThreadToken = NULL;
|
|
HANDLE t_hProcessToken = NULL ;
|
|
try
|
|
{
|
|
DWORD t_dwProcessIdArraySize = 0,
|
|
t_dwNumProcesses = 0,
|
|
t_cbDataReturned = 0;
|
|
BOOL t_fValidProcessArray = FALSE;
|
|
|
|
// Clear the luid / process map
|
|
m_oProcessMap.clear();
|
|
|
|
// make up to 3 passes to get at the process list
|
|
for( int i = 0; i < 3; i++ )
|
|
{
|
|
ReallocProcessIdArray( t_pdwProcessIds, t_dwProcessIdArraySize ) ;
|
|
|
|
if ( t_psapi->EnumProcesses( t_pdwProcessIds, t_dwProcessIdArraySize, &t_cbDataReturned ) )
|
|
{
|
|
// Because EnumProcesses will NOT fail if there are more processes than
|
|
// bytes available in the array, if the amount returned is the same size
|
|
// as the array, realloc the array and retry the Enum.
|
|
|
|
if ( t_dwProcessIdArraySize == t_cbDataReturned )
|
|
{
|
|
ReallocProcessIdArray( t_pdwProcessIds, t_dwProcessIdArraySize );
|
|
}
|
|
else
|
|
{
|
|
t_fValidProcessArray = TRUE ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Identify and stow any processes matching the requested logonID
|
|
if( t_fValidProcessArray )
|
|
{
|
|
// # of processes
|
|
t_dwNumProcesses = t_cbDataReturned / sizeof( DWORD ) ;
|
|
|
|
// ID the processes by logon ID
|
|
for( DWORD t_dwId = 0; t_dwId < t_dwNumProcesses; t_dwId++ )
|
|
{
|
|
// process token
|
|
if( t_hProcessToken = GetProcessToken( t_pdwProcessIds[ t_dwId ] ) )
|
|
{
|
|
// and Logon ID
|
|
__int64 t_ProcessLogonID = GetLogonID( t_hProcessToken ) ;
|
|
|
|
// add to the process list
|
|
if( NULL == a_luid || t_ProcessLogonID == a_luid )
|
|
{
|
|
// map this process
|
|
m_oProcessMap.insert(
|
|
pair<__int64 const, DWORD>(
|
|
t_ProcessLogonID,
|
|
t_pdwProcessIds[ t_dwId ] ) ) ;
|
|
|
|
t_fReturn = TRUE ;
|
|
}
|
|
|
|
CloseHandle( t_hProcessToken ) ;
|
|
t_hProcessToken = NULL ;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( t_pdwProcessIds )
|
|
{
|
|
delete [] t_pdwProcessIds;
|
|
t_pdwProcessIds = NULL ;
|
|
}
|
|
|
|
if ( t_psapi )
|
|
{
|
|
CResourceManager::sm_TheResourceManager.ReleaseResource ( guidPSAPI, t_psapi ) ;
|
|
t_psapi = NULL ;
|
|
}
|
|
}
|
|
catch ( ... )
|
|
{
|
|
if( t_hProcessToken )
|
|
{
|
|
CloseHandle( t_hProcessToken ) ;
|
|
t_hProcessToken = NULL ;
|
|
}
|
|
|
|
if( t_pdwProcessIds )
|
|
{
|
|
delete [] t_pdwProcessIds;
|
|
}
|
|
|
|
if ( t_psapi )
|
|
{
|
|
CResourceManager::sm_TheResourceManager.ReleaseResource ( guidPSAPI, t_psapi ) ;
|
|
}
|
|
throw ;
|
|
}
|
|
|
|
return t_fReturn ;
|
|
}
|
|
|
|
/*=================================================================
|
|
Functions: ReallocProcessIdArray
|
|
|
|
Description: Memory allocation routine for EnumProcess
|
|
|
|
Arguments:
|
|
|
|
Notes:
|
|
Returns:
|
|
Inputs:
|
|
Outputs:
|
|
Caveats:
|
|
Raid:
|
|
History: a-peterc 21-May-1999 Created
|
|
=================================================================*/
|
|
BOOL CImpersonateConnectedUser::ReallocProcessIdArray( PDWORD& pdwProcessIds, DWORD& dwArraySize )
|
|
{
|
|
DWORD dwNewArraySize = dwArraySize + ( PROCESSID_ARRAY_BLOCKSIZE * sizeof(DWORD) );
|
|
PDWORD pdwNewArray = new DWORD[dwNewArraySize];
|
|
|
|
// Make sure the allocation succeeded before overwriting any existing values.
|
|
if ( NULL != pdwNewArray )
|
|
{
|
|
if ( NULL != pdwProcessIds )
|
|
{
|
|
delete [] pdwProcessIds;
|
|
}
|
|
|
|
pdwProcessIds = pdwNewArray;
|
|
dwArraySize = dwNewArraySize;
|
|
}
|
|
else
|
|
{
|
|
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
|
|
}
|
|
|
|
return ( NULL != pdwNewArray );
|
|
}
|
|
|
|
//
|
|
void CImpersonateConnectedUser::RecacheHive()
|
|
{
|
|
// load the users hive
|
|
if( m_fRecacheHive )
|
|
{
|
|
RegCloseKey( HKEY_CURRENT_USER ) ;
|
|
RegEnumKey( HKEY_CURRENT_USER, 0, NULL, 0 ) ;
|
|
}
|
|
}
|
|
|
|
void CImpersonateConnectedUser::FlushCachedHive()
|
|
{
|
|
// load the users hive
|
|
if( m_fRecacheHive )
|
|
{
|
|
RegCloseKey( HKEY_CURRENT_USER ) ;
|
|
}
|
|
}
|
|
|
|
#endif
|