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.

1047 lines
28 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. #include <helper.h>
  21. //***************************************************************************
  22. //
  23. // CWbemCallSecurity
  24. //
  25. // This object is used to supply client impersonation to providers.
  26. //
  27. // Usage:
  28. // (1) When client first makes call, call CreateInst() and get a new
  29. // empty object (ref count of 1). Constructors/Destructors are private.
  30. //
  31. //***************************************************************************
  32. // ok
  33. CWbemCallSecurity::CWbemCallSecurity()
  34. {
  35. #ifdef WMI_PRIVATE_DBG
  36. m_currentThreadID = 0;
  37. m_lastRevert = 0;
  38. #endif
  39. m_lRef = 1; // Ref count
  40. m_hThreadToken = 0; // Handle to thread imp token
  41. m_dwPotentialImpLevel = 0; // Potential
  42. m_dwActiveImpLevel = 0; // Active impersonation
  43. m_dwAuthnSvc = 0;
  44. m_dwAuthzSvc = 0;
  45. m_dwAuthnLevel = 0;
  46. m_pServerPrincNam = 0;
  47. m_pIdentity = 0;
  48. }
  49. //***************************************************************************
  50. //
  51. // ~CWbemCallSecurity
  52. //
  53. // Destructor. Closes any open handles, deallocates any non-NULL
  54. // strings.
  55. //
  56. //***************************************************************************
  57. // ok
  58. CWbemCallSecurity::~CWbemCallSecurity()
  59. {
  60. if (m_hThreadToken)
  61. CloseHandle(m_hThreadToken);
  62. if (m_pServerPrincNam)
  63. CoTaskMemFree(m_pServerPrincNam);
  64. if (m_pIdentity)
  65. CoTaskMemFree(m_pIdentity);
  66. }
  67. CWbemCallSecurity::CWbemCallSecurity(const CWbemCallSecurity& Other)
  68. {
  69. #ifdef WMI_PRIVATE_DBG
  70. m_currentThreadID = 0;
  71. m_lastRevert = 0;
  72. #endif
  73. HANDLE hTmpToken = NULL;
  74. if ( Other.m_hThreadToken )
  75. {
  76. if (!DuplicateHandle(
  77. GetCurrentProcess(),
  78. Other.m_hThreadToken,
  79. GetCurrentProcess(),
  80. &hTmpToken,
  81. 0,
  82. TRUE,
  83. DUPLICATE_SAME_ACCESS))
  84. throw CX_Exception();
  85. }
  86. WCHAR * pTmpPrincipal = NULL;
  87. if (Other.m_pServerPrincNam)
  88. {
  89. size_t tmpLength = wcslen(Other.m_pServerPrincNam) + 1;
  90. pTmpPrincipal = (LPWSTR)CoTaskMemAlloc(tmpLength * (sizeof wchar_t));
  91. if(NULL == pTmpPrincipal)
  92. {
  93. if (hTmpToken) CloseHandle(hTmpToken);
  94. throw CX_MemoryException();
  95. }
  96. StringCchCopyW(pTmpPrincipal , tmpLength, Other.m_pServerPrincNam);
  97. }
  98. WCHAR * pTmpIdentity = NULL;
  99. if (Other.m_pIdentity)
  100. {
  101. size_t tmpLength = wcslen(Other.m_pIdentity) + 1;
  102. pTmpIdentity = (LPWSTR)CoTaskMemAlloc( tmpLength * (sizeof wchar_t));
  103. if(NULL == pTmpIdentity)
  104. {
  105. if (hTmpToken) CloseHandle(hTmpToken);
  106. CoTaskMemFree(pTmpPrincipal);
  107. throw CX_MemoryException();
  108. }
  109. StringCchCopyW(pTmpIdentity, tmpLength , Other.m_pIdentity);
  110. }
  111. m_hThreadToken = hTmpToken;
  112. m_dwPotentialImpLevel = Other.m_dwPotentialImpLevel;
  113. m_dwActiveImpLevel = 0;
  114. m_dwAuthnSvc = Other.m_dwAuthnSvc;
  115. m_dwAuthzSvc = Other.m_dwAuthzSvc;
  116. m_dwAuthnLevel = Other.m_dwAuthnLevel;
  117. m_pServerPrincNam = pTmpPrincipal;
  118. m_pIdentity = pTmpIdentity;
  119. }
  120. CWbemCallSecurity &
  121. CWbemCallSecurity::operator=(const CWbemCallSecurity& Other)
  122. {
  123. CWbemCallSecurity tmp(Other);
  124. std::swap(m_hThreadToken, tmp.m_hThreadToken);
  125. std::swap( m_dwPotentialImpLevel,tmp.m_dwPotentialImpLevel);
  126. std::swap( m_dwActiveImpLevel, tmp.m_dwActiveImpLevel);
  127. std::swap( m_dwAuthnSvc, tmp.m_dwAuthnSvc);
  128. std::swap( m_dwAuthzSvc, tmp.m_dwAuthzSvc);
  129. std::swap( m_dwAuthnLevel, tmp.m_dwAuthnLevel);
  130. std::swap( m_pServerPrincNam, tmp.m_pServerPrincNam);
  131. std::swap( m_pIdentity, tmp.m_pIdentity);
  132. return *this;
  133. }
  134. //***************************************************************************
  135. //
  136. // CWbemCallSecurity::AddRef
  137. //
  138. //***************************************************************************
  139. // ok
  140. ULONG CWbemCallSecurity::AddRef()
  141. {
  142. return InterlockedIncrement(&m_lRef);
  143. }
  144. //***************************************************************************
  145. //
  146. // CWbemCallSecurity::Release
  147. //
  148. //***************************************************************************
  149. // ok
  150. ULONG CWbemCallSecurity::Release()
  151. {
  152. long lRef = InterlockedDecrement(&m_lRef);
  153. if(lRef == 0)
  154. delete this;
  155. return lRef;
  156. }
  157. //***************************************************************************
  158. //
  159. // CWbemCallSecurity::QueryInterface
  160. //
  161. //***************************************************************************
  162. // ok
  163. HRESULT CWbemCallSecurity::QueryInterface(REFIID riid, void** ppv)
  164. {
  165. if(riid == IID_IUnknown)
  166. {
  167. *ppv = (IUnknown *) this;
  168. AddRef();
  169. return S_OK;
  170. }
  171. else if (riid == IID_IServerSecurity)
  172. {
  173. *ppv = (IServerSecurity *) this;
  174. AddRef();
  175. return S_OK;
  176. }
  177. else if (riid == IID_IWbemCallSecurity)
  178. {
  179. *ppv = (IWbemCallSecurity *) this;
  180. AddRef();
  181. return S_OK;
  182. }
  183. else return E_NOINTERFACE;
  184. }
  185. //***************************************************************************
  186. //
  187. // CWbemCallSecurity:QueryBlanket
  188. //
  189. //***************************************************************************
  190. // ok
  191. HRESULT STDMETHODCALLTYPE CWbemCallSecurity::QueryBlanket(
  192. /* [out] */ DWORD __RPC_FAR *pAuthnSvc,
  193. /* [out] */ DWORD __RPC_FAR *pAuthzSvc,
  194. /* [out] */ OLECHAR __RPC_FAR *__RPC_FAR *pServerPrincName,
  195. /* [out] */ DWORD __RPC_FAR *pAuthnLevel,
  196. /* [out] */ DWORD __RPC_FAR *pImpLevel,
  197. /* [out] */ void __RPC_FAR *__RPC_FAR *pPrivs,
  198. /* [out] */ DWORD __RPC_FAR *pCapabilities
  199. )
  200. {
  201. if (m_dwPotentialImpLevel == 0 )
  202. return E_FAIL;
  203. // Return DWORD parameters, after checking.
  204. // ========================================
  205. if (pAuthnSvc)
  206. *pAuthnSvc = m_dwAuthnSvc;
  207. if (pAuthzSvc)
  208. *pAuthzSvc = m_dwAuthzSvc ;
  209. if (pImpLevel)
  210. *pImpLevel = m_dwActiveImpLevel ;
  211. if (pAuthnLevel)
  212. *pAuthnLevel = m_dwAuthnLevel;
  213. if (pServerPrincName)
  214. {
  215. *pServerPrincName = 0;
  216. if (m_pServerPrincNam)
  217. {
  218. size_t tmpLength = wcslen(m_pServerPrincNam) + 1;
  219. *pServerPrincName = (LPWSTR) CoTaskMemAlloc(tmpLength * (sizeof wchar_t));
  220. if (*pServerPrincName)
  221. {
  222. StringCchCopyW(*pServerPrincName, tmpLength , m_pServerPrincNam);
  223. }
  224. else
  225. {
  226. return E_OUTOFMEMORY;
  227. }
  228. }
  229. }
  230. if (pPrivs)
  231. {
  232. *pPrivs = m_pIdentity; // Documented to point to an internal!!
  233. }
  234. return S_OK;
  235. }
  236. //***************************************************************************
  237. //
  238. // CWbemCallSecurity::ImpersonateClient
  239. //
  240. //***************************************************************************
  241. // ok
  242. HRESULT STDMETHODCALLTYPE CWbemCallSecurity::ImpersonateClient(void)
  243. {
  244. #ifdef WMI_PRIVATE_DBG
  245. _DBG_ASSERT(m_currentThreadID == 0 || m_currentThreadID == GetCurrentThreadId());
  246. m_currentThreadID = GetCurrentThreadId();
  247. #endif
  248. if (m_dwActiveImpLevel != 0) // Already impersonating
  249. return S_OK;
  250. if(m_hThreadToken == NULL)
  251. {
  252. return WBEM_E_INVALID_CONTEXT;
  253. }
  254. if (m_dwPotentialImpLevel == 0)
  255. return (ERROR_CANT_OPEN_ANONYMOUS | 0x80070000);
  256. BOOL bRes;
  257. bRes = SetThreadToken(NULL, m_hThreadToken);
  258. if (bRes)
  259. {
  260. m_dwActiveImpLevel = m_dwPotentialImpLevel;
  261. return S_OK;
  262. }
  263. return E_FAIL;
  264. }
  265. //***************************************************************************
  266. //
  267. // CWbemCallSecurity::RevertToSelf
  268. //
  269. // Returns S_OK or E_FAIL.
  270. // Returns E_NOTIMPL on Win9x platforms.
  271. //
  272. //***************************************************************************
  273. // ok
  274. HRESULT STDMETHODCALLTYPE CWbemCallSecurity::RevertToSelf( void)
  275. {
  276. #ifdef WMI_PRIVATE_DBG
  277. _DBG_ASSERT(m_currentThreadID == GetCurrentThreadId() || m_currentThreadID == 0);
  278. m_currentThreadID = 0;
  279. m_lastRevert = GetCurrentThreadId();
  280. #endif
  281. if (m_dwActiveImpLevel == 0)
  282. return S_OK;
  283. if (m_dwPotentialImpLevel == 0)
  284. return (ERROR_CANT_OPEN_ANONYMOUS | 0x80070000);
  285. // If here,we are impersonating and can definitely revert.
  286. // =======================================================
  287. BOOL bRes = SetThreadToken(NULL, NULL);
  288. if (bRes == FALSE)
  289. return E_FAIL;
  290. m_dwActiveImpLevel = 0; // No longer actively impersonating
  291. return S_OK;
  292. }
  293. //***************************************************************************
  294. //
  295. // CWbemCallSecurity::IsImpersonating
  296. //
  297. //***************************************************************************
  298. BOOL STDMETHODCALLTYPE CWbemCallSecurity::IsImpersonating( void)
  299. {
  300. #ifdef WMI_PRIVATE_DBG
  301. #ifdef DBG
  302. IServerSecurity * privateDbgCallSec = NULL;
  303. CoGetCallContext(IID_IUnknown,(void **)&privateDbgCallSec);
  304. if (m_dwActiveImpLevel && privateDbgCallSec == this)
  305. {
  306. HANDLE hToken = NULL;
  307. BOOL bRes = OpenThreadToken(GetCurrentThread(),TOKEN_QUERY,TRUE,&hToken);
  308. _DBG_ASSERT(bRes);
  309. if (hToken) CloseHandle(hToken);
  310. };
  311. if (privateDbgCallSec) privateDbgCallSec->Release();
  312. #endif
  313. #endif
  314. if (m_hThreadToken && m_dwActiveImpLevel != 0)
  315. return TRUE;
  316. return FALSE;
  317. }
  318. //***************************************************************************
  319. //
  320. // CWbemCallSecurity::CreateInst
  321. //
  322. // Creates a new instance
  323. //***************************************************************************
  324. // ok
  325. IWbemCallSecurity * CWbemCallSecurity::CreateInst()
  326. {
  327. return (IWbemCallSecurity *) new CWbemCallSecurity; // Constructed with ref count of 1
  328. }
  329. //***************************************************************************
  330. //
  331. // CWbemCallSecurity::GetPotentialImpersonation
  332. //
  333. // Returns 0 if no impersonation is currently possible or the
  334. // level which would be active during impersonation:
  335. //
  336. // RPC_C_IMP_LEVEL_ANONYMOUS
  337. // RPC_C_IMP_LEVEL_IDENTIFY
  338. // RPC_C_IMP_LEVEL_IMPERSONATE
  339. // RPC_C_IMP_LEVEL_DELEGATE
  340. //
  341. //***************************************************************************
  342. // ok
  343. HRESULT CWbemCallSecurity::GetPotentialImpersonation()
  344. {
  345. return m_dwPotentialImpLevel;
  346. }
  347. //***************************************************************************
  348. //
  349. // CWbemCallSecurity::GetActiveImpersonation
  350. //
  351. // Returns 0 if no impersonation is currently active or the
  352. // currently active level:
  353. //
  354. // RPC_C_IMP_LEVEL_ANONYMOUS
  355. // RPC_C_IMP_LEVEL_IDENTIFY
  356. // RPC_C_IMP_LEVEL_IMPERSONATE
  357. // RPC_C_IMP_LEVEL_DELEGATE
  358. //
  359. //***************************************************************************
  360. // ok
  361. HRESULT CWbemCallSecurity::GetActiveImpersonation()
  362. {
  363. return m_dwActiveImpLevel;
  364. }
  365. //***************************************************************************
  366. //
  367. // CWbemCallSecurity::CloneThreadContext
  368. //
  369. // Call this on a thread to retrieve the potential impersonation info for
  370. // that thread and set the current object to be able to duplicate it later.
  371. //
  372. // Return codes:
  373. //
  374. // S_OK
  375. // E_FAIL
  376. // E_NOTIMPL on Win9x
  377. // E_ABORT if the calling thread is already impersonating a client.
  378. //
  379. //***************************************************************************
  380. HRESULT CWbemCallSecurity::CloneThreadContext(BOOL bInternallyIssued)
  381. {
  382. if (m_hThreadToken) // Already called this
  383. return E_ABORT;
  384. // Get the current context.
  385. // ========================
  386. IServerSecurity *pSec = 0;
  387. HRESULT hRes = WbemCoGetCallContext(IID_IServerSecurity, (LPVOID *) &pSec);
  388. CReleaseMe rmSec(pSec);
  389. if (hRes != S_OK)
  390. {
  391. // There is no call context --- this must be an in-proc object calling
  392. // us from its own thread. Initialize from current thread token
  393. // ===================================================================
  394. return CloneThreadToken();
  395. }
  396. // Figure out if the call context is ours or RPCs
  397. // ==============================================
  398. IWbemCallSecurity* pInternal = NULL;
  399. if(SUCCEEDED(pSec->QueryInterface(IID_IWbemCallSecurity,
  400. (void**)&pInternal)))
  401. {
  402. CReleaseMe rmInt(pInternal);
  403. // This is our own call context --- this must be ab in-proc object
  404. // calling us from our thread. Behave depending on the flags
  405. // ===============================================================
  406. if(bInternallyIssued)
  407. {
  408. // Internal requests always propagate context. Therefore, we just
  409. // copy the context that we have got
  410. // ==============================================================
  411. try
  412. {
  413. *this = *(CWbemCallSecurity*)pInternal;
  414. return S_OK;
  415. }
  416. catch (CX_Exception &)
  417. {
  418. return WBEM_E_OUT_OF_MEMORY;
  419. }
  420. }
  421. else
  422. {
  423. // Provider request --- Initialize from the current thread token
  424. // =============================================================
  425. return CloneThreadToken();
  426. }
  427. }
  428. // If here, we are not impersonating and we want to gather info
  429. // about the client's call.
  430. // ============================================================
  431. RPC_AUTHZ_HANDLE hAuth;
  432. DWORD t_ImpLevel = 0 ;
  433. hRes = pSec->QueryBlanket(
  434. &m_dwAuthnSvc,
  435. &m_dwAuthzSvc,
  436. &m_pServerPrincNam,
  437. &m_dwAuthnLevel,
  438. &t_ImpLevel,
  439. &hAuth, // RPC_AUTHZ_HANDLE
  440. NULL // Capabilities; not used
  441. );
  442. if(FAILED(hRes))
  443. {
  444. // In some cases, we cant get the name, but the rest is ok. In particular
  445. // the temporary SMS accounts have that property. Or nt 4 after IPCONFIG /RELEASE
  446. hRes = pSec->QueryBlanket(
  447. &m_dwAuthnSvc,
  448. &m_dwAuthzSvc,
  449. &m_pServerPrincNam,
  450. &m_dwAuthnLevel,
  451. &t_ImpLevel,
  452. NULL, // RPC_AUTHZ_HANDLE
  453. NULL // Capabilities; not used
  454. );
  455. hAuth = NULL;
  456. }
  457. if(FAILED(hRes))
  458. {
  459. // THIS IS A WORKAROUND FOR COM BUG:
  460. // This failure is indicative of an anonymous-level client.
  461. // ========================================================
  462. m_dwPotentialImpLevel = 0;
  463. return S_OK;
  464. }
  465. if (hAuth)
  466. {
  467. size_t tmpLenght = wcslen(LPWSTR(hAuth)) + 1;
  468. m_pIdentity = LPWSTR(CoTaskMemAlloc(tmpLenght * (sizeof wchar_t)));
  469. if(m_pIdentity)
  470. StringCchCopyW(m_pIdentity, tmpLenght , LPWSTR(hAuth));
  471. }
  472. // Impersonate the client long enough to clone the thread token.
  473. // =============================================================
  474. BOOL bImp = pSec->IsImpersonating();
  475. if(!bImp)
  476. hRes = pSec->ImpersonateClient();
  477. if (FAILED(hRes))
  478. {
  479. if(!bImp)
  480. pSec->RevertToSelf();
  481. return E_FAIL;
  482. }
  483. HRESULT hres = CloneThreadToken();
  484. if(!bImp)
  485. pSec->RevertToSelf();
  486. return hres;
  487. }
  488. void AdjustPrivIfLocalSystem(HANDLE hPrimary)
  489. {
  490. ////////////////////
  491. // if we are in LocalSystem, enable all the privileges here
  492. // to prevent the AdjustTokenPrivileges call done
  493. // when ESS calls into WmiPrvSe, and preventing WmiPrvSe to
  494. // build a HUGE LRPC_SCONTEXT dictionary
  495. // from now on, if we fail, we bail out with success,
  496. // since the Token Duplication has succeeded
  497. DWORD dwSize = sizeof(TOKEN_USER)+sizeof(SID)+(SID_MAX_SUB_AUTHORITIES*sizeof(DWORD));
  498. BYTE Array[sizeof(TOKEN_USER)+sizeof(SID)+(SID_MAX_SUB_AUTHORITIES*sizeof(DWORD))];
  499. TOKEN_USER * pTokenUser = (TOKEN_USER *)Array;
  500. BOOL bRet = GetTokenInformation(hPrimary,TokenUser,pTokenUser,dwSize,&dwSize);
  501. if (!bRet) return;
  502. SID SystemSid = { SID_REVISION,
  503. 1,
  504. SECURITY_NT_AUTHORITY,
  505. SECURITY_LOCAL_SYSTEM_RID
  506. };
  507. PSID pSIDUser = pTokenUser->User.Sid;
  508. DWORD dwUserSidLen = GetLengthSid(pSIDUser);
  509. DWORD dwSystemSid = GetLengthSid(&SystemSid);
  510. BOOL bIsSystem = FALSE;
  511. if (dwUserSidLen == dwSystemSid)
  512. {
  513. bIsSystem = (0 == memcmp(&SystemSid,pSIDUser,dwUserSidLen));
  514. };
  515. if (bIsSystem) // enable all the priviliges
  516. {
  517. DWORD dwReturnedLength = 0;
  518. if (FALSE == GetTokenInformation(hPrimary,TokenPrivileges,NULL,0,&dwReturnedLength))
  519. {
  520. if (ERROR_INSUFFICIENT_BUFFER != GetLastError()) return;
  521. }
  522. BYTE * pBufferPriv = (BYTE *)LocalAlloc(0,dwReturnedLength);
  523. if (NULL == pBufferPriv) return;
  524. OnDelete<HLOCAL,HLOCAL(*)(HLOCAL),LocalFree> FreeMe(pBufferPriv);
  525. bRet = GetTokenInformation(hPrimary,TokenPrivileges,pBufferPriv,dwReturnedLength,&dwReturnedLength);
  526. if (!bRet) return;
  527. TOKEN_PRIVILEGES *pPrivileges = ( TOKEN_PRIVILEGES * ) pBufferPriv ;
  528. BOOL bNeedToAdjust = FALSE;
  529. for ( ULONG lIndex = 0; lIndex < pPrivileges->PrivilegeCount ; lIndex ++ )
  530. {
  531. if (!(pPrivileges->Privileges [lIndex].Attributes & SE_PRIVILEGE_ENABLED))
  532. {
  533. bNeedToAdjust = TRUE;
  534. pPrivileges->Privileges[lIndex].Attributes |= SE_PRIVILEGE_ENABLED ;
  535. }
  536. }
  537. if (bNeedToAdjust)
  538. {
  539. bRet = AdjustTokenPrivileges (hPrimary, FALSE, pPrivileges,0,NULL,NULL);
  540. }
  541. if ( !bRet) return;
  542. }
  543. }
  544. HRESULT CWbemCallSecurity::CloneThreadToken()
  545. {
  546. HANDLE hPrimary = 0 ;
  547. HANDLE hToken = 0;
  548. BOOL bRes = OpenThreadToken(
  549. GetCurrentThread(),
  550. TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE,
  551. TRUE,
  552. &hToken
  553. );
  554. if (bRes == FALSE)
  555. {
  556. m_hThreadToken = NULL;
  557. m_dwAuthnSvc = RPC_C_AUTHN_WINNT;
  558. m_dwAuthzSvc = RPC_C_AUTHZ_NONE;
  559. m_dwAuthnLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
  560. m_pServerPrincNam = NULL;
  561. m_pIdentity = NULL;
  562. long lRes = GetLastError();
  563. if(lRes == ERROR_NO_IMPERSONATION_TOKEN || lRes == ERROR_NO_TOKEN)
  564. {
  565. // This is the basic process thread.
  566. // =================================
  567. bRes = OpenProcessToken(GetCurrentProcess(),
  568. TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE,
  569. &hPrimary);
  570. if (bRes==FALSE)
  571. {
  572. // Unknown error
  573. // =============
  574. m_dwPotentialImpLevel = 0;
  575. return E_FAIL;
  576. }
  577. }
  578. else if(lRes == ERROR_CANT_OPEN_ANONYMOUS)
  579. {
  580. // Anonymous call
  581. // ==============
  582. m_dwPotentialImpLevel = 0;
  583. return S_OK;
  584. }
  585. else
  586. {
  587. // Unknown error
  588. // =============
  589. m_dwPotentialImpLevel = 0;
  590. return E_FAIL;
  591. }
  592. }
  593. // Find out token info.
  594. // =====================
  595. SECURITY_IMPERSONATION_LEVEL t_Level = SecurityImpersonation ;
  596. if ( hToken )
  597. {
  598. DWORD dwBytesReturned = 0;
  599. bRes = GetTokenInformation (
  600. hToken,
  601. TokenImpersonationLevel,
  602. ( void * ) & t_Level,
  603. sizeof ( t_Level ),
  604. &dwBytesReturned
  605. );
  606. if (bRes == FALSE)
  607. {
  608. CloseHandle(hToken);
  609. return E_FAIL;
  610. }
  611. }
  612. switch (t_Level)
  613. {
  614. case SecurityAnonymous:
  615. m_dwPotentialImpLevel = RPC_C_IMP_LEVEL_ANONYMOUS;
  616. break;
  617. case SecurityIdentification:
  618. m_dwPotentialImpLevel = RPC_C_IMP_LEVEL_IDENTIFY;
  619. break;
  620. case SecurityImpersonation:
  621. m_dwPotentialImpLevel = RPC_C_IMP_LEVEL_IMPERSONATE;
  622. break;
  623. case SecurityDelegation:
  624. m_dwPotentialImpLevel = RPC_C_IMP_LEVEL_DELEGATE;
  625. break;
  626. default:
  627. m_dwPotentialImpLevel = 0;
  628. break;
  629. }
  630. // Duplicate the handle.
  631. // ============================
  632. bRes = DuplicateToken (
  633. hToken ? hToken : hPrimary ,
  634. (SECURITY_IMPERSONATION_LEVEL)t_Level,
  635. &m_hThreadToken
  636. );
  637. if ( hToken )
  638. {
  639. CloseHandle(hToken);
  640. }
  641. else
  642. {
  643. CloseHandle(hPrimary);
  644. }
  645. if (bRes == FALSE)
  646. return E_FAIL;
  647. AdjustPrivIfLocalSystem(m_hThreadToken);
  648. return S_OK;
  649. }
  650. RELEASE_ME CWbemCallSecurity* CWbemCallSecurity::MakeInternalCopyOfThread()
  651. {
  652. IServerSecurity* pSec;
  653. HRESULT hres = WbemCoGetCallContext(IID_IServerSecurity, (void**)&pSec);
  654. if(FAILED(hres))
  655. return NULL;
  656. CReleaseMe rm1(pSec);
  657. IServerSecurity* pIntSec;
  658. hres = pSec->QueryInterface(IID_IWbemCallSecurity, (void**)&pIntSec);
  659. if(FAILED(hres))
  660. return NULL;
  661. CWbemCallSecurity* pCopy = new CWbemCallSecurity;
  662. if (pCopy)
  663. *pCopy = *(CWbemCallSecurity*)pIntSec;
  664. pIntSec->Release();
  665. return pCopy;
  666. }
  667. DWORD CWbemCallSecurity::GetAuthenticationId(LUID& rluid)
  668. {
  669. if(m_hThreadToken == NULL)
  670. return ERROR_INVALID_HANDLE;
  671. TOKEN_STATISTICS stat;
  672. DWORD dwRet;
  673. if(!GetTokenInformation(m_hThreadToken, TokenStatistics,
  674. (void*)&stat, sizeof(stat), &dwRet))
  675. {
  676. return GetLastError();
  677. }
  678. rluid = stat.AuthenticationId;
  679. return 0;
  680. }
  681. HANDLE CWbemCallSecurity::GetToken()
  682. {
  683. return m_hThreadToken;
  684. }
  685. HRESULT RetrieveSidFromCall(CNtSid & sid)
  686. {
  687. HANDLE hToken;
  688. HRESULT hres;
  689. BOOL bRes;
  690. // Check if we are on an impersonated thread
  691. // =========================================
  692. bRes = OpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE, &hToken);
  693. if(bRes)
  694. {
  695. // We are --- just use this token for authentication
  696. // =================================================
  697. hres = RetrieveSidFromToken(hToken, sid);
  698. CloseHandle(hToken);
  699. return hres;
  700. }
  701. // Construct CWbemCallSecurity that will determine (according to our
  702. // non-trivial provider handling rules) the security context of this
  703. // call
  704. // =================================================================
  705. IWbemCallSecurity* pServerSec = CWbemCallSecurity::CreateInst();
  706. if(pServerSec == NULL)
  707. return WBEM_E_OUT_OF_MEMORY;
  708. CReleaseMe rm1(pServerSec);
  709. hres = pServerSec->CloneThreadContext(FALSE);
  710. if(FAILED(hres))
  711. return hres;
  712. // Impersonate client
  713. // ==================
  714. hres = pServerSec->ImpersonateClient();
  715. if(FAILED(hres))
  716. return hres;
  717. // Open impersonated token
  718. // =======================
  719. bRes = OpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE, &hToken);
  720. if(!bRes)
  721. {
  722. long lRes = GetLastError();
  723. if(lRes == ERROR_NO_IMPERSONATION_TOKEN || lRes == ERROR_NO_TOKEN)
  724. {
  725. // Not impersonating --- get the process token instead
  726. // ===================================================
  727. bRes = OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hToken);
  728. if(!bRes)
  729. {
  730. pServerSec->RevertToSelf();
  731. return WBEM_E_ACCESS_DENIED;
  732. }
  733. }
  734. else
  735. {
  736. // Real problems
  737. // =============
  738. pServerSec->RevertToSelf();
  739. return WBEM_E_ACCESS_DENIED;
  740. }
  741. }
  742. hres = RetrieveSidFromToken(hToken, sid);
  743. CloseHandle(hToken);
  744. pServerSec->RevertToSelf();
  745. return hres;
  746. }
  747. HRESULT RetrieveSidFromToken(HANDLE hToken, CNtSid & sid)
  748. {
  749. // Retrieve the length of the user sid structure
  750. BOOL bRes;
  751. struct TOKEN_USER_ : TOKEN_USER {
  752. SID RealSid;
  753. DWORD SubAuth[SID_MAX_SUB_AUTHORITIES];
  754. } tu;
  755. DWORD dwLen = sizeof(tu);
  756. bRes = GetTokenInformation(hToken, TokenUser, &tu, sizeof(tu), &dwLen);
  757. if(FALSE == bRes) return WBEM_E_CRITICAL_ERROR;
  758. TOKEN_USER* pUser = (TOKEN_USER*)&tu;
  759. // Set our sid to the returned one
  760. sid = CNtSid(pUser->User.Sid);
  761. return WBEM_S_NO_ERROR;
  762. }
  763. //
  764. //
  765. //
  766. ///////////////////////////////////////////////
  767. CIdentitySecurity::CIdentitySecurity()
  768. {
  769. SID SystemSid = { SID_REVISION,
  770. 1,
  771. SECURITY_NT_AUTHORITY,
  772. SECURITY_LOCAL_SYSTEM_RID
  773. };
  774. CNtSid tempSystem((PSID)&SystemSid);
  775. m_sidSystem = tempSystem;
  776. if (!m_sidSystem.IsValid())
  777. throw CX_Exception();
  778. HRESULT hres = RetrieveSidFromCall(m_sidUser);
  779. if(FAILED(hres))
  780. throw CX_Exception();
  781. }
  782. CIdentitySecurity::~CIdentitySecurity()
  783. {
  784. }
  785. HRESULT
  786. CIdentitySecurity::GetSidFromThreadOrProcess(/*out*/ CNtSid & UserSid)
  787. {
  788. HANDLE hToken = NULL;
  789. BOOL bRet = OpenThreadToken(GetCurrentThread(),TOKEN_QUERY, TRUE, &hToken);
  790. if (FALSE == bRet)
  791. {
  792. long lRes = GetLastError();
  793. if(ERROR_NO_IMPERSONATION_TOKEN == lRes || ERROR_NO_TOKEN == lRes)
  794. {
  795. bRet = OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY,&hToken);
  796. if (FALSE == bRet) HRESULT_FROM_WIN32(GetLastError());
  797. }
  798. else
  799. return HRESULT_FROM_WIN32(GetLastError());
  800. }
  801. OnDelete<HANDLE,BOOL(*)(HANDLE),CloseHandle> CloseMe(hToken);
  802. DWORD dwSize = sizeof(TOKEN_USER)+sizeof(SID)+(SID_MAX_SUB_AUTHORITIES*sizeof(DWORD));
  803. BYTE Array[sizeof(TOKEN_USER)+sizeof(SID)+(SID_MAX_SUB_AUTHORITIES*sizeof(DWORD))];
  804. TOKEN_USER * pTokenUser = (TOKEN_USER *)Array;
  805. bRet = GetTokenInformation(hToken,TokenUser,pTokenUser,dwSize,&dwSize);
  806. if (!bRet) return HRESULT_FROM_WIN32(GetLastError());
  807. PSID pSIDUser = pTokenUser->User.Sid;
  808. CNtSid tempSid(pSIDUser);
  809. UserSid = tempSid;
  810. if (UserSid.IsValid())
  811. return S_OK;
  812. else
  813. return WBEM_E_OUT_OF_MEMORY;
  814. }
  815. HRESULT
  816. CIdentitySecurity::RetrieveSidFromCall(/*out*/ CNtSid & UserSid)
  817. {
  818. HRESULT hr;
  819. IServerSecurity * pCallSec = NULL;
  820. if (S_OK == CoGetCallContext(IID_IServerSecurity,(void **)&pCallSec))
  821. {
  822. OnDelete<IUnknown *,void(*)(IUnknown *),RM> dm(pCallSec);
  823. if (pCallSec->IsImpersonating())
  824. return GetSidFromThreadOrProcess(UserSid);
  825. else
  826. {
  827. RETURN_ON_ERR(pCallSec->ImpersonateClient());
  828. OnDeleteObj0<IServerSecurity ,
  829. HRESULT(__stdcall IServerSecurity:: * )(void),
  830. &IServerSecurity::RevertToSelf> RevertSec(pCallSec);
  831. return GetSidFromThreadOrProcess(UserSid);
  832. }
  833. }
  834. else
  835. return GetSidFromThreadOrProcess(UserSid);
  836. }
  837. BOOL CIdentitySecurity::AccessCheck()
  838. {
  839. // Find out who is calling
  840. // =======================
  841. CNtSid sidCaller;
  842. HRESULT hres = RetrieveSidFromCall(sidCaller);
  843. if(FAILED(hres))
  844. return FALSE;
  845. // Compare the caller to the issuing user and ourselves
  846. // ====================================================
  847. if(sidCaller == m_sidUser || sidCaller == m_sidSystem)
  848. return TRUE;
  849. else
  850. return FALSE;
  851. }