Leaked source code of windows server 2003
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

  1. //=================================================================
  2. //
  3. // ImpLogonUser.CPP -- Class to perform impersonation of logged on user.
  4. //
  5. // Copyright (c) 1997-2002 Microsoft Corporation, All Rights Reserved
  6. //
  7. // Revisions: 09/09/97 a-sanjes Created
  8. //
  9. //=================================================================
  10. //#define _WIN32_DCOM // For CoImpersonateUser and CoRevertToSelf
  11. //#include <objbase.h>
  12. #include "precomp.h"
  13. #ifdef NTONLY
  14. #include <tchar.h>
  15. #include <winerror.h>
  16. #include <cominit.h>
  17. #include <lockwrap.h>
  18. #include "Sid.h"
  19. #include "AccessEntry.h" // CAccessEntry class
  20. #include "AccessEntryList.h"
  21. #include "DACL.h" // CDACL class
  22. #include "SACL.h"
  23. #include "securitydescriptor.h"
  24. #include "CToken.h"
  25. #include "SecureKernelObj.h"
  26. #include "implogonuser.h"
  27. #include "cluidhelper.h"
  28. static DWORD s_dwProcessID = 0;
  29. static CCritSec g_csImpersonate;
  30. //////////////////////////////////////////////////////////////////////////////
  31. //
  32. // implogonuser.cpp - Class implementation of CImpersonateLoggedOnUser.
  33. //
  34. // This class is intended to provide a way for a process to identify the shell
  35. // process on a Windows NT system, and using the access token of that process
  36. // to attempt to impersonate the user logged onto the Interactive Desktop of
  37. // a workstation.
  38. //
  39. //////////////////////////////////////////////////////////////////////////////
  40. //////////////////////////////////////////////////////////////////////////////
  41. //
  42. // FUNCTION : CImpersonateLoggedOnUser::CImpersonateLoggedOnUser
  43. //
  44. // DESCRIPTION : Constructor
  45. //
  46. // INPUTS : NONE
  47. //
  48. // OUTPUTS : none
  49. //
  50. // RETURNS : nothing
  51. //
  52. // COMMENTS : Constructs empty instance to prepare for impersonation of user.
  53. //
  54. //////////////////////////////////////////////////////////////////////////////
  55. CImpersonateLoggedOnUser::CImpersonateLoggedOnUser() :
  56. m_hShellProcess(NULL),
  57. m_hUserToken(NULL),
  58. m_fImpersonatingUser(FALSE) ,
  59. m_hThreadToken ( INVALID_HANDLE_VALUE )
  60. {
  61. }
  62. //////////////////////////////////////////////////////////////////////////////
  63. //
  64. // FUNCTION : CImpersonateLoggedOnUser::~CImpersonateLoggedOnUser
  65. //
  66. // DESCRIPTION : Destructor
  67. //
  68. // INPUTS : none
  69. //
  70. // OUTPUTS : none
  71. //
  72. // RETURNS : nothing
  73. //
  74. // COMMENTS : Class destructor
  75. //
  76. //////////////////////////////////////////////////////////////////////////////
  77. CImpersonateLoggedOnUser::~CImpersonateLoggedOnUser( void )
  78. {
  79. // Stop any current impersonation
  80. End();
  81. }
  82. //////////////////////////////////////////////////////////////////////////////
  83. //
  84. // FUNCTION : CImpersonateLoggedOnUser::Begin
  85. //
  86. // DESCRIPTION : Attempts to begin impersonation of user.
  87. //
  88. // INPUTS : none
  89. //
  90. // OUTPUTS : none
  91. //
  92. // RETURNS : BOOL TRUE/FALSE - Success/Failure
  93. //
  94. // COMMENTS : Uses helper functions to try to impersonate the
  95. // currently logged on user. The process must have
  96. // the proper level of access to perform the operation.
  97. //
  98. //////////////////////////////////////////////////////////////////////////////
  99. BOOL CImpersonateLoggedOnUser::Begin( void )
  100. {
  101. BOOL fReturn = FALSE;
  102. TCHAR szShellProcessName[256];
  103. LogMessage(_T("CImpersonateLoggedOnUser::Begin"));
  104. // Only continue if we are not already impersonating a user
  105. if (!m_fImpersonatingUser )
  106. {
  107. //Store the current thread token, assuming that the thread is impersonating somebody (DCOM client)
  108. if ( !OpenThreadToken ( GetCurrentThread(), TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE, TRUE, &m_hThreadToken ) )
  109. {
  110. m_hThreadToken = INVALID_HANDLE_VALUE;
  111. }
  112. // We will need a copy of PSAPI.DLL and a bunch of entry point
  113. // addresses before we can continue, so let our base class take
  114. // care of this.
  115. // We need a handle for the Shell Process in order to
  116. // successfully impersonate the user.
  117. if ( NULL == m_hShellProcess )
  118. {
  119. if ( LoadShellName( szShellProcessName, sizeof(szShellProcessName) ) )
  120. FindShellProcess( szShellProcessName);
  121. else
  122. LogErrorMessage(_T("LoadShellName failed"));
  123. }
  124. if ( NULL != m_hShellProcess )
  125. {
  126. fReturn = ImpersonateUser();
  127. }
  128. else
  129. {
  130. // We didn't find the Shell Process Name that we extracted from the
  131. // registry. We saw this happening on Alphas that seem to get "fx32strt.exe"
  132. // dumped in the shell. In these cases, it seems to cause explorer to run.
  133. // So with that in mind, if we drop down in this branch of code, we're going
  134. // to retry the locate shell process operation using Explorer.Exe.
  135. if ( IsErrorLoggingEnabled() )
  136. {
  137. CHString sTemp;
  138. sTemp.Format(_T("Shell Name %s in Registry not found in process list."), szShellProcessName);
  139. LogErrorMessage(sTemp);
  140. }
  141. FindShellProcess( IDS_WINNT_SHELLNAME_EXPLORER ) ;
  142. // m_hShellProcess will be non-NULL if and only if we got one.
  143. if ( NULL != m_hShellProcess )
  144. {
  145. fReturn = ImpersonateUser();
  146. }
  147. else
  148. {
  149. LogErrorMessage(_T("Unable to locate Shell Process, Impersonation failed."));
  150. SetLastError(0);
  151. }
  152. }
  153. }
  154. else
  155. {
  156. LogMessage(_T("CImpersonateLoggedOnUser::Begin - Already impersonated"));
  157. fReturn = TRUE; // Already initialized
  158. }
  159. // We don't yet have a way to know whether explorer is really alive
  160. // because we're impersonating someone and I can't find a way to
  161. // revert back to LocalSystem. So, for now just set it to 0.
  162. SetLastError(0);
  163. return fReturn;
  164. }
  165. //////////////////////////////////////////////////////////////////////////////
  166. //
  167. // FUNCTION : CImpersonateLoggedOnUser::End
  168. //
  169. // DESCRIPTION : Ends impersonation of logged on user
  170. //
  171. // INPUTS : none
  172. //
  173. // OUTPUTS : none
  174. //
  175. // RETURNS : BOOL TRUE/FALSE - Success/Failure
  176. //
  177. // COMMENTS : Ends impersonation of logged on user. Clears all elements
  178. // of class as a byproduct.
  179. //
  180. //////////////////////////////////////////////////////////////////////////////
  181. BOOL CImpersonateLoggedOnUser::End( void )
  182. {
  183. BOOL fReturn = FALSE;
  184. // Only initiate a Revert if we are impersonating the user.
  185. if ( m_fImpersonatingUser )
  186. {
  187. LogMessage(_T("CImpersonateLoggedOnUser::End"));
  188. fReturn = Revert();
  189. }
  190. else
  191. {
  192. fReturn = TRUE;
  193. }
  194. // Clear the handles out
  195. if ( NULL != m_hUserToken )
  196. {
  197. CloseHandle( m_hUserToken );
  198. m_hUserToken = NULL;
  199. }
  200. if ( NULL != m_hShellProcess )
  201. {
  202. CloseHandle( m_hShellProcess );
  203. m_hShellProcess = NULL;
  204. }
  205. if ( m_hThreadToken != INVALID_HANDLE_VALUE )
  206. {
  207. CloseHandle( m_hThreadToken );
  208. m_hThreadToken = INVALID_HANDLE_VALUE ;
  209. }
  210. return fReturn;
  211. }
  212. //////////////////////////////////////////////////////////////////////////////
  213. //
  214. // FUNCTION : CImpersonateLoggedOnUser::LoadShellName
  215. //
  216. // DESCRIPTION : Loads Windows NT Shell name from registry
  217. //
  218. // INPUTS : DWORD cbShellNameBuffer - Shell Name Buffer Size (in bytes)
  219. //
  220. // OUTPUTS : LPTSTR pszShellName - Buffer to contain shell name.
  221. //
  222. // RETURNS : BOOL TRUE/FALSE - Success/Failure
  223. //
  224. // COMMENTS : Jumps into Windows Registry and attempts to determine the
  225. // NT Shell Name.
  226. //
  227. //////////////////////////////////////////////////////////////////////////////
  228. BOOL CImpersonateLoggedOnUser::LoadShellName( LPTSTR pszShellName, DWORD cbShellNameBuffer )
  229. {
  230. BOOL fReturn = FALSE;
  231. LONG lErrReturn = ERROR_SUCCESS;
  232. // Only continue if we have a buffer to work with first
  233. if ( NULL != pszShellName )
  234. {
  235. HKEY hReg = NULL;
  236. // Open the key in HKEY_LOCAL_MACHINE, if that succeeds, get the
  237. // value associated with "Shell".
  238. if ( ( lErrReturn = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  239. WINNT_WINLOGON_KEY,
  240. 0,
  241. KEY_READ,
  242. &hReg ) ) == ERROR_SUCCESS )
  243. {
  244. try
  245. {
  246. DWORD dwType = REG_SZ;
  247. if ( ( lErrReturn = RegQueryValueEx( hReg,
  248. WINNT_SHELL_VALUE,
  249. 0,
  250. &dwType,
  251. (LPBYTE) pszShellName,
  252. &cbShellNameBuffer ) ) == ERROR_SUCCESS )
  253. {
  254. fReturn = TRUE;
  255. }
  256. else
  257. {
  258. LogErrorMessage(_T("RegQueryValueEx FAILED"));
  259. }
  260. }
  261. catch ( ... )
  262. {
  263. RegCloseKey( hReg );
  264. throw ;
  265. }
  266. RegCloseKey( hReg );
  267. } // RegOpenKeyEx
  268. else
  269. {
  270. LogErrorMessage(_T("RegOpenKeyEx FAILED"));
  271. }
  272. } // NULL != pszShellName
  273. return fReturn;
  274. }
  275. //////////////////////////////////////////////////////////////////////////////
  276. //
  277. // FUNCTION : CImpersonateLoggedOnUser::FindShellProcess
  278. //
  279. // DESCRIPTION : Enumerates the processes to locate the Shell Process.
  280. //
  281. // INPUTS : LPCTSTR pszShellName - Name of the process to locate.
  282. //
  283. // OUTPUTS : None.
  284. //
  285. // RETURNS : BOOL TRUE/FALSE - Success/Failure
  286. //
  287. // COMMENTS : Enumerates the processes on the local system using PSAPI.DLL
  288. // functions, attempting to locate the one that corresponds to
  289. // the WINNT Shell passed into this function.
  290. //
  291. //////////////////////////////////////////////////////////////////////////////
  292. BOOL CImpersonateLoggedOnUser::FindShellProcess( LPCTSTR pszShellName )
  293. {
  294. BOOL fReturn = FALSE;
  295. HANDLE hProcess = NULL;
  296. HMODULE *phModules = NULL;
  297. DWORD dwModuleArraySize = 0;
  298. DWORD* pdwProcessIds = NULL;
  299. if ( NULL != pszShellName )
  300. {
  301. CPSAPI *t_psapi = (CPSAPI*) CResourceManager::sm_TheResourceManager.GetResource ( guidPSAPI, NULL ) ;
  302. if ( t_psapi )
  303. {
  304. try
  305. {
  306. CLuidHelper luid ;
  307. LUID processLUID ;
  308. // This locks access to the s_dwProcessID value. WATCH THE SCOPING HERE!
  309. CLockWrapper t_lockImp(g_csImpersonate);
  310. // First check to see if we have a cached value. If so, check to see if it's still valid.
  311. if (s_dwProcessID != 0)
  312. {
  313. if ( ( hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
  314. FALSE,
  315. s_dwProcessID ) )
  316. != NULL )
  317. {
  318. try
  319. {
  320. // Now search the process modules for a match to the supplied
  321. // shell name.
  322. fReturn = FindShellModuleInProcess( pszShellName, hProcess, phModules, dwModuleArraySize, t_psapi );
  323. if ( TRUE == fReturn )
  324. {
  325. if ( STATUS_SUCCESS == luid.GetLUIDFromProcess ( hProcess, &processLUID ) )
  326. {
  327. if ( ! luid.IsInteractiveSession ( &processLUID ) )
  328. {
  329. fReturn = FALSE ;
  330. }
  331. }
  332. else
  333. {
  334. fReturn = FALSE ;
  335. }
  336. }
  337. }
  338. catch ( ... )
  339. {
  340. CloseHandle (hProcess);
  341. throw ;
  342. }
  343. // Close the process handle if it's not the shell (in which
  344. // case we'll save the value and close it as part of the
  345. // Clear() function.
  346. if ( !fReturn )
  347. {
  348. CloseHandle( hProcess );
  349. hProcess = NULL;
  350. // Not valid anymore
  351. s_dwProcessID = 0;
  352. }
  353. else
  354. {
  355. m_hShellProcess = hProcess;
  356. LogMessage(L"Using cached handle for impersonation");
  357. hProcess = NULL;
  358. }
  359. } // if OpenProcess
  360. else
  361. {
  362. // We didn't open the process, so we need to set the value to zero so that
  363. // we will look for a new process below.
  364. s_dwProcessID = 0;
  365. }
  366. }
  367. // Did we find a cached value?
  368. if (s_dwProcessID == 0)
  369. {
  370. // Nope. Scan all processes to see if we can find the explorer
  371. DWORD dwProcessIdArraySize = 0,
  372. dwNumProcesses = 0,
  373. cbDataReturned = 0;
  374. BOOL fEnumSucceeded = FALSE;
  375. // Perform initial allocations of our arrays. Since
  376. // pointers and values are 0, this will just fill out
  377. // said values.
  378. do
  379. {
  380. ReallocProcessIdArray( pdwProcessIds, dwProcessIdArraySize );
  381. fEnumSucceeded = t_psapi->EnumProcesses( pdwProcessIds, dwProcessIdArraySize, &cbDataReturned );
  382. } while ( (dwProcessIdArraySize == cbDataReturned) && fEnumSucceeded);
  383. // Only walk the array if we sucessfully populated it
  384. if ( fEnumSucceeded )
  385. {
  386. // Count of Bytes returned / sizeof(DWORD) tells us how many
  387. // processes are out in the world.
  388. dwNumProcesses = cbDataReturned / sizeof(DWORD);
  389. DWORD dwId = 0;
  390. // Enum processes until we obtain a shell process or run out
  391. // of processes to query.
  392. while ( dwId < dwNumProcesses && !fReturn )
  393. {
  394. if ( ( hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
  395. FALSE,
  396. pdwProcessIds[dwId] ) )
  397. != NULL )
  398. {
  399. try
  400. {
  401. // Now search the process modules for a match to the supplied
  402. // shell name.
  403. fReturn = FindShellModuleInProcess( pszShellName, hProcess, phModules, dwModuleArraySize, t_psapi );
  404. if ( TRUE == fReturn )
  405. {
  406. if ( STATUS_SUCCESS == luid.GetLUIDFromProcess ( hProcess, &processLUID ) )
  407. {
  408. if ( ! luid.IsInteractiveSession ( &processLUID ) )
  409. {
  410. fReturn = FALSE ;
  411. }
  412. }
  413. else
  414. {
  415. fReturn = FALSE ;
  416. }
  417. }
  418. }
  419. catch ( ... )
  420. {
  421. CloseHandle (hProcess);
  422. throw ;
  423. }
  424. // Close the process handle if it's not the shell (in which
  425. // case we'll save the value and close it as part of the
  426. // Clear() function.
  427. if ( !fReturn )
  428. {
  429. CloseHandle( hProcess );
  430. hProcess = NULL;
  431. }
  432. else
  433. {
  434. m_hShellProcess = hProcess;
  435. s_dwProcessID = pdwProcessIds[dwId];
  436. hProcess = NULL;
  437. }
  438. } // if OpenProcess
  439. // Increment the Id counter
  440. ++dwId;
  441. } // While OpenProcesses
  442. } // If !fRetryEnumProcesses
  443. }
  444. }
  445. catch ( ... )
  446. {
  447. if (phModules)
  448. {
  449. delete [] phModules;
  450. }
  451. if (pdwProcessIds)
  452. {
  453. delete [] pdwProcessIds;
  454. }
  455. if ( t_psapi )
  456. {
  457. CResourceManager::sm_TheResourceManager.ReleaseResource ( guidPSAPI, t_psapi ) ;
  458. t_psapi = NULL ;
  459. }
  460. throw ;
  461. }
  462. }
  463. if (pdwProcessIds)
  464. {
  465. delete [] pdwProcessIds;
  466. }
  467. if (phModules)
  468. {
  469. delete [] phModules;
  470. }
  471. if ( t_psapi )
  472. {
  473. CResourceManager::sm_TheResourceManager.ReleaseResource ( guidPSAPI, t_psapi ) ;
  474. // t_psapi = NULL ;
  475. }
  476. }
  477. return fReturn;
  478. }
  479. //////////////////////////////////////////////////////////////////////////////
  480. //
  481. // FUNCTION : CImpersonateLoggedOnUser::FindShellModuleInProcess
  482. //
  483. // DESCRIPTION : Enumerates the modules in a process to find our
  484. // shell.
  485. //
  486. // INPUTS : LPCTSTR pszShellName - Name of the process to locate.
  487. // HANDLE hProcess - Process we are enumerating modules in.
  488. //
  489. // OUTPUTS : HMODULE*& phModules - Array of module handle pointers.
  490. // DWORD& dwModuleArraySize - Size of Module Array (in bytes)
  491. //
  492. // RETURNS : BOOL TRUE/FALSE - Success/Failure
  493. //
  494. // COMMENTS : Enumerates the modules specified by a process identifier and
  495. // attemptsto locate the one that corresponds to the WINNT Shell
  496. // passed into this function.
  497. //
  498. //////////////////////////////////////////////////////////////////////////////
  499. BOOL CImpersonateLoggedOnUser::FindShellModuleInProcess( LPCTSTR pszShellName, HANDLE hProcess, HMODULE*& phModules, DWORD& dwModuleArraySize, CPSAPI *a_psapi )
  500. {
  501. BOOL fReturn = FALSE,
  502. fRetryEnumModules = FALSE;
  503. DWORD cbDataReturned = 0;
  504. TCHAR szModuleName[MAX_PATH];
  505. if (dwModuleArraySize == 0)
  506. {
  507. ReallocModuleHandleArray( phModules, dwModuleArraySize );
  508. }
  509. do
  510. {
  511. // Get a list of the process HMODULEs and for each HMODULE, get
  512. // the base file name.
  513. if ( a_psapi->EnumProcessModules( hProcess, phModules, dwModuleArraySize, &cbDataReturned ) )
  514. {
  515. // Because m_pfnEnumProcessModules will NOT fail if there are more process
  516. // modules than bytes available in the array, if the amount returned is
  517. // the same size as the array, realloc the array and retry the Enum.
  518. if ( dwModuleArraySize == cbDataReturned )
  519. {
  520. fRetryEnumModules = ReallocModuleHandleArray( phModules, dwModuleArraySize );
  521. }
  522. else
  523. {
  524. fRetryEnumModules = FALSE;
  525. }
  526. // Only walk the array if we don't need to retry the enum
  527. if ( !fRetryEnumModules )
  528. {
  529. DWORD dwModuleCtr = 0;
  530. // Executable name always returned in entry 0
  531. if ( a_psapi->GetModuleBaseName( hProcess, phModules[dwModuleCtr], szModuleName, sizeof(szModuleName) ) )
  532. {
  533. fReturn = ( lstrcmpi( pszShellName, szModuleName ) == 0 );
  534. }
  535. } // If !fRetryEnumModules
  536. } // if EnumProcessModules
  537. }
  538. while ( fRetryEnumModules );
  539. return fReturn;
  540. }
  541. DWORD CImpersonateLoggedOnUser::AdjustSecurityDescriptorOfImpersonatedToken(
  542. CSid& csidSidOfCurrentProcess )
  543. {
  544. DWORD dwRet = E_FAIL;
  545. // Get the thread token...
  546. CThreadToken ctt;
  547. if ( ctt.IsValidToken () )
  548. {
  549. // Obtain access to its security descriptor...
  550. CSecureKernelObj sko(ctt.GetTokenHandle(), FALSE);
  551. // Modify the security descriptor...
  552. if(sko.AddDACLEntry(
  553. csidSidOfCurrentProcess,
  554. ENUM_ACCESS_ALLOWED_ACE_TYPE,
  555. TOKEN_ALL_ACCESS,
  556. 0,
  557. NULL,
  558. NULL))
  559. {
  560. dwRet = sko.ApplySecurity(
  561. DACL_SECURITY_INFORMATION);
  562. }
  563. }
  564. return dwRet ;
  565. }
  566. //////////////////////////////////////////////////////////////////////////////
  567. //
  568. // FUNCTION : CImpersonateLoggedOnUser::ImpersonateUser
  569. //
  570. // DESCRIPTION : Attempts to impersonate the user.
  571. //
  572. // INPUTS : None.
  573. //
  574. // OUTPUTS : None.
  575. //
  576. // RETURNS : BOOL TRUE/FALSE - Success/Failure
  577. //
  578. // COMMENTS : Opens the security token of the Shell Process and
  579. // uses it to try to impersonate the user.
  580. //
  581. //////////////////////////////////////////////////////////////////////////////
  582. BOOL CImpersonateLoggedOnUser::ImpersonateUser( void )
  583. {
  584. BOOL fRet = FALSE;
  585. // Make sure we have a shell process
  586. if (m_hShellProcess)
  587. {
  588. CSid csidCurrentProcess;
  589. if(GetCurrentProcessSid(csidCurrentProcess))
  590. {
  591. // Get the Process User token if we don't have one (token of the explorer process).
  592. //Removed the TOKEN_ALL_ACCESS desired access mask to this call as Winmgmt(Local system) can't open the token of the
  593. //shell process (with all access rights)if the logged-in user is an Admin. So open the token with 'desired access' sufficient
  594. //enough to use it for impersonation only.
  595. if (m_hUserToken ||
  596. OpenProcessToken(m_hShellProcess, TOKEN_READ | TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE, &m_hUserToken))
  597. {
  598. // Now we should have what we need. Impersonate the user.
  599. HANDLE hCurThread = ::GetCurrentThread () ;
  600. CProcessToken cpt ( m_hUserToken );
  601. if ( cpt.IsValidToken () )
  602. {
  603. TOKEN_TYPE type;
  604. if ( cpt.GetTokenType ( type ) )
  605. {
  606. if ( TokenPrimary == type )
  607. {
  608. CToken ct;
  609. if ( ct.Duplicate ( cpt, FALSE ) )
  610. {
  611. if( ::SetThreadToken ( &hCurThread, ct.GetTokenHandle () ) )
  612. {
  613. m_fImpersonatingUser = TRUE ;
  614. }
  615. }
  616. }
  617. else
  618. {
  619. if( ::SetThreadToken ( &hCurThread, cpt.GetTokenHandle () ) )
  620. {
  621. m_fImpersonatingUser = TRUE ;
  622. }
  623. }
  624. if ( m_fImpersonatingUser )
  625. {
  626. if(AdjustSecurityDescriptorOfImpersonatedToken ( csidCurrentProcess ) == ERROR_SUCCESS)
  627. {
  628. fRet = TRUE;
  629. }
  630. else
  631. {
  632. Revert () ;
  633. }
  634. }
  635. }
  636. }
  637. }
  638. }
  639. }
  640. return (m_fImpersonatingUser = fRet);
  641. }
  642. //////////////////////////////////////////////////////////////////////////////
  643. //
  644. // FUNCTION : CImpersonateLoggedOnUser::Revert
  645. //
  646. // DESCRIPTION : Attempts to revert to self.
  647. //
  648. // INPUTS : None.
  649. //
  650. // OUTPUTS : None.
  651. //
  652. // RETURNS : BOOL TRUE/FALSE - Success/Failure
  653. //
  654. // COMMENTS : If we're impersonating a user, we now revert to
  655. // ourselves.
  656. //
  657. //////////////////////////////////////////////////////////////////////////////
  658. BOOL CImpersonateLoggedOnUser::Revert( void )
  659. {
  660. HRESULT hRes = WBEM_E_FAILED ;
  661. BOOL bRet = FALSE ;
  662. // See if we're currently impersonating prior to reverting.
  663. if (m_fImpersonatingUser)
  664. {
  665. // Now get back to to the previous impersonation or impersonate the DCOM client.
  666. if ( m_hThreadToken != INVALID_HANDLE_VALUE )
  667. {
  668. HANDLE hCurThread = ::GetCurrentThread () ;
  669. CThreadToken cpt ( m_hThreadToken );
  670. if ( cpt.IsValidToken () )
  671. {
  672. TOKEN_TYPE type;
  673. if ( cpt.GetTokenType ( type ) )
  674. {
  675. if ( TokenPrimary == type )
  676. {
  677. CToken ct;
  678. if ( ct.Duplicate ( cpt, FALSE ) )
  679. {
  680. bRet = ::SetThreadToken ( &hCurThread, ct.GetTokenHandle () );
  681. }
  682. }
  683. else
  684. {
  685. bRet = ::SetThreadToken ( &hCurThread, cpt.GetTokenHandle () ) ;
  686. }
  687. if (!bRet)
  688. {
  689. throw CFramework_Exception(L"SetThreadToken failed", GetLastError());
  690. }
  691. }
  692. }
  693. }
  694. else
  695. {
  696. hRes = WbemCoImpersonateClient();
  697. if (FAILED(hRes))
  698. {
  699. throw CFramework_Exception(L"WbemCoImpersonateClient failed", hRes);
  700. }
  701. }
  702. if (SUCCEEDED(hRes) || hRes == E_NOTIMPL || bRet )
  703. {
  704. m_fImpersonatingUser = FALSE;
  705. }
  706. }
  707. return ( !m_fImpersonatingUser );
  708. }
  709. //////////////////////////////////////////////////////////////////////////////
  710. //
  711. // FUNCTION : CImpersonateLoggedOnUser::ReallocProcessIdArray
  712. //
  713. // DESCRIPTION : Helper function to alloc a process id array.
  714. //
  715. // INPUTS : None.
  716. //
  717. // OUTPUTS : PDWORD& pdwProcessIds - Process Id Array pointer
  718. // DWORD& dwArraySize - Size of array in bytes
  719. //
  720. // RETURNS : BOOL TRUE/FALSE - Success/Failure
  721. //
  722. // COMMENTS : Call when we need to realloc our process id array.
  723. // This will grow the array by a fixed size, but not
  724. // preserve values.
  725. //
  726. //////////////////////////////////////////////////////////////////////////////
  727. BOOL CImpersonateLoggedOnUser::ReallocProcessIdArray( PDWORD& pdwProcessIds, DWORD& dwArraySize )
  728. {
  729. DWORD dwNewArraySize = dwArraySize + ( PROCESSID_ARRAY_BLOCKSIZE * sizeof(DWORD) );
  730. PDWORD pdwNewArray = new DWORD[dwNewArraySize];
  731. // Make sure the allocation succeeded before overwriting any existing values.
  732. if ( NULL != pdwNewArray )
  733. {
  734. if ( NULL != pdwProcessIds )
  735. {
  736. delete [] pdwProcessIds;
  737. }
  738. pdwProcessIds = pdwNewArray;
  739. dwArraySize = dwNewArraySize;
  740. }
  741. else
  742. {
  743. throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
  744. }
  745. return ( NULL != pdwNewArray );
  746. }
  747. //////////////////////////////////////////////////////////////////////////////
  748. //
  749. // FUNCTION : CImpersonateLoggedOnUser::ReallocModuleHandleArray
  750. //
  751. // DESCRIPTION : Helper function to alloc a module handle array.
  752. //
  753. // INPUTS : None.
  754. //
  755. // OUTPUTS : HMODULE*& phModules - Module Handle Array pointer
  756. // DWORD& dwArraySize - size of array in bytes
  757. //
  758. // RETURNS : BOOL TRUE/FALSE - Success/Failure
  759. //
  760. // COMMENTS : Call when we need to realloc our module handle array.
  761. // This will grow the array by a fixed size, but not
  762. // preserve values.
  763. //
  764. //////////////////////////////////////////////////////////////////////////////
  765. BOOL CImpersonateLoggedOnUser::ReallocModuleHandleArray( HMODULE*& phModules, DWORD& dwArraySize )
  766. {
  767. DWORD dwNewArraySize = dwArraySize + ( HMODULE_ARRAY_BLOCKSIZE * sizeof(HMODULE) );
  768. HMODULE* phNewArray = new HMODULE[dwNewArraySize];
  769. // Make sure the allocation succeeded before overwriting any existing values.
  770. if ( NULL != phNewArray )
  771. {
  772. if ( NULL != phModules )
  773. {
  774. delete [] phModules;
  775. }
  776. phModules = phNewArray;
  777. dwArraySize = dwNewArraySize;
  778. }
  779. else
  780. {
  781. throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
  782. }
  783. return ( NULL != phNewArray );
  784. }
  785. bool CImpersonateLoggedOnUser::GetCurrentProcessSid(CSid& sidCurrentProcess)
  786. {
  787. bool fRet = false;
  788. PBYTE pbuff = NULL;
  789. // I am going to revert here in order to access the process's
  790. // sid. This is not privileged information, so this doesn't
  791. // present a security breach.
  792. WbemCoRevertToSelf();
  793. try
  794. {
  795. CProcessToken cpt(NULL, true, TOKEN_QUERY);
  796. DWORD dwLen = 0;
  797. if(!::GetTokenInformation(
  798. cpt.GetTokenHandle(), // the PR0CESS token
  799. TokenUser,
  800. NULL,
  801. 0L,
  802. &dwLen) && (::GetLastError() == ERROR_INSUFFICIENT_BUFFER))
  803. {
  804. pbuff = new BYTE[dwLen];
  805. if(pbuff)
  806. {
  807. if(::GetTokenInformation(
  808. cpt.GetTokenHandle(),
  809. TokenUser,
  810. pbuff,
  811. dwLen,
  812. &dwLen))
  813. {
  814. PTOKEN_USER ptu = (PTOKEN_USER)pbuff;
  815. CSid sidTemp(ptu->User.Sid);
  816. if(sidTemp.IsOK() &&
  817. sidTemp.IsValid())
  818. {
  819. sidCurrentProcess = sidTemp;
  820. fRet = true;
  821. }
  822. }
  823. delete pbuff;
  824. pbuff = NULL;
  825. }
  826. }
  827. }
  828. catch(...)
  829. {
  830. //on our way out not returning anything to user except failure
  831. //can't do anything on this impersonation failure...
  832. WbemCoImpersonateClient();
  833. delete pbuff;
  834. pbuff = NULL;
  835. throw;
  836. }
  837. HRESULT hr = WbemCoImpersonateClient() ;
  838. if (FAILED(hr))
  839. {
  840. throw CFramework_Exception(L"WbemCoImpersonateClient failed", hr);
  841. }
  842. return fRet;
  843. }
  844. #endif