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.

712 lines
22 KiB

  1. //***************************************************************************
  2. //
  3. // (c) 2000-2001 by Microsoft Corp. All Rights Reserved.
  4. //
  5. // repsecurity.cpp
  6. //
  7. // a-davcoo 25-Jan-00 Created to house repository security
  8. // functionality.
  9. //
  10. //***************************************************************************
  11. #define _REPSECURITY_CPP_
  12. #pragma warning( disable : 4786 ) // identifier was truncated to 'number' characters in the
  13. #pragma warning( disable : 4251 ) // needs to have dll-interface to be used by clients of class
  14. #define DBINITCONSTANTS // Initialize OLE constants...
  15. #define INITGUID // ...once in each app.
  16. #define _WIN32_DCOM
  17. #include "precomp.h"
  18. #include <std.h>
  19. #include <sqlexec.h>
  20. #include <repdrvr.h>
  21. #include <wbemint.h>
  22. #include <math.h>
  23. #include <resource.h>
  24. #include <reputils.h>
  25. #include <crc64.h>
  26. #include <smrtptr.h>
  27. #include <winntsec.h>
  28. //***************************************************************************
  29. //
  30. // CWmiDbSession::GetObjectSecurity
  31. //
  32. //***************************************************************************
  33. HRESULT CWmiDbSession::GetObjectSecurity (CSQLConnection *pConn, SQL_ID dObjectId, PNTSECURITY_DESCRIPTOR *ppSD, DWORD dwSDLength,
  34. DWORD dwFlags, BOOL &bHasDacl)
  35. {
  36. HRESULT hr = WBEM_S_NO_ERROR;
  37. // Retrieve this object and populate the SD.
  38. bHasDacl = FALSE;
  39. // See if this ID even has an SD.
  40. if (!((CWmiDbController *)m_pController)->HasSecurityDescriptor(dObjectId))
  41. return WBEM_S_NO_ERROR;
  42. if(IsInAdminGroup())
  43. return WBEM_S_NO_ERROR;
  44. BOOL bNeedToRel = FALSE;
  45. if (!pConn)
  46. {
  47. hr = GetSQLCache()->GetConnection(&pConn, FALSE, FALSE);
  48. bNeedToRel = TRUE;
  49. }
  50. if (SUCCEEDED(hr))
  51. {
  52. PNTSECURITY_DESCRIPTOR pSD = NULL;
  53. // For now, we will never cache the __SECURITY_DESCRIPTOR property. Always
  54. // retrieve it from a proc call.
  55. hr = CSQLExecProcedure::GetSecurityDescriptor(pConn, dObjectId, &pSD, dwSDLength, dwFlags);
  56. if (hr == WBEM_E_NOT_FOUND)
  57. {
  58. bHasDacl = FALSE;
  59. hr = WBEM_S_NO_ERROR;
  60. }
  61. else
  62. {
  63. PACL pDACL=NULL;
  64. BOOL bDefaulted, bTemp;
  65. BOOL bSuccess=GetSecurityDescriptorDacl (pSD, &bTemp, &pDACL, &bDefaulted);
  66. if (!bSuccess)
  67. {
  68. hr = WBEM_E_FAILED;
  69. }
  70. else
  71. {
  72. bHasDacl = (bTemp && pDACL!=NULL);
  73. }
  74. }
  75. if (bHasDacl)
  76. *ppSD = pSD;
  77. else
  78. {
  79. *ppSD = NULL;
  80. delete pSD;
  81. }
  82. if (bNeedToRel)
  83. GetSQLCache()->ReleaseConnection(pConn, hr, FALSE);
  84. }
  85. return hr;
  86. }
  87. //***************************************************************************
  88. //
  89. // CWmiDbSession::VerifyObjectSecurity()
  90. //
  91. // This method verifies that the caller has the requested access to the
  92. // target object. If the reqested access can be granted, a successfull
  93. // result is returned. If not, WBEM_E_ACCESS_DENIED is returned. This
  94. // method will check the entire security inheritance tree, as required.
  95. //
  96. //***************************************************************************
  97. HRESULT CWmiDbSession::VerifyObjectSecurity(CSQLConnection *pConn, IWmiDbHandle __RPC_FAR *pTarget,
  98. DWORD AccessType)
  99. {
  100. CWmiDbHandle *pObject=(CWmiDbHandle *)pTarget;
  101. HRESULT hr=VerifyObjectSecurity (pConn, pObject->m_dObjectId, pObject->m_dClassId,
  102. pObject->m_dScopeId, 0, AccessType);
  103. return hr;
  104. }
  105. //***************************************************************************
  106. //
  107. // CWmiDbSession::VerifyObjectSecurity()
  108. //
  109. // This method verifies that the caller has the requested access to the
  110. // target object. If the reqested access can be granted, a successfull
  111. // result is returned. If not, WBEM_E_ACCESS_DENIED is returned. This
  112. // method will check the entire security inheritance tree, as required.
  113. // The ScopeId and ScopeClassId are allowed to be 0 when calling this
  114. // method.
  115. //
  116. //***************************************************************************
  117. HRESULT CWmiDbSession::VerifyObjectSecurity(CSQLConnection *pConn,
  118. SQL_ID ObjectId,
  119. SQL_ID ClassId,
  120. SQL_ID ScopeId,
  121. SQL_ID ScopeClassId,
  122. DWORD AccessType)
  123. {
  124. // Validate the state of the session and initialize the schema cache if required.
  125. if (!m_pController || ((CWmiDbController *)m_pController)->m_dwCurrentStatus == WBEM_E_SHUTTING_DOWN)
  126. {
  127. return WBEM_E_SHUTTING_DOWN;
  128. }
  129. if (!((CWmiDbController *)m_pController)->m_bCacheInit)
  130. {
  131. HRESULT hr=LoadSchemaCache();
  132. if (SUCCEEDED(hr))
  133. ((CWmiDbController *)m_pController)->m_bCacheInit=TRUE;
  134. else
  135. return hr;
  136. }
  137. // Obtain the object's effective security descriptor and see if access to the object
  138. // is granted. Access to administrators is always granted.
  139. HRESULT hr=WBEM_S_NO_ERROR;
  140. if (!((CWmiDbController *)m_pController)->m_bIsAdmin)
  141. {
  142. PNTSECURITY_DESCRIPTOR pSD=NULL;
  143. DWORD dwSDLength;
  144. hr=GetEffectiveObjectSecurity (pConn, ObjectId, ClassId, ScopeId, ScopeClassId, &pSD, dwSDLength);
  145. if (SUCCEEDED(hr) && pSD)
  146. {
  147. BOOL bHasDACL;
  148. hr=AccessCheck (pSD, AccessType, bHasDACL);
  149. delete pSD;
  150. }
  151. }
  152. return hr;
  153. }
  154. //***************************************************************************
  155. //
  156. // CWmiDbSession::VerifyObjectSecurity()
  157. //
  158. // Used internally to the repository driver, currently only by PutObject().
  159. //
  160. //***************************************************************************
  161. HRESULT CWmiDbSession::VerifyObjectSecurity(CSQLConnection *pConn,
  162. SQL_ID dScopeID,
  163. SQL_ID dScopeClassId,
  164. LPWSTR lpObjectPath,
  165. CWbemClassObjectProps *pProps,
  166. DWORD dwHandleType,
  167. DWORD dwReqAccess,
  168. SQL_ID &dObjectId,
  169. SQL_ID &dClassId)
  170. {
  171. // Validate the state of the session and initialize the schema cache if required.
  172. if (!m_pController || ((CWmiDbController *)m_pController)->m_dwCurrentStatus == WBEM_E_SHUTTING_DOWN)
  173. {
  174. return WBEM_E_SHUTTING_DOWN;
  175. }
  176. if (!((CWmiDbController *)m_pController)->m_bCacheInit)
  177. {
  178. HRESULT hr=LoadSchemaCache();
  179. if (SUCCEEDED(hr))
  180. ((CWmiDbController *)m_pController)->m_bCacheInit=TRUE;
  181. else
  182. return hr;
  183. }
  184. // If we have an objectid, then the security has already been validated. We can just
  185. // return the classid.
  186. HRESULT hr=WBEM_S_NO_ERROR;
  187. if (dObjectId && !dClassId)
  188. {
  189. hr=GetSchemaCache()->GetClassID(pProps->lpClassName, dScopeID, dClassId);
  190. }
  191. else
  192. {
  193. // Otherwise, we don't have an objectid and we'll need to get it from the database
  194. // or from the schema cache.
  195. hr=GetSchemaCache()->GetClassID(pProps->lpClassName, dScopeID, dClassId);
  196. if (pProps->dwGenus==WBEM_GENUS_CLASS)
  197. {
  198. dObjectId=dClassId;
  199. }
  200. // Make sure the parent class isn't locked.
  201. if (!dClassId)
  202. {
  203. hr=GetSchemaCache()->GetClassID(pProps->lpSuperClass, dScopeID, dClassId);
  204. }
  205. // If not found, make sure we can access the class.
  206. BOOL bNewObj=(!dObjectId);
  207. if (bNewObj)
  208. {
  209. hr=VerifyClassSecurity(pConn, dClassId, dwReqAccess);
  210. }
  211. else
  212. {
  213. hr=VerifyObjectSecurity(pConn, dObjectId, dClassId, dScopeID, dScopeClassId, dwReqAccess);
  214. if (SUCCEEDED(hr))
  215. {
  216. // Make sure we aren't blocked by any other handle type.
  217. bool bImmediate=!((dwHandleType & 0xF0000000)==WMIDB_HANDLE_TYPE_SUBSCOPED);
  218. hr=((CWmiDbController *)m_pController)->LockCache.AddLock(bImmediate, dObjectId, WMIDB_HANDLE_TYPE_EXCLUSIVE, NULL,
  219. dScopeID, dClassId, &((CWmiDbController *)m_pController)->SchemaCache, false, 0, 0);
  220. if (SUCCEEDED(hr))
  221. {
  222. hr=((CWmiDbController *)m_pController)->LockCache.DeleteLock(dObjectId, false, WMIDB_HANDLE_TYPE_EXCLUSIVE);
  223. }
  224. }
  225. }
  226. }
  227. // Done.
  228. return hr;
  229. }
  230. //***************************************************************************
  231. //
  232. // CWmiDbSession::VerifyClassSecurity()
  233. //
  234. // This method verifies that the caller has the requested access to the
  235. // target class. If the reqested access can be granted, a successfull
  236. // result is returned. If not, WBEM_E_ACCESS_DENIED is returned. This
  237. // method will check the entire security inheritance tree, as required.
  238. //
  239. //***************************************************************************
  240. HRESULT CWmiDbSession::VerifyClassSecurity(CSQLConnection *pConn,
  241. SQL_ID ClassId,
  242. DWORD AccessType)
  243. {
  244. return VerifyObjectSecurity (pConn, ClassId, 1, 0, 0, AccessType);
  245. }
  246. //***************************************************************************
  247. //
  248. // CWmiDbSession::GetEffectiveObjectSecurity()
  249. //
  250. // This method searches for the SD which should be applied to verification
  251. // of access against the specified object. This SD could be the one directly
  252. // associated with the object, or if the object does not have a SD with a
  253. // DACL, it will be the inherited SD. Note, ScopeId and ScopeClassId can
  254. // be 0 when calling this function.
  255. //
  256. //***************************************************************************
  257. HRESULT CWmiDbSession::GetEffectiveObjectSecurity(CSQLConnection *pConn,
  258. SQL_ID ObjectId,
  259. SQL_ID ClassId,
  260. SQL_ID ScopeId,
  261. SQL_ID ScopeClassId,
  262. PNTSECURITY_DESCRIPTOR *ppSD,
  263. DWORD &dwSDLength
  264. )
  265. {
  266. // Attempt to get the security descriptor directly associated with the object.
  267. HRESULT hr = 0;
  268. BOOL bHasDACL;
  269. if (ClassId == 1)
  270. hr = GetObjectSecurity (pConn, ObjectId, ppSD, dwSDLength, WMIDB_SECURITY_FLAG_CLASS, bHasDACL);
  271. else
  272. hr = GetObjectSecurity (pConn, ObjectId, ppSD, dwSDLength, WMIDB_SECURITY_FLAG_INSTANCE, bHasDACL);
  273. // If the object did not have a security descriptor, get it's inherited security descriptor.
  274. if (SUCCEEDED(hr) && !bHasDACL)
  275. {
  276. hr=GetInheritedObjectSecurity (pConn, ObjectId, ClassId, ScopeId, ScopeClassId, ppSD, dwSDLength);
  277. }
  278. // Done.
  279. return hr;
  280. }
  281. //***************************************************************************
  282. //
  283. // CWmiDbSession::GetInheritedObjectSecurity()
  284. //
  285. // This method determines what security descriptor (if any) would be
  286. // inherited by a target object, if the target object had no security
  287. // descriptor. Note that ScopeId and ScopeClassId are allowed to be 0
  288. // when calling this method.
  289. //
  290. //***************************************************************************
  291. HRESULT CWmiDbSession::GetInheritedObjectSecurity(CSQLConnection *pConn,
  292. SQL_ID ObjectId,
  293. SQL_ID ClassId,
  294. SQL_ID ScopeId,
  295. SQL_ID ScopeClassId,
  296. PNTSECURITY_DESCRIPTOR *ppSD,
  297. DWORD &dwSDLength)
  298. {
  299. // Determine whether the target object is a class or an instance. Handling
  300. // of instances includes handling of __Instances containers. Note, a target
  301. // with a ClassId of 1 is a class object and the object ID is the class's
  302. // class ID.
  303. HRESULT hr=WBEM_S_NO_ERROR;
  304. if (ClassId==1)
  305. {
  306. hr=GetInheritedClassSecurity (pConn, ObjectId, ScopeId, ScopeClassId, ppSD, dwSDLength);
  307. }
  308. else
  309. {
  310. hr=GetInheritedInstanceSecurity (pConn, ObjectId, ClassId, ScopeId, ScopeClassId, ppSD, dwSDLength);
  311. }
  312. // Done.
  313. return hr;
  314. }
  315. //***************************************************************************
  316. //
  317. // CWmiDbSession::GetInheritedClassSecurity()
  318. //
  319. // This method determines what security descriptor (if any) would be inherited
  320. // by a target class, if the target class had no security descriptor. This
  321. // function will work properly for classes scoped to an object, although this
  322. // isn't currently being supported in the rest of WMI. The ScopeId and the
  323. // ScopeClassId are allowed to be 0 when using this method.
  324. //
  325. //***************************************************************************
  326. HRESULT CWmiDbSession::GetInheritedClassSecurity(CSQLConnection *pConn,
  327. SQL_ID ClassId,
  328. SQL_ID ScopeId,
  329. SQL_ID ScopeClassId,
  330. PNTSECURITY_DESCRIPTOR *ppSD,
  331. DWORD &dwSDLength)
  332. {
  333. // Create some convience variables.
  334. CSchemaCache *pSchema=&((CWmiDbController *)m_pController)->SchemaCache;
  335. // Iterate through the chain of superclasses, until a security descriptor
  336. // is found, or the top-level base class is reached.
  337. HRESULT hr=WBEM_S_NO_ERROR;
  338. bool bTopReached=false;
  339. BOOL bHasDACL = FALSE;
  340. SQL_ID dParentId=ClassId;
  341. do
  342. {
  343. // Attempt to locate the superclass.
  344. hr=pSchema->GetParentId (dParentId, dParentId);
  345. if (SUCCEEDED(hr) && dParentId != 1)
  346. {
  347. hr = GetObjectSecurity(pConn, dParentId, ppSD, dwSDLength, WMIDB_SECURITY_FLAG_CLASS, bHasDACL);
  348. }
  349. else if (hr==WBEM_E_NOT_FOUND || dParentId == 1)
  350. {
  351. // Top of the class hierarchy has been reached.
  352. hr=WBEM_S_NO_ERROR;
  353. bTopReached=true;
  354. }
  355. }
  356. while (SUCCEEDED(hr) && !bTopReached && !bHasDACL);
  357. // If we are at the top of the hierarchy, check security on __Classes for this
  358. // namespace.
  359. if (bTopReached && !bHasDACL)
  360. {
  361. IWmiDbHandle *pClassesObj = NULL;
  362. _bstr_t sName;
  363. if (ScopeId && SUCCEEDED(pSchema->GetNamespaceName(ScopeId, &sName)))
  364. {
  365. sName += L":__Classes=@";
  366. SQL_ID dClassSec = CRC64::GenerateHashValue(sName);
  367. hr = GetObjectSecurity(pConn, dClassSec, ppSD, dwSDLength, 0, bHasDACL);
  368. }
  369. }
  370. // Done.
  371. return hr;
  372. }
  373. //***************************************************************************
  374. //
  375. // CWmiDbSession::GetInheritedInstanceSecurity()
  376. //
  377. // This method determines what security descriptor (if any) would be inher-
  378. // ited by a target instance, if the target instance had no SD. This method
  379. // works for both real instances and instances of __Instances containers.
  380. // The ScopeId and the ScopeClassId are allowed to be 0 when using this
  381. // method.
  382. //
  383. //***************************************************************************
  384. HRESULT CWmiDbSession::GetInheritedInstanceSecurity(CSQLConnection *pConn,
  385. SQL_ID ObjectId,
  386. SQL_ID ClassId,
  387. SQL_ID ScopeId,
  388. SQL_ID ScopeClassId,
  389. PNTSECURITY_DESCRIPTOR *ppSD,
  390. DWORD &dwSDLength)
  391. {
  392. // Setup some convience variables.
  393. CSchemaCache *pSchema=&((CWmiDbController *)m_pController)->SchemaCache;
  394. // See if the target is an __Instances container. If so, it's security is
  395. // inherited from the __Instances containers of parent classes, and finaly
  396. // from it's scoping object (owning namespace).
  397. HRESULT hr=WBEM_S_NO_ERROR;
  398. if (ClassId==INSTANCESCLASSID)
  399. {
  400. hr=GetInheritedContainerSecurity (pConn, ObjectId, ScopeId, ScopeClassId, ppSD, dwSDLength);
  401. }
  402. else
  403. {
  404. // See if the target object is a namespace. If it is, then do not attempt
  405. // to inherit security from parent namespaces. The security inheritance tree
  406. // effictively stops at the first namespace.
  407. /// A-DAVCOO: Of course we should inherit security from the parent namespaces.
  408. /// A-DAVCOO: But, those namespaces might not even be in the same repository.
  409. /// A-DAVCOO: Hence, that case needs to be handled outside of this driver.
  410. if (ClassId!=NAMESPACECLASSID && !pSchema->IsDerivedClass (NAMESPACECLASSID, ClassId))
  411. {
  412. // Determine the parent scope/namespace as well as it's class, if they
  413. // were not supplied by the caller.
  414. if (!ScopeId)
  415. {
  416. // We do not have the scope, so get the scope and it's class.
  417. hr=pSchema->GetParentNamespace (ObjectId, ScopeId, &ScopeClassId);
  418. }
  419. else if (!ScopeClassId)
  420. {
  421. // We have the scope, but not the scope's class.
  422. hr=pSchema->GetNamespaceClass (ScopeId, ScopeClassId);
  423. }
  424. // If the instance is scoped directly to a namespace, then we first walk
  425. // the instance's __Instances container chain. Note, that an __Instances
  426. // container's object ID is the class ID it represents.
  427. if (SUCCEEDED(hr))
  428. {
  429. if (ScopeClassId==NAMESPACECLASSID || pSchema->IsDerivedClass (NAMESPACECLASSID, ScopeClassId))
  430. {
  431. // Check the class's immediate __Instances container.
  432. BOOL bHasDACL;
  433. hr = GetObjectSecurity (pConn, ClassId, ppSD, dwSDLength, WMIDB_SECURITY_FLAG_INSTANCE, bHasDACL);
  434. if (SUCCEEDED(hr))
  435. {
  436. // The class's __Instances container did not supply a DACL, so get
  437. // the __Instances container's inherited security.
  438. hr=GetInheritedContainerSecurity (pConn, ClassId, 0, 0, ppSD, dwSDLength);
  439. }
  440. }
  441. else
  442. {
  443. // The instance is not scoped immediately to a namespace derived class,
  444. // so, check the security of it's scoping object.
  445. BOOL bHasDACL;
  446. hr = GetObjectSecurity (pConn, ScopeId, ppSD, dwSDLength, WMIDB_SECURITY_FLAG_INSTANCE, bHasDACL);
  447. if (SUCCEEDED(hr))
  448. {
  449. // Scoping object had no DACL, so use it's inherited security.
  450. hr=GetInheritedInstanceSecurity (pConn, ScopeId, ScopeClassId, 0, 0, ppSD, dwSDLength);
  451. }
  452. }
  453. }
  454. }
  455. else
  456. {
  457. BOOL bHasDACL = FALSE;
  458. // Check security on this namespace object.
  459. hr = GetObjectSecurity (pConn, ScopeId, ppSD, dwSDLength, WMIDB_SECURITY_FLAG_INSTANCE, bHasDACL);
  460. }
  461. }
  462. // Done.
  463. return hr;
  464. }
  465. //***************************************************************************
  466. //
  467. // CWmiDbSession::GetInheritedContainerSecurity()
  468. //
  469. // This method determines what security descriptor (if any) would be inherited
  470. // by a target __Instances container, if the target container had no security
  471. // descriptor. Note, that as a side effect of the alogrithm used, this method
  472. // will work for __Instances containers scoped to an object as well as to a
  473. // namespace, if such beasts ever exist for the purposes of scoping a class to
  474. // an instance. The ScopeId and the ScopeClassId are allowed to be 0 when
  475. // using this method.
  476. //
  477. //***************************************************************************
  478. HRESULT CWmiDbSession::GetInheritedContainerSecurity(CSQLConnection *pConn,
  479. SQL_ID ClassId,
  480. SQL_ID ScopeId,
  481. SQL_ID ScopeClassId,
  482. PNTSECURITY_DESCRIPTOR *ppSD,
  483. DWORD &dwSDLength)
  484. {
  485. // Setup some convience variables.
  486. CSchemaCache *pSchema=&((CWmiDbController *)m_pController)->SchemaCache;
  487. // Iterate through the chain of superclasses, checking each __Instances
  488. // container for an appropriate security descriptor and DACL.
  489. HRESULT hr=WBEM_S_NO_ERROR;
  490. BOOL bHasDACL=false;
  491. bool bTopReached=false;
  492. SQL_ID dParentId=ClassId;
  493. do
  494. {
  495. // Attempt to locate the superclass.
  496. hr=pSchema->GetParentId (dParentId, dParentId);
  497. if (SUCCEEDED(hr))
  498. {
  499. // A class's class ID is used for it's __Instances conatiner's object ID.
  500. hr = GetObjectSecurity(pConn, dParentId, ppSD, dwSDLength, WMIDB_SECURITY_FLAG_INSTANCE, bHasDACL);
  501. }
  502. else if (hr==WBEM_E_NOT_FOUND)
  503. {
  504. // Top of the class hierarchy has been reached.
  505. hr = WBEM_S_NO_ERROR;
  506. bTopReached = true;
  507. }
  508. }
  509. while (SUCCEEDED(hr) && !bHasDACL && !bTopReached);
  510. return hr;
  511. }
  512. //***************************************************************************
  513. //
  514. // CSecurityCache::AccessCheck()
  515. //
  516. // This function returns a successful result if the requested access to the
  517. // object is granted, an error result if an error occurs while validating
  518. // access, or WMI_E_ACCESS_DENIED if access was sucessfully verified but
  519. // denied.
  520. //
  521. // NOTE: If an object does not have and SD or it has a NULL DACL, access
  522. // is granted, but, bHasDACL is set to FALSE.
  523. //
  524. //***************************************************************************
  525. HRESULT CWmiDbSession::AccessCheck( PNTSECURITY_DESCRIPTOR pSD, DWORD dwAccessType, BOOL &bHasDACL )
  526. {
  527. bHasDACL=TRUE;
  528. // An object without an SD grants all access. The caller should check bHasDACL and
  529. // inherit security as appropriate.
  530. HRESULT hr=WBEM_S_NO_ERROR;
  531. if (pSD==NULL)
  532. {
  533. bHasDACL=FALSE;
  534. }
  535. else
  536. {
  537. // If the object has an SD, but no DACL, then all access is granted. The caller
  538. // should check bHasDACL and propagate the check upwards as necessary.
  539. PACL pDACL=NULL;
  540. BOOL bDefaulted;
  541. BOOL bSuccess=GetSecurityDescriptorDacl (pSD, &bHasDACL, &pDACL, &bDefaulted);
  542. if (!bSuccess)
  543. {
  544. hr=WBEM_E_FAILED;
  545. }
  546. else if (!bHasDACL || pDACL==NULL)
  547. {
  548. bHasDACL=FALSE;
  549. }
  550. else
  551. {
  552. bHasDACL=TRUE;
  553. HRESULT hr2 = CoImpersonateClient();
  554. if (SUCCEEDED(hr))
  555. {
  556. // Because we have called CoImpersonateClient(), the thread will have an access
  557. // token (inferred from Okuntseff, p151). Threads don't have one by default.
  558. HANDLE hClientToken=NULL;
  559. HANDLE hThread = GetCurrentThread();
  560. bSuccess=OpenThreadToken (hThread, TOKEN_READ | TOKEN_QUERY , TRUE, &hClientToken);
  561. if (!bSuccess)
  562. {
  563. DWORD dwRet = GetLastError();
  564. if (dwRet == ERROR_NO_TOKEN)
  565. {
  566. // No thread token. Look at process tokens.
  567. HANDLE hProc = GetCurrentProcess();
  568. HANDLE hProcToken;
  569. bSuccess = OpenProcessToken(hProc, TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE , &hProcToken);
  570. if (bSuccess)
  571. {
  572. bSuccess = DuplicateToken (
  573. hProcToken,
  574. SecurityDelegation ,
  575. & hClientToken
  576. ) ;
  577. CloseHandle ( hProcToken ) ;
  578. }
  579. CloseHandle(hProc);
  580. }
  581. if (!bSuccess)
  582. {
  583. DEBUGTRACE((LOG_WBEMCORE, "OpenThreadToken failed with %ld", dwRet));
  584. hr=WBEM_E_FAILED;
  585. }
  586. }
  587. if (bSuccess)
  588. {
  589. GENERIC_MAPPING accessmap;
  590. DWORD dw1 = 0, dw2 = 1;
  591. accessmap.GenericWrite=0;
  592. accessmap.GenericRead=0;
  593. accessmap.GenericExecute=0;
  594. accessmap.GenericAll=0;
  595. MapGenericMask(&dwAccessType, &accessmap);
  596. PRIVILEGE_SET ps[10];
  597. dw1 = 10 * sizeof(PRIVILEGE_SET);
  598. DWORD PsSize, GrantedAccess;
  599. BOOL AccessStatus;
  600. bSuccess = ::AccessCheck(
  601. pSD, // security descriptor
  602. hClientToken, // handle to client access token
  603. dwAccessType, // requested access rights
  604. &accessmap, // map generic to specific rights
  605. ps, // receives privileges used
  606. &dw1, // size of privilege-set buffer
  607. &dw2, // retrieves mask of granted rights
  608. &AccessStatus // retrieves results of access check
  609. );
  610. if (!bSuccess)
  611. {
  612. DWORD dwRet = GetLastError();
  613. DEBUGTRACE((LOG_WBEMCORE, "AccessCheck failed with %ld", dwRet));
  614. hr=WBEM_E_FAILED;
  615. }
  616. else if (!AccessStatus)
  617. {
  618. hr=WBEM_E_ACCESS_DENIED;
  619. }
  620. CloseHandle (hClientToken);
  621. }
  622. CloseHandle(hThread);
  623. CoRevertToSelf();
  624. }
  625. }
  626. }
  627. return hr;
  628. }