You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
974 lines
26 KiB
974 lines
26 KiB
//=================================================================
|
|
//
|
|
// ImpLogonUser.CPP -- Class to perform impersonation of logged on user.
|
|
//
|
|
// Copyright (c) 1997-2002 Microsoft Corporation, All Rights Reserved
|
|
//
|
|
// Revisions: 09/09/97 a-sanjes Created
|
|
//
|
|
//=================================================================
|
|
//#define _WIN32_DCOM // For CoImpersonateUser and CoRevertToSelf
|
|
//#include <objbase.h>
|
|
|
|
#include "precomp.h"
|
|
|
|
#ifdef NTONLY
|
|
#include <tchar.h>
|
|
#include <winerror.h>
|
|
|
|
#include <cominit.h>
|
|
#include <lockwrap.h>
|
|
#include "Sid.h"
|
|
#include "AccessEntry.h" // CAccessEntry class
|
|
#include "AccessEntryList.h"
|
|
#include "DACL.h" // CDACL class
|
|
#include "SACL.h"
|
|
#include "securitydescriptor.h"
|
|
#include "CToken.h"
|
|
#include "SecureKernelObj.h"
|
|
#include "implogonuser.h"
|
|
|
|
#include "cluidhelper.h"
|
|
|
|
static DWORD s_dwProcessID = 0;
|
|
static CCritSec g_csImpersonate;
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// implogonuser.cpp - Class implementation of CImpersonateLoggedOnUser.
|
|
//
|
|
// This class is intended to provide a way for a process to identify the shell
|
|
// process on a Windows NT system, and using the access token of that process
|
|
// to attempt to impersonate the user logged onto the Interactive Desktop of
|
|
// a workstation.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUNCTION : CImpersonateLoggedOnUser::CImpersonateLoggedOnUser
|
|
//
|
|
// DESCRIPTION : Constructor
|
|
//
|
|
// INPUTS : NONE
|
|
//
|
|
// OUTPUTS : none
|
|
//
|
|
// RETURNS : nothing
|
|
//
|
|
// COMMENTS : Constructs empty instance to prepare for impersonation of user.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
CImpersonateLoggedOnUser::CImpersonateLoggedOnUser() :
|
|
m_hShellProcess(NULL),
|
|
m_hUserToken(NULL),
|
|
m_fImpersonatingUser(FALSE) ,
|
|
m_hThreadToken ( INVALID_HANDLE_VALUE )
|
|
{
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUNCTION : CImpersonateLoggedOnUser::~CImpersonateLoggedOnUser
|
|
//
|
|
// DESCRIPTION : Destructor
|
|
//
|
|
// INPUTS : none
|
|
//
|
|
// OUTPUTS : none
|
|
//
|
|
// RETURNS : nothing
|
|
//
|
|
// COMMENTS : Class destructor
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
CImpersonateLoggedOnUser::~CImpersonateLoggedOnUser( void )
|
|
{
|
|
// Stop any current impersonation
|
|
End();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUNCTION : CImpersonateLoggedOnUser::Begin
|
|
//
|
|
// DESCRIPTION : Attempts to begin impersonation of user.
|
|
//
|
|
// INPUTS : none
|
|
//
|
|
// OUTPUTS : none
|
|
//
|
|
// RETURNS : BOOL TRUE/FALSE - Success/Failure
|
|
//
|
|
// COMMENTS : Uses helper functions to try to impersonate the
|
|
// currently logged on user. The process must have
|
|
// the proper level of access to perform the operation.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL CImpersonateLoggedOnUser::Begin( void )
|
|
{
|
|
BOOL fReturn = FALSE;
|
|
TCHAR szShellProcessName[256];
|
|
LogMessage(_T("CImpersonateLoggedOnUser::Begin"));
|
|
|
|
// Only continue if we are not already impersonating a user
|
|
if (!m_fImpersonatingUser )
|
|
{
|
|
//Store the current thread token, assuming that the thread is impersonating somebody (DCOM client)
|
|
if ( !OpenThreadToken ( GetCurrentThread(), TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE, TRUE, &m_hThreadToken ) )
|
|
{
|
|
m_hThreadToken = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
// We will need a copy of PSAPI.DLL and a bunch of entry point
|
|
// addresses before we can continue, so let our base class take
|
|
// care of this.
|
|
|
|
// We need a handle for the Shell Process in order to
|
|
// successfully impersonate the user.
|
|
if ( NULL == m_hShellProcess )
|
|
{
|
|
if ( LoadShellName( szShellProcessName, sizeof(szShellProcessName) ) )
|
|
FindShellProcess( szShellProcessName);
|
|
else
|
|
LogErrorMessage(_T("LoadShellName failed"));
|
|
}
|
|
|
|
if ( NULL != m_hShellProcess )
|
|
{
|
|
fReturn = ImpersonateUser();
|
|
}
|
|
else
|
|
{
|
|
// We didn't find the Shell Process Name that we extracted from the
|
|
// registry. We saw this happening on Alphas that seem to get "fx32strt.exe"
|
|
// dumped in the shell. In these cases, it seems to cause explorer to run.
|
|
// So with that in mind, if we drop down in this branch of code, we're going
|
|
// to retry the locate shell process operation using Explorer.Exe.
|
|
|
|
if ( IsErrorLoggingEnabled() )
|
|
{
|
|
CHString sTemp;
|
|
sTemp.Format(_T("Shell Name %s in Registry not found in process list."), szShellProcessName);
|
|
LogErrorMessage(sTemp);
|
|
}
|
|
|
|
FindShellProcess( IDS_WINNT_SHELLNAME_EXPLORER ) ;
|
|
|
|
// m_hShellProcess will be non-NULL if and only if we got one.
|
|
if ( NULL != m_hShellProcess )
|
|
{
|
|
fReturn = ImpersonateUser();
|
|
}
|
|
else
|
|
{
|
|
LogErrorMessage(_T("Unable to locate Shell Process, Impersonation failed."));
|
|
SetLastError(0);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LogMessage(_T("CImpersonateLoggedOnUser::Begin - Already impersonated"));
|
|
fReturn = TRUE; // Already initialized
|
|
}
|
|
|
|
// We don't yet have a way to know whether explorer is really alive
|
|
// because we're impersonating someone and I can't find a way to
|
|
// revert back to LocalSystem. So, for now just set it to 0.
|
|
SetLastError(0);
|
|
|
|
return fReturn;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUNCTION : CImpersonateLoggedOnUser::End
|
|
//
|
|
// DESCRIPTION : Ends impersonation of logged on user
|
|
//
|
|
// INPUTS : none
|
|
//
|
|
// OUTPUTS : none
|
|
//
|
|
// RETURNS : BOOL TRUE/FALSE - Success/Failure
|
|
//
|
|
// COMMENTS : Ends impersonation of logged on user. Clears all elements
|
|
// of class as a byproduct.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL CImpersonateLoggedOnUser::End( void )
|
|
{
|
|
BOOL fReturn = FALSE;
|
|
|
|
// Only initiate a Revert if we are impersonating the user.
|
|
|
|
if ( m_fImpersonatingUser )
|
|
{
|
|
LogMessage(_T("CImpersonateLoggedOnUser::End"));
|
|
fReturn = Revert();
|
|
}
|
|
else
|
|
{
|
|
fReturn = TRUE;
|
|
}
|
|
|
|
// Clear the handles out
|
|
if ( NULL != m_hUserToken )
|
|
{
|
|
CloseHandle( m_hUserToken );
|
|
m_hUserToken = NULL;
|
|
}
|
|
|
|
if ( NULL != m_hShellProcess )
|
|
{
|
|
CloseHandle( m_hShellProcess );
|
|
m_hShellProcess = NULL;
|
|
}
|
|
if ( m_hThreadToken != INVALID_HANDLE_VALUE )
|
|
{
|
|
CloseHandle( m_hThreadToken );
|
|
m_hThreadToken = INVALID_HANDLE_VALUE ;
|
|
}
|
|
return fReturn;
|
|
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUNCTION : CImpersonateLoggedOnUser::LoadShellName
|
|
//
|
|
// DESCRIPTION : Loads Windows NT Shell name from registry
|
|
//
|
|
// INPUTS : DWORD cbShellNameBuffer - Shell Name Buffer Size (in bytes)
|
|
//
|
|
// OUTPUTS : LPTSTR pszShellName - Buffer to contain shell name.
|
|
//
|
|
// RETURNS : BOOL TRUE/FALSE - Success/Failure
|
|
//
|
|
// COMMENTS : Jumps into Windows Registry and attempts to determine the
|
|
// NT Shell Name.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL CImpersonateLoggedOnUser::LoadShellName( LPTSTR pszShellName, DWORD cbShellNameBuffer )
|
|
{
|
|
BOOL fReturn = FALSE;
|
|
LONG lErrReturn = ERROR_SUCCESS;
|
|
|
|
// Only continue if we have a buffer to work with first
|
|
|
|
if ( NULL != pszShellName )
|
|
{
|
|
HKEY hReg = NULL;
|
|
|
|
// Open the key in HKEY_LOCAL_MACHINE, if that succeeds, get the
|
|
// value associated with "Shell".
|
|
if ( ( lErrReturn = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
WINNT_WINLOGON_KEY,
|
|
0,
|
|
KEY_READ,
|
|
&hReg ) ) == ERROR_SUCCESS )
|
|
{
|
|
try
|
|
{
|
|
|
|
DWORD dwType = REG_SZ;
|
|
|
|
if ( ( lErrReturn = RegQueryValueEx( hReg,
|
|
WINNT_SHELL_VALUE,
|
|
0,
|
|
&dwType,
|
|
(LPBYTE) pszShellName,
|
|
&cbShellNameBuffer ) ) == ERROR_SUCCESS )
|
|
{
|
|
fReturn = TRUE;
|
|
}
|
|
else
|
|
{
|
|
LogErrorMessage(_T("RegQueryValueEx FAILED"));
|
|
}
|
|
}
|
|
catch ( ... )
|
|
{
|
|
RegCloseKey( hReg );
|
|
throw ;
|
|
}
|
|
|
|
RegCloseKey( hReg );
|
|
|
|
} // RegOpenKeyEx
|
|
else
|
|
{
|
|
LogErrorMessage(_T("RegOpenKeyEx FAILED"));
|
|
}
|
|
|
|
} // NULL != pszShellName
|
|
|
|
return fReturn;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUNCTION : CImpersonateLoggedOnUser::FindShellProcess
|
|
//
|
|
// DESCRIPTION : Enumerates the processes to locate the Shell Process.
|
|
//
|
|
// INPUTS : LPCTSTR pszShellName - Name of the process to locate.
|
|
//
|
|
// OUTPUTS : None.
|
|
//
|
|
// RETURNS : BOOL TRUE/FALSE - Success/Failure
|
|
//
|
|
// COMMENTS : Enumerates the processes on the local system using PSAPI.DLL
|
|
// functions, attempting to locate the one that corresponds to
|
|
// the WINNT Shell passed into this function.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL CImpersonateLoggedOnUser::FindShellProcess( LPCTSTR pszShellName )
|
|
{
|
|
BOOL fReturn = FALSE;
|
|
HANDLE hProcess = NULL;
|
|
HMODULE *phModules = NULL;
|
|
DWORD dwModuleArraySize = 0;
|
|
DWORD* pdwProcessIds = NULL;
|
|
|
|
if ( NULL != pszShellName )
|
|
{
|
|
CPSAPI *t_psapi = (CPSAPI*) CResourceManager::sm_TheResourceManager.GetResource ( guidPSAPI, NULL ) ;
|
|
if ( t_psapi )
|
|
{
|
|
try
|
|
{
|
|
CLuidHelper luid ;
|
|
LUID processLUID ;
|
|
|
|
// This locks access to the s_dwProcessID value. WATCH THE SCOPING HERE!
|
|
CLockWrapper t_lockImp(g_csImpersonate);
|
|
|
|
// First check to see if we have a cached value. If so, check to see if it's still valid.
|
|
if (s_dwProcessID != 0)
|
|
{
|
|
if ( ( hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
|
|
FALSE,
|
|
s_dwProcessID ) )
|
|
!= NULL )
|
|
{
|
|
try
|
|
{
|
|
// Now search the process modules for a match to the supplied
|
|
// shell name.
|
|
|
|
fReturn = FindShellModuleInProcess( pszShellName, hProcess, phModules, dwModuleArraySize, t_psapi );
|
|
|
|
if ( TRUE == fReturn )
|
|
{
|
|
if ( STATUS_SUCCESS == luid.GetLUIDFromProcess ( hProcess, &processLUID ) )
|
|
{
|
|
if ( ! luid.IsInteractiveSession ( &processLUID ) )
|
|
{
|
|
fReturn = FALSE ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fReturn = FALSE ;
|
|
}
|
|
}
|
|
}
|
|
catch ( ... )
|
|
{
|
|
CloseHandle (hProcess);
|
|
throw ;
|
|
}
|
|
|
|
// Close the process handle if it's not the shell (in which
|
|
// case we'll save the value and close it as part of the
|
|
// Clear() function.
|
|
|
|
if ( !fReturn )
|
|
{
|
|
CloseHandle( hProcess );
|
|
hProcess = NULL;
|
|
|
|
// Not valid anymore
|
|
s_dwProcessID = 0;
|
|
}
|
|
else
|
|
{
|
|
m_hShellProcess = hProcess;
|
|
LogMessage(L"Using cached handle for impersonation");
|
|
|
|
hProcess = NULL;
|
|
}
|
|
|
|
} // if OpenProcess
|
|
else
|
|
{
|
|
// We didn't open the process, so we need to set the value to zero so that
|
|
// we will look for a new process below.
|
|
s_dwProcessID = 0;
|
|
}
|
|
}
|
|
|
|
// Did we find a cached value?
|
|
if (s_dwProcessID == 0)
|
|
{
|
|
// Nope. Scan all processes to see if we can find the explorer
|
|
|
|
DWORD dwProcessIdArraySize = 0,
|
|
dwNumProcesses = 0,
|
|
cbDataReturned = 0;
|
|
BOOL fEnumSucceeded = FALSE;
|
|
|
|
// Perform initial allocations of our arrays. Since
|
|
// pointers and values are 0, this will just fill out
|
|
// said values.
|
|
|
|
do
|
|
{
|
|
ReallocProcessIdArray( pdwProcessIds, dwProcessIdArraySize );
|
|
|
|
fEnumSucceeded = t_psapi->EnumProcesses( pdwProcessIds, dwProcessIdArraySize, &cbDataReturned );
|
|
|
|
} while ( (dwProcessIdArraySize == cbDataReturned) && fEnumSucceeded);
|
|
|
|
// Only walk the array if we sucessfully populated it
|
|
if ( fEnumSucceeded )
|
|
{
|
|
// Count of Bytes returned / sizeof(DWORD) tells us how many
|
|
// processes are out in the world.
|
|
|
|
dwNumProcesses = cbDataReturned / sizeof(DWORD);
|
|
|
|
DWORD dwId = 0;
|
|
|
|
// Enum processes until we obtain a shell process or run out
|
|
// of processes to query.
|
|
|
|
while ( dwId < dwNumProcesses && !fReturn )
|
|
{
|
|
if ( ( hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
|
|
FALSE,
|
|
pdwProcessIds[dwId] ) )
|
|
!= NULL )
|
|
{
|
|
try
|
|
{
|
|
// Now search the process modules for a match to the supplied
|
|
// shell name.
|
|
|
|
fReturn = FindShellModuleInProcess( pszShellName, hProcess, phModules, dwModuleArraySize, t_psapi );
|
|
|
|
if ( TRUE == fReturn )
|
|
{
|
|
if ( STATUS_SUCCESS == luid.GetLUIDFromProcess ( hProcess, &processLUID ) )
|
|
{
|
|
if ( ! luid.IsInteractiveSession ( &processLUID ) )
|
|
{
|
|
fReturn = FALSE ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fReturn = FALSE ;
|
|
}
|
|
}
|
|
}
|
|
catch ( ... )
|
|
{
|
|
CloseHandle (hProcess);
|
|
throw ;
|
|
}
|
|
|
|
// Close the process handle if it's not the shell (in which
|
|
// case we'll save the value and close it as part of the
|
|
// Clear() function.
|
|
|
|
if ( !fReturn )
|
|
{
|
|
CloseHandle( hProcess );
|
|
hProcess = NULL;
|
|
}
|
|
else
|
|
{
|
|
m_hShellProcess = hProcess;
|
|
s_dwProcessID = pdwProcessIds[dwId];
|
|
hProcess = NULL;
|
|
}
|
|
|
|
} // if OpenProcess
|
|
|
|
// Increment the Id counter
|
|
|
|
++dwId;
|
|
|
|
} // While OpenProcesses
|
|
|
|
} // If !fRetryEnumProcesses
|
|
}
|
|
}
|
|
catch ( ... )
|
|
{
|
|
if (phModules)
|
|
{
|
|
delete [] phModules;
|
|
}
|
|
|
|
if (pdwProcessIds)
|
|
{
|
|
delete [] pdwProcessIds;
|
|
}
|
|
|
|
if ( t_psapi )
|
|
{
|
|
CResourceManager::sm_TheResourceManager.ReleaseResource ( guidPSAPI, t_psapi ) ;
|
|
t_psapi = NULL ;
|
|
}
|
|
throw ;
|
|
}
|
|
}
|
|
|
|
if (pdwProcessIds)
|
|
{
|
|
delete [] pdwProcessIds;
|
|
}
|
|
|
|
if (phModules)
|
|
{
|
|
delete [] phModules;
|
|
}
|
|
|
|
if ( t_psapi )
|
|
{
|
|
CResourceManager::sm_TheResourceManager.ReleaseResource ( guidPSAPI, t_psapi ) ;
|
|
// t_psapi = NULL ;
|
|
}
|
|
}
|
|
|
|
return fReturn;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUNCTION : CImpersonateLoggedOnUser::FindShellModuleInProcess
|
|
//
|
|
// DESCRIPTION : Enumerates the modules in a process to find our
|
|
// shell.
|
|
//
|
|
// INPUTS : LPCTSTR pszShellName - Name of the process to locate.
|
|
// HANDLE hProcess - Process we are enumerating modules in.
|
|
//
|
|
// OUTPUTS : HMODULE*& phModules - Array of module handle pointers.
|
|
// DWORD& dwModuleArraySize - Size of Module Array (in bytes)
|
|
//
|
|
// RETURNS : BOOL TRUE/FALSE - Success/Failure
|
|
//
|
|
// COMMENTS : Enumerates the modules specified by a process identifier and
|
|
// attemptsto locate the one that corresponds to the WINNT Shell
|
|
// passed into this function.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL CImpersonateLoggedOnUser::FindShellModuleInProcess( LPCTSTR pszShellName, HANDLE hProcess, HMODULE*& phModules, DWORD& dwModuleArraySize, CPSAPI *a_psapi )
|
|
{
|
|
BOOL fReturn = FALSE,
|
|
fRetryEnumModules = FALSE;
|
|
DWORD cbDataReturned = 0;
|
|
|
|
TCHAR szModuleName[MAX_PATH];
|
|
|
|
if (dwModuleArraySize == 0)
|
|
{
|
|
ReallocModuleHandleArray( phModules, dwModuleArraySize );
|
|
}
|
|
|
|
do
|
|
{
|
|
// Get a list of the process HMODULEs and for each HMODULE, get
|
|
// the base file name.
|
|
|
|
if ( a_psapi->EnumProcessModules( hProcess, phModules, dwModuleArraySize, &cbDataReturned ) )
|
|
{
|
|
|
|
// Because m_pfnEnumProcessModules will NOT fail if there are more process
|
|
// modules 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 ( dwModuleArraySize == cbDataReturned )
|
|
{
|
|
fRetryEnumModules = ReallocModuleHandleArray( phModules, dwModuleArraySize );
|
|
}
|
|
else
|
|
{
|
|
fRetryEnumModules = FALSE;
|
|
}
|
|
|
|
// Only walk the array if we don't need to retry the enum
|
|
if ( !fRetryEnumModules )
|
|
{
|
|
DWORD dwModuleCtr = 0;
|
|
|
|
// Executable name always returned in entry 0
|
|
|
|
if ( a_psapi->GetModuleBaseName( hProcess, phModules[dwModuleCtr], szModuleName, sizeof(szModuleName) ) )
|
|
{
|
|
fReturn = ( lstrcmpi( pszShellName, szModuleName ) == 0 );
|
|
}
|
|
|
|
} // If !fRetryEnumModules
|
|
|
|
} // if EnumProcessModules
|
|
|
|
}
|
|
while ( fRetryEnumModules );
|
|
|
|
return fReturn;
|
|
}
|
|
|
|
DWORD CImpersonateLoggedOnUser::AdjustSecurityDescriptorOfImpersonatedToken(
|
|
CSid& csidSidOfCurrentProcess )
|
|
{
|
|
DWORD dwRet = E_FAIL;
|
|
|
|
// Get the thread token...
|
|
CThreadToken ctt;
|
|
if ( ctt.IsValidToken () )
|
|
{
|
|
// Obtain access to its security descriptor...
|
|
CSecureKernelObj sko(ctt.GetTokenHandle(), FALSE);
|
|
// Modify the security descriptor...
|
|
if(sko.AddDACLEntry(
|
|
csidSidOfCurrentProcess,
|
|
ENUM_ACCESS_ALLOWED_ACE_TYPE,
|
|
TOKEN_ALL_ACCESS,
|
|
0,
|
|
NULL,
|
|
NULL))
|
|
{
|
|
dwRet = sko.ApplySecurity(
|
|
DACL_SECURITY_INFORMATION);
|
|
}
|
|
}
|
|
|
|
return dwRet ;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUNCTION : CImpersonateLoggedOnUser::ImpersonateUser
|
|
//
|
|
// DESCRIPTION : Attempts to impersonate the user.
|
|
//
|
|
// INPUTS : None.
|
|
//
|
|
// OUTPUTS : None.
|
|
//
|
|
// RETURNS : BOOL TRUE/FALSE - Success/Failure
|
|
//
|
|
// COMMENTS : Opens the security token of the Shell Process and
|
|
// uses it to try to impersonate the user.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL CImpersonateLoggedOnUser::ImpersonateUser( void )
|
|
{
|
|
BOOL fRet = FALSE;
|
|
// Make sure we have a shell process
|
|
if (m_hShellProcess)
|
|
{
|
|
CSid csidCurrentProcess;
|
|
if(GetCurrentProcessSid(csidCurrentProcess))
|
|
{
|
|
// Get the Process User token if we don't have one (token of the explorer process).
|
|
//Removed the TOKEN_ALL_ACCESS desired access mask to this call 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. So open the token with 'desired access' sufficient
|
|
//enough to use it for impersonation only.
|
|
if (m_hUserToken ||
|
|
OpenProcessToken(m_hShellProcess, TOKEN_READ | TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE, &m_hUserToken))
|
|
{
|
|
// Now we should have what we need. Impersonate the user.
|
|
|
|
HANDLE hCurThread = ::GetCurrentThread () ;
|
|
|
|
CProcessToken cpt ( m_hUserToken );
|
|
if ( cpt.IsValidToken () )
|
|
{
|
|
TOKEN_TYPE type;
|
|
if ( cpt.GetTokenType ( type ) )
|
|
{
|
|
if ( TokenPrimary == type )
|
|
{
|
|
CToken ct;
|
|
if ( ct.Duplicate ( cpt, FALSE ) )
|
|
{
|
|
if( ::SetThreadToken ( &hCurThread, ct.GetTokenHandle () ) )
|
|
{
|
|
m_fImpersonatingUser = TRUE ;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( ::SetThreadToken ( &hCurThread, cpt.GetTokenHandle () ) )
|
|
{
|
|
m_fImpersonatingUser = TRUE ;
|
|
}
|
|
}
|
|
|
|
if ( m_fImpersonatingUser )
|
|
{
|
|
if(AdjustSecurityDescriptorOfImpersonatedToken ( csidCurrentProcess ) == ERROR_SUCCESS)
|
|
{
|
|
fRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
Revert () ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return (m_fImpersonatingUser = fRet);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUNCTION : CImpersonateLoggedOnUser::Revert
|
|
//
|
|
// DESCRIPTION : Attempts to revert to self.
|
|
//
|
|
// INPUTS : None.
|
|
//
|
|
// OUTPUTS : None.
|
|
//
|
|
// RETURNS : BOOL TRUE/FALSE - Success/Failure
|
|
//
|
|
// COMMENTS : If we're impersonating a user, we now revert to
|
|
// ourselves.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL CImpersonateLoggedOnUser::Revert( void )
|
|
{
|
|
HRESULT hRes = WBEM_E_FAILED ;
|
|
BOOL bRet = FALSE ;
|
|
// See if we're currently impersonating prior to reverting.
|
|
if (m_fImpersonatingUser)
|
|
{
|
|
// Now get back to to the previous impersonation or impersonate the DCOM client.
|
|
if ( m_hThreadToken != INVALID_HANDLE_VALUE )
|
|
{
|
|
HANDLE hCurThread = ::GetCurrentThread () ;
|
|
|
|
CThreadToken cpt ( m_hThreadToken );
|
|
if ( cpt.IsValidToken () )
|
|
{
|
|
TOKEN_TYPE type;
|
|
if ( cpt.GetTokenType ( type ) )
|
|
{
|
|
if ( TokenPrimary == type )
|
|
{
|
|
CToken ct;
|
|
if ( ct.Duplicate ( cpt, FALSE ) )
|
|
{
|
|
bRet = ::SetThreadToken ( &hCurThread, ct.GetTokenHandle () );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bRet = ::SetThreadToken ( &hCurThread, cpt.GetTokenHandle () ) ;
|
|
}
|
|
|
|
if (!bRet)
|
|
{
|
|
throw CFramework_Exception(L"SetThreadToken failed", GetLastError());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hRes = WbemCoImpersonateClient();
|
|
|
|
if (FAILED(hRes))
|
|
{
|
|
throw CFramework_Exception(L"WbemCoImpersonateClient failed", hRes);
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hRes) || hRes == E_NOTIMPL || bRet )
|
|
{
|
|
m_fImpersonatingUser = FALSE;
|
|
}
|
|
}
|
|
return ( !m_fImpersonatingUser );
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUNCTION : CImpersonateLoggedOnUser::ReallocProcessIdArray
|
|
//
|
|
// DESCRIPTION : Helper function to alloc a process id array.
|
|
//
|
|
// INPUTS : None.
|
|
//
|
|
// OUTPUTS : PDWORD& pdwProcessIds - Process Id Array pointer
|
|
// DWORD& dwArraySize - Size of array in bytes
|
|
//
|
|
// RETURNS : BOOL TRUE/FALSE - Success/Failure
|
|
//
|
|
// COMMENTS : Call when we need to realloc our process id array.
|
|
// This will grow the array by a fixed size, but not
|
|
// preserve values.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL CImpersonateLoggedOnUser::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 );
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUNCTION : CImpersonateLoggedOnUser::ReallocModuleHandleArray
|
|
//
|
|
// DESCRIPTION : Helper function to alloc a module handle array.
|
|
//
|
|
// INPUTS : None.
|
|
//
|
|
// OUTPUTS : HMODULE*& phModules - Module Handle Array pointer
|
|
// DWORD& dwArraySize - size of array in bytes
|
|
//
|
|
// RETURNS : BOOL TRUE/FALSE - Success/Failure
|
|
//
|
|
// COMMENTS : Call when we need to realloc our module handle array.
|
|
// This will grow the array by a fixed size, but not
|
|
// preserve values.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL CImpersonateLoggedOnUser::ReallocModuleHandleArray( HMODULE*& phModules, DWORD& dwArraySize )
|
|
{
|
|
DWORD dwNewArraySize = dwArraySize + ( HMODULE_ARRAY_BLOCKSIZE * sizeof(HMODULE) );
|
|
HMODULE* phNewArray = new HMODULE[dwNewArraySize];
|
|
|
|
// Make sure the allocation succeeded before overwriting any existing values.
|
|
|
|
if ( NULL != phNewArray )
|
|
{
|
|
if ( NULL != phModules )
|
|
{
|
|
delete [] phModules;
|
|
}
|
|
|
|
phModules = phNewArray;
|
|
dwArraySize = dwNewArraySize;
|
|
}
|
|
else
|
|
{
|
|
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
|
|
}
|
|
|
|
|
|
return ( NULL != phNewArray );
|
|
}
|
|
|
|
bool CImpersonateLoggedOnUser::GetCurrentProcessSid(CSid& sidCurrentProcess)
|
|
{
|
|
bool fRet = false;
|
|
|
|
PBYTE pbuff = NULL;
|
|
|
|
// I am going to revert here in order to access the process's
|
|
// sid. This is not privileged information, so this doesn't
|
|
// present a security breach.
|
|
|
|
WbemCoRevertToSelf();
|
|
|
|
try
|
|
{
|
|
CProcessToken cpt(NULL, true, TOKEN_QUERY);
|
|
|
|
DWORD dwLen = 0;
|
|
if(!::GetTokenInformation(
|
|
cpt.GetTokenHandle(), // the PR0CESS token
|
|
TokenUser,
|
|
NULL,
|
|
0L,
|
|
&dwLen) && (::GetLastError() == ERROR_INSUFFICIENT_BUFFER))
|
|
{
|
|
pbuff = new BYTE[dwLen];
|
|
if(pbuff)
|
|
{
|
|
if(::GetTokenInformation(
|
|
cpt.GetTokenHandle(),
|
|
TokenUser,
|
|
pbuff,
|
|
dwLen,
|
|
&dwLen))
|
|
{
|
|
PTOKEN_USER ptu = (PTOKEN_USER)pbuff;
|
|
CSid sidTemp(ptu->User.Sid);
|
|
if(sidTemp.IsOK() &&
|
|
sidTemp.IsValid())
|
|
{
|
|
sidCurrentProcess = sidTemp;
|
|
fRet = true;
|
|
}
|
|
}
|
|
delete pbuff;
|
|
pbuff = NULL;
|
|
}
|
|
}
|
|
}
|
|
catch(...)
|
|
{
|
|
//on our way out not returning anything to user except failure
|
|
//can't do anything on this impersonation failure...
|
|
WbemCoImpersonateClient();
|
|
delete pbuff;
|
|
pbuff = NULL;
|
|
throw;
|
|
}
|
|
|
|
HRESULT hr = WbemCoImpersonateClient() ;
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
throw CFramework_Exception(L"WbemCoImpersonateClient failed", hr);
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
#endif
|