Source code of Windows XP (NT5)
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.

1002 lines
24 KiB

  1. /*++
  2. Copyright (C) 1998-2001 Microsoft Corporation
  3. Module Name:
  4. CALLSEC.CPP
  5. Abstract:
  6. IWbemCallSecurity, IServerSecurity implementation for
  7. provider impersonation.
  8. History:
  9. raymcc 29-Jul-98 First draft.
  10. --*/
  11. #include "precomp.h"
  12. #include <stdio.h>
  13. #include <initguid.h>
  14. #include <winntsec.h>
  15. #include <callsec.h>
  16. #include <cominit.h>
  17. #include <arrtempl.h>
  18. #include <cominit.h>
  19. #include <genutils.h>
  20. //***************************************************************************
  21. //
  22. // CWbemCallSecurity
  23. //
  24. // This object is used to supply client impersonation to providers.
  25. //
  26. // Usage:
  27. // (1) When client first makes call, call CreateInst() and get a new
  28. // empty object (ref count of 1). Constructors/Destructors are private.
  29. //
  30. //***************************************************************************
  31. // ok
  32. CWbemCallSecurity::CWbemCallSecurity()
  33. {
  34. OSVERSIONINFO os;
  35. os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  36. GetVersionEx(&os);
  37. if (os.dwPlatformId != VER_PLATFORM_WIN32_NT)
  38. m_bWin9x = TRUE;
  39. else
  40. m_bWin9x = FALSE;
  41. m_lRef = 1; // Ref count
  42. m_hThreadToken = 0; // Handle to thread imp token
  43. m_dwPotentialImpLevel = 0; // Potential
  44. m_dwActiveImpLevel = 0; // Active impersonation
  45. m_dwAuthnSvc = 0;
  46. m_dwAuthzSvc = 0;
  47. m_dwAuthnLevel = 0;
  48. m_pServerPrincNam = 0;
  49. m_pIdentity = 0;
  50. }
  51. //***************************************************************************
  52. //
  53. // ~CWbemCallSecurity
  54. //
  55. // Destructor. Closes any open handles, deallocates any non-NULL
  56. // strings.
  57. //
  58. //***************************************************************************
  59. // ok
  60. CWbemCallSecurity::~CWbemCallSecurity()
  61. {
  62. if (m_hThreadToken)
  63. CloseHandle(m_hThreadToken);
  64. if (m_pServerPrincNam)
  65. CoTaskMemFree(m_pServerPrincNam);
  66. if (m_pIdentity)
  67. CoTaskMemFree(m_pIdentity);
  68. }
  69. void
  70. CWbemCallSecurity::operator=(const CWbemCallSecurity& Other)
  71. {
  72. if(m_hThreadToken)
  73. {
  74. CloseHandle(m_hThreadToken);
  75. m_hThreadToken=NULL ;
  76. }
  77. if ( Other.m_hThreadToken )
  78. {
  79. DuplicateHandle(
  80. GetCurrentProcess(),
  81. Other.m_hThreadToken,
  82. GetCurrentProcess(),
  83. &m_hThreadToken,
  84. 0,
  85. TRUE,
  86. DUPLICATE_SAME_ACCESS);
  87. }
  88. m_dwPotentialImpLevel = Other.m_dwPotentialImpLevel;
  89. m_dwActiveImpLevel = 0;
  90. m_dwAuthnSvc = Other.m_dwAuthnSvc;
  91. m_dwAuthzSvc = Other.m_dwAuthzSvc;
  92. m_dwAuthnLevel = Other.m_dwAuthnLevel;
  93. if(m_pServerPrincNam)
  94. {
  95. CoTaskMemFree(m_pServerPrincNam);
  96. m_pServerPrincNam = NULL;
  97. }
  98. if (Other.m_pServerPrincNam)
  99. {
  100. m_pServerPrincNam = (LPWSTR)CoTaskMemAlloc(
  101. (wcslen(Other.m_pServerPrincNam) + 1) * 2);
  102. if(m_pServerPrincNam)
  103. wcscpy(m_pServerPrincNam, Other.m_pServerPrincNam);
  104. }
  105. if(m_pIdentity)
  106. {
  107. CoTaskMemFree(m_pIdentity);
  108. m_pIdentity = NULL;
  109. }
  110. if (Other.m_pIdentity)
  111. {
  112. m_pIdentity = (LPWSTR)CoTaskMemAlloc(
  113. (wcslen(Other.m_pIdentity) + 1) * 2);
  114. if(m_pIdentity)
  115. wcscpy(m_pIdentity, Other.m_pIdentity);
  116. }
  117. }
  118. //***************************************************************************
  119. //
  120. // CWbemCallSecurity::AddRef
  121. //
  122. //***************************************************************************
  123. // ok
  124. ULONG CWbemCallSecurity::AddRef()
  125. {
  126. return InterlockedIncrement(&m_lRef);
  127. }
  128. //***************************************************************************
  129. //
  130. // CWbemCallSecurity::Release
  131. //
  132. //***************************************************************************
  133. // ok
  134. ULONG CWbemCallSecurity::Release()
  135. {
  136. long lRef = InterlockedDecrement(&m_lRef);
  137. if(lRef == 0)
  138. delete this;
  139. return lRef;
  140. }
  141. //***************************************************************************
  142. //
  143. // CWbemCallSecurity::QueryInterface
  144. //
  145. //***************************************************************************
  146. // ok
  147. HRESULT CWbemCallSecurity::QueryInterface(REFIID riid, void** ppv)
  148. {
  149. if(riid == IID_IUnknown)
  150. {
  151. *ppv = (IUnknown *) this;
  152. AddRef();
  153. return S_OK;
  154. }
  155. else if (riid == IID_IServerSecurity)
  156. {
  157. *ppv = (IServerSecurity *) this;
  158. AddRef();
  159. return S_OK;
  160. }
  161. else if (riid == IID_IWbemCallSecurity)
  162. {
  163. *ppv = (IWbemCallSecurity *) this;
  164. AddRef();
  165. return S_OK;
  166. }
  167. else return E_NOINTERFACE;
  168. }
  169. //***************************************************************************
  170. //
  171. // CWbemCallSecurity:QueryBlanket
  172. //
  173. //***************************************************************************
  174. // ok
  175. HRESULT STDMETHODCALLTYPE CWbemCallSecurity::QueryBlanket(
  176. /* [out] */ DWORD __RPC_FAR *pAuthnSvc,
  177. /* [out] */ DWORD __RPC_FAR *pAuthzSvc,
  178. /* [out] */ OLECHAR __RPC_FAR *__RPC_FAR *pServerPrincName,
  179. /* [out] */ DWORD __RPC_FAR *pAuthnLevel,
  180. /* [out] */ DWORD __RPC_FAR *pImpLevel,
  181. /* [out] */ void __RPC_FAR *__RPC_FAR *pPrivs,
  182. /* [out] */ DWORD __RPC_FAR *pCapabilities
  183. )
  184. {
  185. if (m_bWin9x)
  186. return E_NOTIMPL;
  187. if (m_dwPotentialImpLevel == 0 )
  188. return E_FAIL;
  189. // Return DWORD parameters, after checking.
  190. // ========================================
  191. if (pAuthnSvc)
  192. *pAuthnSvc = m_dwAuthnSvc;
  193. if (pAuthzSvc)
  194. *pAuthzSvc = m_dwAuthzSvc ;
  195. if (pImpLevel)
  196. *pImpLevel = m_dwActiveImpLevel ;
  197. if (pAuthnLevel)
  198. *pAuthnLevel = m_dwAuthnLevel;
  199. if (pServerPrincName)
  200. {
  201. *pServerPrincName = 0;
  202. if (m_pServerPrincNam)
  203. {
  204. *pServerPrincName = (LPWSTR) CoTaskMemAlloc((wcslen(m_pServerPrincNam) + 1) * 2);
  205. wcscpy(*pServerPrincName, m_pServerPrincNam);
  206. }
  207. }
  208. if (pPrivs)
  209. {
  210. *pPrivs = m_pIdentity; // Documented to point to an internal!!
  211. }
  212. return S_OK;
  213. }
  214. //***************************************************************************
  215. //
  216. // CWbemCallSecurity::ImpersonateClient
  217. //
  218. //***************************************************************************
  219. // ok
  220. HRESULT STDMETHODCALLTYPE CWbemCallSecurity::ImpersonateClient(void)
  221. {
  222. if (m_bWin9x)
  223. return E_NOTIMPL;
  224. if (m_dwActiveImpLevel != 0) // Already impersonating
  225. return S_OK;
  226. if(m_hThreadToken == NULL)
  227. {
  228. return WBEM_E_INVALID_CONTEXT;
  229. }
  230. if (m_dwPotentialImpLevel == 0)
  231. return (ERROR_CANT_OPEN_ANONYMOUS | 0x80070000);
  232. BOOL bRes;
  233. bRes = SetThreadToken(NULL, m_hThreadToken);
  234. if (bRes)
  235. {
  236. m_dwActiveImpLevel = m_dwPotentialImpLevel;
  237. return S_OK;
  238. }
  239. return E_FAIL;
  240. }
  241. //***************************************************************************
  242. //
  243. // CWbemCallSecurity::RevertToSelf
  244. //
  245. // Returns S_OK or E_FAIL.
  246. // Returns E_NOTIMPL on Win9x platforms.
  247. //
  248. //***************************************************************************
  249. // ok
  250. HRESULT STDMETHODCALLTYPE CWbemCallSecurity::RevertToSelf( void)
  251. {
  252. if (m_bWin9x)
  253. return E_NOTIMPL;
  254. if (m_dwActiveImpLevel == 0)
  255. return S_OK;
  256. if (m_dwPotentialImpLevel == 0)
  257. return (ERROR_CANT_OPEN_ANONYMOUS | 0x80070000);
  258. // If here,we are impersonating and can definitely revert.
  259. // =======================================================
  260. BOOL bRes = SetThreadToken(NULL, NULL);
  261. if (bRes == FALSE)
  262. return E_FAIL;
  263. m_dwActiveImpLevel = 0; // No longer actively impersonating
  264. return S_OK;
  265. }
  266. //***************************************************************************
  267. //
  268. // CWbemCallSecurity::IsImpersonating
  269. //
  270. //***************************************************************************
  271. BOOL STDMETHODCALLTYPE CWbemCallSecurity::IsImpersonating( void)
  272. {
  273. if (m_hThreadToken && m_dwActiveImpLevel != 0)
  274. return TRUE;
  275. return FALSE;
  276. }
  277. //***************************************************************************
  278. //
  279. // CWbemCallSecurity::CreateInst
  280. //
  281. // Creates a new instance
  282. //***************************************************************************
  283. // ok
  284. IWbemCallSecurity * CWbemCallSecurity::CreateInst()
  285. {
  286. return (IWbemCallSecurity *) new CWbemCallSecurity; // Constructed with ref count of 1
  287. }
  288. //***************************************************************************
  289. //
  290. // CWbemCallSecurity::GetPotentialImpersonation
  291. //
  292. // Returns 0 if no impersonation is currently possible or the
  293. // level which would be active during impersonation:
  294. //
  295. // RPC_C_IMP_LEVEL_ANONYMOUS
  296. // RPC_C_IMP_LEVEL_IDENTIFY
  297. // RPC_C_IMP_LEVEL_IMPERSONATE
  298. // RPC_C_IMP_LEVEL_DELEGATE
  299. //
  300. //***************************************************************************
  301. // ok
  302. HRESULT CWbemCallSecurity::GetPotentialImpersonation()
  303. {
  304. return m_dwPotentialImpLevel;
  305. }
  306. //***************************************************************************
  307. //
  308. // CWbemCallSecurity::GetActiveImpersonation
  309. //
  310. // Returns 0 if no impersonation is currently active or the
  311. // currently active level:
  312. //
  313. // RPC_C_IMP_LEVEL_ANONYMOUS
  314. // RPC_C_IMP_LEVEL_IDENTIFY
  315. // RPC_C_IMP_LEVEL_IMPERSONATE
  316. // RPC_C_IMP_LEVEL_DELEGATE
  317. //
  318. //***************************************************************************
  319. // ok
  320. HRESULT CWbemCallSecurity::GetActiveImpersonation()
  321. {
  322. return m_dwActiveImpLevel;
  323. }
  324. //***************************************************************************
  325. //
  326. // CWbemCallSecurity::CloneThreadContext
  327. //
  328. // Call this on a thread to retrieve the potential impersonation info for
  329. // that thread and set the current object to be able to duplicate it later.
  330. //
  331. // Return codes:
  332. //
  333. // S_OK
  334. // E_FAIL
  335. // E_NOTIMPL on Win9x
  336. // E_ABORT if the calling thread is already impersonating a client.
  337. //
  338. //***************************************************************************
  339. HRESULT CWbemCallSecurity::CloneThreadContext(BOOL bInternallyIssued)
  340. {
  341. // If on Win9x, don't bother.
  342. // ==========================
  343. if (m_bWin9x)
  344. return E_NOTIMPL;
  345. if (m_hThreadToken) // Already called this
  346. return E_ABORT;
  347. // Get the current context.
  348. // ========================
  349. IServerSecurity *pSec = 0;
  350. HRESULT hRes = WbemCoGetCallContext(IID_IServerSecurity, (LPVOID *) &pSec);
  351. CReleaseMe rmSec(pSec);
  352. if (hRes != S_OK)
  353. {
  354. // There is no call context --- this must be an in-proc object calling
  355. // us from its own thread. Initialize from current thread token
  356. // ===================================================================
  357. return CloneThreadToken();
  358. }
  359. // Figure out if the call context is ours or RPCs
  360. // ==============================================
  361. IWbemCallSecurity* pInternal = NULL;
  362. if(SUCCEEDED(pSec->QueryInterface(IID_IWbemCallSecurity,
  363. (void**)&pInternal)))
  364. {
  365. CReleaseMe rmInt(pInternal);
  366. // This is our own call context --- this must be ab in-proc object
  367. // calling us from our thread. Behave depending on the flags
  368. // ===============================================================
  369. if(bInternallyIssued)
  370. {
  371. // Internal requests always propagate context. Therefore, we just
  372. // copy the context that we have got
  373. // ==============================================================
  374. *this = *(CWbemCallSecurity*)pInternal;
  375. return S_OK;
  376. }
  377. else
  378. {
  379. // Provider request --- Initialize from the current thread token
  380. // =============================================================
  381. return CloneThreadToken();
  382. }
  383. }
  384. // If here, we are not impersonating and we want to gather info
  385. // about the client's call.
  386. // ============================================================
  387. RPC_AUTHZ_HANDLE hAuth;
  388. // Ensures auto release of the mutex if we crash
  389. CAutoSecurityMutex autosm;
  390. DWORD t_ImpLevel = 0 ;
  391. hRes = pSec->QueryBlanket(
  392. &m_dwAuthnSvc,
  393. &m_dwAuthzSvc,
  394. &m_pServerPrincNam,
  395. &m_dwAuthnLevel,
  396. &t_ImpLevel,
  397. &hAuth, // RPC_AUTHZ_HANDLE
  398. NULL // Capabilities; not used
  399. );
  400. if(FAILED(hRes))
  401. {
  402. // In some cases, we cant get the name, but the rest is ok. In particular
  403. // the temporary SMS accounts have that property. Or nt 4 after IPCONFIG /RELEASE
  404. hRes = pSec->QueryBlanket(
  405. &m_dwAuthnSvc,
  406. &m_dwAuthzSvc,
  407. &m_pServerPrincNam,
  408. &m_dwAuthnLevel,
  409. &t_ImpLevel,
  410. NULL, // RPC_AUTHZ_HANDLE
  411. NULL // Capabilities; not used
  412. );
  413. hAuth = NULL;
  414. }
  415. // We don't need this anymore.
  416. autosm.Release();
  417. if(FAILED(hRes))
  418. {
  419. // THIS IS A WORKAROUND FOR COM BUG:
  420. // This failure is indicative of an anonymous-level client.
  421. // ========================================================
  422. m_dwPotentialImpLevel = 0;
  423. return S_OK;
  424. }
  425. if (hAuth)
  426. {
  427. m_pIdentity = LPWSTR(CoTaskMemAlloc((wcslen(LPWSTR(hAuth)) + 1) * 2));
  428. if(m_pIdentity)
  429. wcscpy(m_pIdentity, LPWSTR(hAuth));
  430. }
  431. // Impersonate the client long enough to clone the thread token.
  432. // =============================================================
  433. BOOL bImp = pSec->IsImpersonating();
  434. if(!bImp)
  435. hRes = pSec->ImpersonateClient();
  436. if (FAILED(hRes))
  437. {
  438. if(!bImp)
  439. pSec->RevertToSelf();
  440. return E_FAIL;
  441. }
  442. HRESULT hres = CloneThreadToken();
  443. if(!bImp)
  444. pSec->RevertToSelf();
  445. return hres;
  446. }
  447. HRESULT CWbemCallSecurity::CloneThreadToken()
  448. {
  449. HANDLE hPrimary = 0 ;
  450. HANDLE hToken = 0;
  451. BOOL bRes = OpenThreadToken(
  452. GetCurrentThread(),
  453. TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE,
  454. TRUE,
  455. &hToken
  456. );
  457. if (bRes == FALSE)
  458. {
  459. m_hThreadToken = NULL;
  460. m_dwAuthnSvc = RPC_C_AUTHN_WINNT;
  461. m_dwAuthzSvc = RPC_C_AUTHZ_NONE;
  462. m_dwAuthnLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
  463. m_pServerPrincNam = NULL;
  464. m_pIdentity = NULL;
  465. long lRes = GetLastError();
  466. if(lRes == ERROR_NO_IMPERSONATION_TOKEN || lRes == ERROR_NO_TOKEN)
  467. {
  468. // This is the basic process thread.
  469. // =================================
  470. bRes = OpenProcessToken(
  471. GetCurrentProcess(),
  472. TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE,
  473. &hPrimary
  474. );
  475. if (bRes==FALSE)
  476. {
  477. // Unknown error
  478. // =============
  479. m_dwPotentialImpLevel = 0;
  480. return E_FAIL;
  481. }
  482. }
  483. else if(lRes == ERROR_CANT_OPEN_ANONYMOUS)
  484. {
  485. // Anonymous call
  486. // ==============
  487. m_dwPotentialImpLevel = 0;
  488. return S_OK;
  489. }
  490. else
  491. {
  492. // Unknown error
  493. // =============
  494. m_dwPotentialImpLevel = 0;
  495. return E_FAIL;
  496. }
  497. }
  498. // Find out token info.
  499. // =====================
  500. SECURITY_IMPERSONATION_LEVEL t_Level = SecurityImpersonation ;
  501. if ( hToken )
  502. {
  503. DWORD dwBytesReturned = 0;
  504. bRes = GetTokenInformation (
  505. hToken,
  506. TokenImpersonationLevel,
  507. ( void * ) & t_Level,
  508. sizeof ( t_Level ),
  509. &dwBytesReturned
  510. );
  511. if (bRes == FALSE)
  512. {
  513. CloseHandle(hToken);
  514. return E_FAIL;
  515. }
  516. }
  517. switch (t_Level)
  518. {
  519. case SecurityAnonymous:
  520. m_dwPotentialImpLevel = RPC_C_IMP_LEVEL_ANONYMOUS;
  521. break;
  522. case SecurityIdentification:
  523. m_dwPotentialImpLevel = RPC_C_IMP_LEVEL_IDENTIFY;
  524. break;
  525. case SecurityImpersonation:
  526. m_dwPotentialImpLevel = RPC_C_IMP_LEVEL_IMPERSONATE;
  527. break;
  528. case SecurityDelegation:
  529. m_dwPotentialImpLevel = RPC_C_IMP_LEVEL_DELEGATE;
  530. break;
  531. default:
  532. m_dwPotentialImpLevel = 0;
  533. break;
  534. }
  535. // Duplicate the handle.
  536. // ============================
  537. bRes = DuplicateToken (
  538. hToken ? hToken : hPrimary ,
  539. (SECURITY_IMPERSONATION_LEVEL)t_Level,
  540. &m_hThreadToken
  541. );
  542. if ( hToken )
  543. {
  544. CloseHandle(hToken);
  545. }
  546. else
  547. {
  548. CloseHandle(hPrimary);
  549. }
  550. if (bRes == FALSE)
  551. return E_FAIL;
  552. return S_OK;
  553. }
  554. RELEASE_ME CWbemCallSecurity* CWbemCallSecurity::MakeInternalCopyOfThread()
  555. {
  556. IServerSecurity* pSec;
  557. HRESULT hres = WbemCoGetCallContext(IID_IServerSecurity, (void**)&pSec);
  558. if(FAILED(hres))
  559. return NULL;
  560. CReleaseMe rm1(pSec);
  561. IServerSecurity* pIntSec;
  562. hres = pSec->QueryInterface(IID_IWbemCallSecurity, (void**)&pIntSec);
  563. if(FAILED(hres))
  564. return NULL;
  565. CWbemCallSecurity* pCopy = new CWbemCallSecurity;
  566. if (pCopy)
  567. *pCopy = *(CWbemCallSecurity*)pIntSec;
  568. pIntSec->Release();
  569. return pCopy;
  570. }
  571. DWORD CWbemCallSecurity::GetAuthenticationId(LUID& rluid)
  572. {
  573. if(m_hThreadToken == NULL)
  574. return ERROR_INVALID_HANDLE;
  575. TOKEN_STATISTICS stat;
  576. DWORD dwRet;
  577. if(!GetTokenInformation(m_hThreadToken, TokenStatistics,
  578. (void*)&stat, sizeof(stat), &dwRet))
  579. {
  580. return GetLastError();
  581. }
  582. rluid = stat.AuthenticationId;
  583. return 0;
  584. }
  585. HANDLE CWbemCallSecurity::GetToken()
  586. {
  587. return m_hThreadToken;
  588. }
  589. //***************************************************************************
  590. //
  591. //***************************************************************************
  592. void CWbemCallSecurity::DumpCurrentContext()
  593. {
  594. if (m_bWin9x)
  595. return;
  596. HANDLE hThreadToken;
  597. BOOL bRes = OpenThreadToken(
  598. GetCurrentThread(),
  599. TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE,
  600. TRUE,
  601. &hThreadToken
  602. );
  603. if (!bRes)
  604. return;
  605. const DWORD dwBytes = 512;
  606. BYTE Buf[dwBytes], Name[dwBytes], Domain[dwBytes];
  607. DWORD dwBytesReturned = 0, dwDomainSize = dwBytes, dwNameSize = dwBytes;
  608. GetTokenInformation(hThreadToken, TokenUser, Buf, dwBytes, &dwBytesReturned);
  609. SID_NAME_USE snu;
  610. SetThreadToken(NULL, NULL);
  611. bRes = LookupAccountSidW(NULL, ((PTOKEN_USER) Buf)->User.Sid, LPWSTR(Name), &dwNameSize,
  612. LPWSTR(Domain), &dwDomainSize, &snu);
  613. SetThreadToken(NULL, hThreadToken);
  614. printf("User = %S\\%S\n", Domain, Name);
  615. CloseHandle(hThreadToken);
  616. }
  617. CDerivedObjectSecurity::CDerivedObjectSecurity()
  618. {
  619. m_bValid = FALSE;
  620. m_bEnabled = TRUE;
  621. if(!IsNT() || !IsDcomEnabled())
  622. {
  623. m_bEnabled = FALSE;
  624. m_bValid = TRUE;
  625. }
  626. HRESULT hres = RetrieveSidFromCall(&m_sidUser);
  627. if(FAILED(hres))
  628. return;
  629. // Revert to self while remebering the thread token
  630. // ================================================
  631. BOOL bRes;
  632. HANDLE hThreadToken = NULL;
  633. bRes = OpenThreadToken(GetCurrentThread(), TOKEN_READ | TOKEN_IMPERSONATE,
  634. TRUE, &hThreadToken);
  635. if(bRes)
  636. SetThreadToken(NULL, NULL);
  637. // Open process token
  638. // ==================
  639. HANDLE hProcessToken;
  640. bRes = OpenProcessToken(GetCurrentProcess(), TOKEN_READ,
  641. &hProcessToken);
  642. if(!bRes)
  643. {
  644. if(hThreadToken)
  645. CloseHandle(hThreadToken);
  646. return;
  647. }
  648. // Retrieve our process SID
  649. // ========================
  650. hres = RetrieveSidFromToken(hProcessToken, &m_sidSystem);
  651. CloseHandle(hProcessToken);
  652. // Re-impersonate the original thread token
  653. // ========================================
  654. if(hThreadToken)
  655. {
  656. SetThreadToken(NULL, hThreadToken);
  657. CloseHandle(hThreadToken);
  658. }
  659. if(FAILED(hres))
  660. return;
  661. m_bValid = TRUE;
  662. }
  663. HRESULT CDerivedObjectSecurity::RetrieveSidFromCall(CNtSid* psid)
  664. {
  665. HANDLE hToken;
  666. HRESULT hres;
  667. BOOL bRes;
  668. // Check if we are on an impersonated thread
  669. // =========================================
  670. bRes = OpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE, &hToken);
  671. if(bRes)
  672. {
  673. // We are --- just use this token for authentication
  674. // =================================================
  675. hres = RetrieveSidFromToken(hToken, psid);
  676. CloseHandle(hToken);
  677. return hres;
  678. }
  679. // Construct CWbemCallSecurity that will determine (according to our
  680. // non-trivial provider handling rules) the security context of this
  681. // call
  682. // =================================================================
  683. IWbemCallSecurity* pServerSec = CWbemCallSecurity::CreateInst();
  684. if(pServerSec == NULL)
  685. return WBEM_E_OUT_OF_MEMORY;
  686. CReleaseMe rm1(pServerSec);
  687. hres = pServerSec->CloneThreadContext(FALSE);
  688. if(FAILED(hres))
  689. return hres;
  690. // Impersonate client
  691. // ==================
  692. hres = pServerSec->ImpersonateClient();
  693. if(FAILED(hres))
  694. return hres;
  695. // Open impersonated token
  696. // =======================
  697. bRes = OpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE, &hToken);
  698. if(!bRes)
  699. {
  700. long lRes = GetLastError();
  701. if(lRes == ERROR_NO_IMPERSONATION_TOKEN || lRes == ERROR_NO_TOKEN)
  702. {
  703. // Not impersonating --- get the process token instead
  704. // ===================================================
  705. bRes = OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hToken);
  706. if(!bRes)
  707. {
  708. pServerSec->RevertToSelf();
  709. return WBEM_E_ACCESS_DENIED;
  710. }
  711. }
  712. else
  713. {
  714. // Real problems
  715. // =============
  716. pServerSec->RevertToSelf();
  717. return WBEM_E_ACCESS_DENIED;
  718. }
  719. }
  720. hres = RetrieveSidFromToken(hToken, psid);
  721. CloseHandle(hToken);
  722. pServerSec->RevertToSelf();
  723. return hres;
  724. }
  725. HRESULT CDerivedObjectSecurity::RetrieveSidFromToken(HANDLE hToken,
  726. CNtSid* psid)
  727. {
  728. // Retrieve the length of the user sid structure
  729. // =============================================
  730. BOOL bRes;
  731. DWORD dwLen = 0;
  732. TOKEN_USER tu;
  733. memset(&tu,0,sizeof(TOKEN_USER));
  734. bRes = GetTokenInformation(hToken, TokenUser, &tu, sizeof(TOKEN_USER), &dwLen);
  735. DWORD dwLast = GetLastError();
  736. if(bRes)
  737. {
  738. // 1-length sid? I don't think so
  739. return WBEM_E_CRITICAL_ERROR;
  740. }
  741. // Allocate buffer to hold user sid
  742. // ================================
  743. BYTE* pBuffer = new BYTE[dwLen];
  744. if(pBuffer == NULL)
  745. return WBEM_E_OUT_OF_MEMORY;
  746. CVectorDeleteMe<BYTE> dm1(pBuffer);
  747. // Retrieve the user sid structure
  748. // ===============================
  749. bRes = GetTokenInformation(hToken, TokenUser, pBuffer, dwLen, &dwLen);
  750. if(!bRes)
  751. return WBEM_E_ACCESS_DENIED;
  752. TOKEN_USER* pUser = (TOKEN_USER*)pBuffer;
  753. // Set our sid to the returned one
  754. // ===============================
  755. *psid = CNtSid(pUser->User.Sid);
  756. return WBEM_S_NO_ERROR;
  757. }
  758. CDerivedObjectSecurity::~CDerivedObjectSecurity()
  759. {
  760. }
  761. BOOL CDerivedObjectSecurity::AccessCheck()
  762. {
  763. if(!m_bValid)
  764. return FALSE;
  765. if(!m_bEnabled)
  766. return TRUE;
  767. // Find out who is calling
  768. // =======================
  769. CNtSid sidCaller;
  770. HRESULT hres = RetrieveSidFromCall(&sidCaller);
  771. if(FAILED(hres))
  772. return FALSE;
  773. // Compare the caller to the issuing user and ourselves
  774. // ====================================================
  775. if(sidCaller == m_sidUser || sidCaller == m_sidSystem)
  776. return TRUE;
  777. else
  778. return FALSE;
  779. }