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.

1513 lines
46 KiB

  1. /*++
  2. Copyright (C) 1998-2001 Microsoft Corporation
  3. Module Name:
  4. SECURE.CPP
  5. Abstract:
  6. Contains various routines used for ACL based security.
  7. It is defined in secure.h
  8. History:
  9. a-davj 05-NOV-98 Created.
  10. --*/
  11. #include "precomp.h"
  12. #include <wbemcore.h>
  13. #include <oleauto.h>
  14. #include <genutils.h>
  15. #include <safearry.h>
  16. #include <oahelp.inl>
  17. #include <fcntl.h>
  18. #define WBEM_WMISETUP __TEXT("WMISetup")
  19. // /////////////////////////////////////////////////
  20. AutoRevertSecTlsFlag::AutoRevertSecTlsFlag ( LPVOID dir )
  21. {
  22. m_bDir = dir ;
  23. TlsSetValue ( CCoreQueue::GetSecFlagTlsIndex(), (LPVOID)dir );
  24. }
  25. AutoRevertSecTlsFlag::AutoRevertSecTlsFlag()
  26. {
  27. m_bDir = TlsGetValue ( CCoreQueue::GetSecFlagTlsIndex() ) ;
  28. }
  29. AutoRevertSecTlsFlag::~AutoRevertSecTlsFlag()
  30. {
  31. TlsSetValue ( CCoreQueue::GetSecFlagTlsIndex(), (LPVOID)1 ) ;
  32. }
  33. VOID AutoRevertSecTlsFlag::SetSecTlsFlag ( LPVOID dir )
  34. {
  35. TlsSetValue ( CCoreQueue::GetSecFlagTlsIndex(), (LPVOID)dir );
  36. }
  37. //***************************************************************************
  38. //
  39. // SetOwnerAndGroup
  40. //
  41. // Sets the owner and group of the SD to the Admininstrators group
  42. //
  43. //***************************************************************************
  44. BOOL SetOwnerAndGroup(CNtSecurityDescriptor &sd)
  45. {
  46. PSID pRawSid;
  47. BOOL bRet = FALSE;
  48. SID_IDENTIFIER_AUTHORITY id = SECURITY_NT_AUTHORITY;
  49. if(AllocateAndInitializeSid( &id, 2, // SEC:REVIEWED 2002-03-22 : OK
  50. SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
  51. 0,0,0,0,0,0,&pRawSid))
  52. {
  53. CNtSid SidAdmins(pRawSid);
  54. FreeSid(pRawSid);
  55. if (CNtSid::NoError != SidAdmins.GetStatus()) return FALSE;
  56. bRet = sd.SetGroup(&SidAdmins); // Access check doesnt really care what you put, so long as you
  57. // put something for the owner
  58. if(bRet)
  59. bRet = sd.SetOwner(&SidAdmins);
  60. return bRet;
  61. }
  62. return bRet;
  63. }
  64. //***************************************************************************
  65. //
  66. // CFlexAceArray::~CFlexAceArray()
  67. //
  68. // Cleans up safe array entries.
  69. //
  70. //***************************************************************************
  71. CFlexAceArray::~CFlexAceArray()
  72. {
  73. for(int iCnt = 0; iCnt < Size(); iCnt++)
  74. {
  75. CBaseAce * pace = (CBaseAce *)GetAt(iCnt);
  76. if(pace)
  77. delete pace;
  78. }
  79. Empty();
  80. }
  81. //***************************************************************************
  82. //
  83. // SetStatusAndReturnOK
  84. //
  85. // If there is an error, it dumps an error message. It also sets the status
  86. //
  87. //***************************************************************************
  88. HRESULT SetStatusAndReturnOK(SCODE sc, IWbemObjectSink* pSink, char * pMsg)
  89. {
  90. if(sc != S_OK && pMsg)
  91. ERRORTRACE((LOG_WBEMCORE, "SecurityMethod failed doing %s, sc = 0x%x", pMsg, sc));
  92. pSink->SetStatus(0,sc, NULL, NULL);
  93. return S_OK;
  94. }
  95. //***************************************************************************
  96. //
  97. // DumpErrorMsgAndReturn
  98. //
  99. // Dumps out an error message
  100. //
  101. //***************************************************************************
  102. HRESULT DumpErrorMsgAndReturn(SCODE sc, char * pMsg)
  103. {
  104. if(pMsg)
  105. ERRORTRACE((LOG_WBEMCORE, "%s, sc = 0x%x", pMsg, sc));
  106. return sc;
  107. }
  108. //***************************************************************************
  109. //
  110. // CWbemNamespace::GetSDMethod
  111. //
  112. // Implements the GetSD method. This method returns the security descriptor
  113. //
  114. //***************************************************************************
  115. HRESULT CWbemNamespace::GetSDMethod(IWbemClassObject* pOutParams)
  116. {
  117. // Load up the return object with the security descriptor
  118. SCODE sc = EnsureSecurity();
  119. if(sc != S_OK)
  120. return DumpErrorMsgAndReturn(sc, "GetSDMethod failed creating a SD");
  121. CNtSecurityDescriptor &sd = GetSDRef();
  122. sc = CopySDIntoProperty(L"SD", sd, pOutParams);
  123. return sc;
  124. }
  125. //***************************************************************************
  126. //
  127. // SetSDMethod
  128. //
  129. // Implements the SetSD method. This method sets the security descriptor
  130. //
  131. //***************************************************************************
  132. HRESULT CWbemNamespace::RecursiveSDMerge()
  133. {
  134. // Enumerate the child namespaces
  135. CSynchronousSink* pSyncSink = CSynchronousSink::Create();
  136. if(pSyncSink == NULL)
  137. return WBEM_E_OUT_OF_MEMORY;
  138. pSyncSink->AddRef();
  139. CReleaseMe rm4(pSyncSink);
  140. HRESULT hres = CRepository::ExecQuery ( m_pSession, m_pNsHandle, L"select * from __Namespace", pSyncSink, WBEM_FLAG_DEEP );
  141. if(FAILED(hres))
  142. return hres;
  143. pSyncSink->Block();
  144. // For each child
  145. for(int i = 0; i < pSyncSink->GetObjects().GetSize(); i++)
  146. {
  147. // Get the child namespace
  148. CWbemNamespace* pNewNs = CWbemNamespace::CreateInstance();
  149. if (pNewNs == NULL)
  150. {
  151. return WBEM_E_OUT_OF_MEMORY;
  152. }
  153. CReleaseMe rm2((IWbemServices *)pNewNs);
  154. VARIANT var;
  155. VariantInit(&var);
  156. CWbemObject* pObj = (CWbemObject*)pSyncSink->GetObjects().GetAt(i);
  157. hres = pObj->Get(L"name", 0, &var, NULL, NULL);
  158. if(SUCCEEDED(hres) && var.vt == VT_BSTR && var.bstrVal && m_pThisNamespace)
  159. {
  160. CClearMe cm(&var);
  161. DWORD dwLen = wcslen(m_pThisNamespace) + wcslen(var.bstrVal) + 2; // SEC:REVIEWED 2002-03-22 : OK, Nulls are provably there
  162. WCHAR * pNewName = new WCHAR[dwLen];
  163. if(pNewName == NULL)
  164. return WBEM_E_OUT_OF_MEMORY;
  165. CDeleteMe<WCHAR> dm(pNewName);
  166. StringCchCopyW(pNewName, dwLen, m_pThisNamespace);
  167. StringCchCatW(pNewName, dwLen, L"\\");
  168. StringCchCatW(pNewName, dwLen, var.bstrVal);
  169. hres = pNewNs->Initialize(pNewName,
  170. NULL,
  171. m_dwSecurityFlags, m_dwPermission, m_bForClient, FALSE,
  172. NULL, 0xFFFFFFFF, FALSE, NULL);
  173. if(FAILED(hres))
  174. return hres;
  175. // Merge parents SD into the child
  176. if(pNewNs->IsNamespaceSDProtected())
  177. continue;
  178. hres = SetSecurityForNS(pNewNs->m_pSession, pNewNs->m_pNsHandle, m_pSession, m_pNsHandle, TRUE);
  179. if(FAILED(hres))
  180. return hres;
  181. // Recursively call the child
  182. hres = pNewNs->RecursiveSDMerge();
  183. if (FAILED(hres))
  184. return hres;
  185. }
  186. }
  187. return S_OK;
  188. }
  189. BOOL IsProtected(CNtSecurityDescriptor & sd)
  190. {
  191. PSECURITY_DESCRIPTOR pActual = sd.GetPtr();
  192. if(pActual == NULL)
  193. return FALSE;
  194. SECURITY_DESCRIPTOR_CONTROL Control;
  195. DWORD dwRevision;
  196. BOOL bRet = GetSecurityDescriptorControl(pActual, &Control, &dwRevision);
  197. if(bRet == FALSE)
  198. return FALSE;
  199. if(Control & SE_DACL_PROTECTED)
  200. return TRUE;
  201. else
  202. return FALSE;
  203. }
  204. BOOL CWbemNamespace::IsNamespaceSDProtected()
  205. {
  206. // Get the SD for this namespace
  207. HRESULT hRes = EnsureSecurity();
  208. if(FAILED(hRes))
  209. return FALSE;
  210. // check the control flag
  211. return IsProtected(m_sd);
  212. }
  213. HRESULT StripOutInheritedAces(CNtSecurityDescriptor &sd)
  214. {
  215. // Get the DACL
  216. CNtAcl * DestAcl;
  217. DestAcl = sd.GetDacl();
  218. if(DestAcl == FALSE)
  219. return WBEM_E_INVALID_PARAMETER;
  220. CDeleteMe<CNtAcl> dm(DestAcl);
  221. // enumerate through the aces
  222. DWORD dwNumAces = DestAcl->GetNumAces();
  223. BOOL bChanged = FALSE;
  224. for(long nIndex = (long)dwNumAces-1; nIndex >= 0; nIndex--)
  225. {
  226. CNtAce *pAce = DestAcl->GetAce(nIndex);
  227. if(pAce && CNtAce::NoError == pAce->GetStatus())
  228. {
  229. long lFlags = pAce->GetFlags();
  230. if(lFlags & INHERITED_ACE)
  231. {
  232. DestAcl->DeleteAce(nIndex);
  233. bChanged = TRUE;
  234. delete pAce;
  235. }
  236. }
  237. }
  238. if(bChanged)
  239. sd.SetDacl(DestAcl);
  240. return S_OK;
  241. }
  242. HRESULT CWbemNamespace::GetParentsInheritableAces(CNtSecurityDescriptor &sd)
  243. {
  244. // Get the parent namespace's SD
  245. if(m_pThisNamespace == NULL)
  246. return WBEM_E_CRITICAL_ERROR;
  247. // Start by figuring out what the parents name is. Do this by copying the namespace name,
  248. // then nulling out the last back slash.
  249. int iLen = wcslen(m_pThisNamespace); // SEC:REVIEWED 2002-03-22 : OK, Null is provably there
  250. WCHAR * pParentName = new WCHAR[iLen + 1];
  251. if(pParentName == NULL)
  252. return WBEM_E_OUT_OF_MEMORY;
  253. CDeleteMe<WCHAR> dm(pParentName);
  254. StringCchCopyW(pParentName, iLen + 1, m_pThisNamespace);
  255. BOOL bFoundBackSlash = FALSE;
  256. WCHAR * pTest = pParentName+iLen-1;
  257. for (; pTest >= pParentName; pTest--)
  258. {
  259. if ( *pTest == '\\' || *pTest == '/' )
  260. {
  261. bFoundBackSlash = TRUE;
  262. *pTest = 0;
  263. break;
  264. }
  265. }
  266. if(!bFoundBackSlash)
  267. return S_OK; // probably already in root
  268. // Open the parent namespace
  269. CWbemNamespace* pNewNs = CWbemNamespace::CreateInstance();
  270. if (pNewNs == NULL)
  271. {
  272. return WBEM_E_OUT_OF_MEMORY;
  273. }
  274. IUnknown * pUnk = NULL;
  275. HRESULT hres = pNewNs->QueryInterface(IID_IUnknown, (void **)&pUnk);
  276. if(FAILED(hres))
  277. return hres;
  278. pNewNs->Release(); // ref count held by pUnk
  279. CReleaseMe rm2(pUnk);
  280. hres = pNewNs->Initialize(pParentName,
  281. NULL,
  282. m_dwSecurityFlags, m_dwPermission, m_bForClient, FALSE,
  283. NULL, 0xFFFFFFFF, FALSE, NULL);
  284. if(FAILED(hres))
  285. return hres;
  286. hres = pNewNs->EnsureSecurity();
  287. if(FAILED(hres))
  288. return FALSE;
  289. // Go through the parents dacl and add and inheritiable aces to ours.
  290. hres = CopyInheritAces(sd, pNewNs->m_sd);
  291. return hres;
  292. }
  293. HRESULT CWbemNamespace::SetSDMethod(IWbemClassObject* pInParams)
  294. {
  295. // Make sure that there is an input argument
  296. if(pInParams == NULL)
  297. return DumpErrorMsgAndReturn(WBEM_E_INVALID_PARAMETER, "SetSD failed due to null pInParams");
  298. // Get the security descriptor argument
  299. CNtSecurityDescriptor sd;
  300. HRESULT hr = GetSDFromProperty(L"SD", sd, pInParams);
  301. if(FAILED(hr))
  302. return hr;
  303. // Check to make sure the SD is valid before attempting to store it
  304. // CNtSecurityDescriptor does this via IsValidSecurityDescriptor so
  305. // all we need to do is check the status of sd before continuing.
  306. // NT RAID#: 152990 [marioh]
  307. if ( sd.GetStatus() != CNtSecurityDescriptor::NoError )
  308. return WBEM_E_INVALID_OBJECT;
  309. //
  310. // Reject SecurityDescriptors with NULL Owner or NULL group
  311. //
  312. // This is temporarily removed since _SOMEONE_ decided we need
  313. // to RI yesterday and test wasnt quite done with smoking this.
  314. //
  315. CNtSid *pTmpSid = sd.GetOwner ( ) ;
  316. CNtSid *pTmpSid2 = sd.GetGroup ( ) ;
  317. CDeleteMe<CNtSid> owner ( pTmpSid ) ;
  318. CDeleteMe<CNtSid> group ( pTmpSid2 ) ;
  319. if ( pTmpSid == NULL || pTmpSid2 == NULL )
  320. {
  321. return WBEM_E_FAILED ;
  322. }
  323. if (CNtSid::NoError != pTmpSid->GetStatus() || CNtSid::NoError != pTmpSid2->GetStatus())
  324. {
  325. return WBEM_E_FAILED;
  326. }
  327. // Some editors return inherited aces, and others dont. Strip the inherited ones so
  328. // that we have a consistent SD.
  329. StripOutInheritedAces(sd);
  330. //
  331. // Make sure to order the ACEs that are in the pInparams.
  332. // NT Bug: 515545 [marioh]
  333. //
  334. CNtAcl* pAcl = sd.GetDacl ( ) ;
  335. CDeleteMe <CNtAcl> dacl ( pAcl ) ;
  336. CNtAcl* pOrderedAcl = NULL ;
  337. CDeleteMe <CNtAcl> ordDacl ( pOrderedAcl ) ;
  338. if ( pAcl != NULL )
  339. {
  340. //
  341. // Order the DACL.
  342. //
  343. pOrderedAcl = pAcl->OrderAces ( ) ;
  344. if ( pOrderedAcl == NULL )
  345. {
  346. return WBEM_E_FAILED ;
  347. }
  348. //
  349. // Now, set the DACL to the newly ordered one.
  350. //
  351. if ( sd.SetDacl ( pOrderedAcl ) == FALSE )
  352. {
  353. return WBEM_E_FAILED ;
  354. }
  355. }
  356. // Get the inherited aces from the parent
  357. if(!IsProtected(sd))
  358. GetParentsInheritableAces(sd);
  359. // Store the sd.
  360. hr = StoreSDIntoNamespace(m_pSession, m_pNsHandle, sd);
  361. if(FAILED(hr))
  362. return hr;
  363. hr = RecursiveSDMerge();
  364. return hr;
  365. }
  366. //***************************************************************************
  367. //
  368. // IsAceValid()
  369. //
  370. // Does a sanity check on aces
  371. //
  372. //***************************************************************************
  373. bool IsAceValid(DWORD dwMask, DWORD dwType, DWORD dwFlag)
  374. {
  375. bool bOK = true;
  376. if(dwMask & WBEM_FULL_WRITE_REP && ((dwMask & WBEM_PARTIAL_WRITE_REP) == 0 ||
  377. (dwMask & WBEM_WRITE_PROVIDER) == 0))
  378. {
  379. bOK = false;
  380. return false;
  381. }
  382. // DONT allow INHERIT_ONLY_ACE with out CONTAINER_INHERIT
  383. DWORD dwTemp = dwFlag & (INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE);
  384. if(dwTemp == INHERIT_ONLY_ACE)
  385. bOK = false;
  386. DWORD dwBadAccess = dwMask & ~(FULL_RIGHTS);
  387. DWORD dwBadFlag = dwFlag & ~(CONTAINER_INHERIT_ACE | NO_PROPAGATE_INHERIT_ACE |
  388. INHERIT_ONLY_ACE | INHERITED_ACE);
  389. if(dwBadFlag || dwBadAccess)
  390. bOK = false;
  391. if((dwType != 0) && (dwType != 1))
  392. bOK = false;
  393. if(!bOK)
  394. ERRORTRACE((LOG_WBEMCORE, "Got passed a bad ace, dwMask=0x%x, dwType=0x%x, dwFlag=0x%x",
  395. dwMask, dwType, dwFlag));
  396. return bOK;
  397. }
  398. //***************************************************************************
  399. //
  400. // GetCallerAccessRightsMethod
  401. //
  402. // Implements the GetCallerAccessRights methods. It returns the access rignts
  403. // of the current caller.
  404. //
  405. //***************************************************************************
  406. HRESULT CWbemNamespace::GetCallerAccessRightsMethod(IWbemClassObject* pOutParams)
  407. {
  408. VARIANT var;
  409. var.vt = VT_I4;
  410. var.lVal = m_dwPermission;
  411. //
  412. // Instead of using the 'saved' permission set from original namespace connect
  413. // we get the caller access rights every time. This is to avoid the scenario
  414. // whereby user A connects and then sets the proxyblanket to user B and makes
  415. // a call to GetCallerAccessRights. Without getting the access rights each time
  416. // we would end of with A's access rights.
  417. //
  418. var.lVal = GetUserAccess ( ) ;
  419. //var.lVal = m_dwPermission;
  420. SCODE sc = pOutParams->Put(L"rights" , 0, &var, 0);
  421. if(sc != S_OK)
  422. return DumpErrorMsgAndReturn(sc, "GetCallerAccessRights failed putting the dwAccesMask property");
  423. return S_OK;
  424. }
  425. //***************************************************************************
  426. //
  427. // SecurityMethod
  428. //
  429. // Implements the security methods.
  430. //
  431. //***************************************************************************
  432. HRESULT CWbemNamespace::SecurityMethod(LPWSTR wszMethodName, long lFlags,
  433. IWbemClassObject *pInParams, IWbemContext *pCtx,
  434. IWbemObjectSink* pSink)
  435. {
  436. SCODE sc;
  437. // Do some parameter checking
  438. if(pSink == NULL || wszMethodName == NULL)
  439. return WBEM_E_INVALID_PARAMETER;
  440. IWbemClassObject * pClass = NULL;
  441. IWbemClassObject * pOutClass = NULL;
  442. IWbemClassObject* pOutParams = NULL;
  443. // Get the class object
  444. sc = GetObject(L"__SystemSecurity", 0, pCtx, &pClass, NULL);
  445. if(sc != S_OK || pClass == NULL)
  446. return SetStatusAndReturnOK(sc, pSink, "getting the class object");
  447. // All the methods return data, so create an instance of the
  448. // output argument class.
  449. sc = pClass->GetMethod(wszMethodName, 0, NULL, &pOutClass);
  450. pClass->Release();
  451. if(sc != S_OK)
  452. return SetStatusAndReturnOK(sc, pSink, "getting the method");
  453. sc = pOutClass->SpawnInstance(0, &pOutParams);
  454. pOutClass->Release();
  455. if(sc != S_OK || pOutParams == NULL)
  456. return SetStatusAndReturnOK(sc, pSink, "spawning an instance of the output class");
  457. CReleaseMe rm(pOutParams);
  458. // Depending on the actual method, call the appropritate routine
  459. if(!wbem_wcsicmp(wszMethodName, L"GetSD"))
  460. {
  461. if (!Allowed(READ_CONTROL))
  462. sc = WBEM_E_ACCESS_DENIED;
  463. else
  464. sc = GetSDMethod(pOutParams);
  465. }
  466. else if(!wbem_wcsicmp(wszMethodName, L"Get9XUserList"))
  467. {
  468. sc = WBEM_E_METHOD_DISABLED;
  469. }
  470. else if(!wbem_wcsicmp(wszMethodName, L"SetSD"))
  471. {
  472. if (!Allowed(WRITE_DAC))
  473. sc = WBEM_E_ACCESS_DENIED;
  474. else
  475. sc = SetSDMethod(pInParams);
  476. }
  477. else if(!wbem_wcsicmp(wszMethodName, L"Set9XUserList"))
  478. {
  479. sc = WBEM_E_METHOD_DISABLED;
  480. }
  481. else if(!wbem_wcsicmp(wszMethodName, L"GetCallerAccessRights"))
  482. {
  483. sc = GetCallerAccessRightsMethod(pOutParams);
  484. }
  485. else
  486. {
  487. return SetStatusAndReturnOK(WBEM_E_INVALID_PARAMETER, pSink, "Invalid method name");
  488. }
  489. if(sc != S_OK)
  490. return SetStatusAndReturnOK(sc, pSink, "calling method");
  491. // Set the return code
  492. VARIANT var;
  493. var.vt = VT_I4;
  494. var.lVal = 0; // special name for return value.
  495. sc = pOutParams->Put(L"ReturnValue" , 0, &var, 0);
  496. if(sc != S_OK)
  497. return SetStatusAndReturnOK(sc, pSink, "setting the ReturnCode property");
  498. // Send the output object back to the client via the sink. Then
  499. // release the pointers and free the strings.
  500. sc = pSink->Indicate(1, &pOutParams);
  501. // all done now, set the status
  502. sc = pSink->SetStatus(0,WBEM_S_NO_ERROR,NULL,NULL);
  503. return WBEM_S_NO_ERROR;
  504. }
  505. //***************************************************************************
  506. //
  507. // GetUserAccess
  508. //
  509. // Determines the allowed access for a user.
  510. //
  511. //***************************************************************************
  512. DWORD CWbemNamespace::GetUserAccess()
  513. {
  514. DWORD dwRet = 0;
  515. if(IsInAdminGroup())
  516. return FULL_RIGHTS;
  517. if(S_OK !=EnsureSecurity())
  518. return dwRet; // nothing!
  519. dwRet = GetNTUserAccess();
  520. if((dwRet & WBEM_REMOTE_ACCESS) == 0)
  521. {
  522. HANDLE hAccessToken;
  523. if(SUCCEEDED(GetAccessToken(hAccessToken)))
  524. {
  525. BOOL bRemote = IsRemote(hAccessToken);
  526. CloseHandle(hAccessToken);
  527. if(bRemote)
  528. dwRet = 0;
  529. }
  530. }
  531. if(m_pThisNamespace && (wbem_wcsicmp(L"root\\security", m_pThisNamespace) == 0 ||
  532. wbem_wcsicmp(L"root/security", m_pThisNamespace) == 0))
  533. if((dwRet & READ_CONTROL) == 0)
  534. dwRet = 0;
  535. return dwRet;
  536. }
  537. //***************************************************************************
  538. //
  539. // GetNTUserAccess
  540. //
  541. // Determines the allowed access for a user.
  542. //
  543. //***************************************************************************
  544. DWORD CWbemNamespace::GetNTUserAccess()
  545. {
  546. HANDLE hAccessToken = INVALID_HANDLE_VALUE;
  547. if(S_OK != GetAccessToken(hAccessToken))
  548. return FULL_RIGHTS; // Not having a token indicates an internal thread
  549. CCloseHandle cm(hAccessToken);
  550. DWORD dwMask = 0;
  551. if(IsAdmin(hAccessToken))
  552. return FULL_RIGHTS;
  553. // use the SD
  554. GENERIC_MAPPING map;
  555. map.GenericRead = 1;
  556. map.GenericWrite = 0x1C;
  557. map.GenericExecute = 2;
  558. map.GenericAll = 0x6001f;
  559. PRIVILEGE_SET ps[3];
  560. DWORD dwSize = 3 * sizeof(PRIVILEGE_SET);
  561. BOOL bResult;
  562. long testbit = 1;
  563. for(int iCnt = 0; iCnt < 26; iCnt++, testbit <<= 1)
  564. {
  565. // dont bother testing bits that we dont use
  566. DWORD dwGranted = 0;
  567. if(testbit & (FULL_RIGHTS))
  568. {
  569. BOOL bOK = AccessCheck(m_sd.GetPtr(), hAccessToken, testbit, &map, ps, &dwSize, &dwGranted, &bResult);
  570. if(bOK && bResult && dwGranted)
  571. {
  572. // if the right is full repository, make sure the user also gets the lesser write
  573. // access or else the logic for putting/deleting classes will have problems.
  574. if(testbit == WBEM_FULL_WRITE_REP)
  575. dwMask |= (WBEM_PARTIAL_WRITE_REP|WBEM_WRITE_PROVIDER);
  576. dwMask |= testbit;
  577. }
  578. }
  579. }
  580. return dwMask;
  581. }
  582. //***************************************************************************
  583. //
  584. // bool CWbemNamespace::Allowed(DWORD dwRequired)
  585. //
  586. // Description. Tests if the user has the requested permission. This is
  587. // called before something like a WRITE is done. Since nt supports
  588. // supports impersonation, this is always called. For 9X, a simple check
  589. // of the permissions strored at the time of connection is OK.
  590. //
  591. //***************************************************************************
  592. bool CWbemNamespace::Allowed(DWORD dwRequired)
  593. {
  594. //
  595. // Check for admin first
  596. //
  597. GENERIC_MAPPING map;
  598. map.GenericRead = 1;
  599. map.GenericWrite = 0x1C;
  600. map.GenericExecute = 2;
  601. map.GenericAll = 0x6001f;
  602. PRIVILEGE_SET ps[3];
  603. DWORD dwSize = 3 * sizeof(PRIVILEGE_SET);
  604. BOOL bResult;
  605. DWORD dwGranted = 0;
  606. BOOL bOK;
  607. HANDLE hAccessToken = INVALID_HANDLE_VALUE;
  608. if(S_OK != GetAccessToken(hAccessToken))
  609. return true;
  610. CCloseHandle cm(hAccessToken);
  611. bOK = AccessCheck(m_sdCheckAdmin.GetPtr(), hAccessToken, 1,
  612. &map, ps, &dwSize, &dwGranted, &bResult);
  613. if(bOK && bResult && dwGranted)
  614. return true;
  615. //
  616. // Not an admin. Continue
  617. //
  618. if(EnsureSecurity() != S_OK)
  619. return false;
  620. //
  621. // Always include the check for account enabled right.
  622. // NOTE: This is safe. We dont really care about the explicit
  623. // checks for PARTIAL of FULL write below if the account is disabled.
  624. //
  625. // NOTE: Why, oh, why did we go the anti-NT security path???????????????
  626. //
  627. DWORD dwRequiredCheck = dwRequired ;
  628. dwRequired |= WBEM_ENABLE ;
  629. // For nt, the current users priviledges are checked on the fly via access check
  630. CInCritSec ics(&m_cs); // grab the cs since we are using the security desc. // SEC:REVIEWED 2002-03-22 : Assumes entry
  631. if(IsRemote(hAccessToken))
  632. {
  633. //
  634. // Check to see if the user is remote enabled before continuing. If they are not
  635. // remote enabled, we fail (except in admin cases).
  636. //
  637. dwGranted = 0 ;
  638. bResult = FALSE ;
  639. bOK = AccessCheck(m_sd.GetPtr(), hAccessToken, WBEM_REMOTE_ACCESS, &map, ps, &dwSize,
  640. &dwGranted, &bResult);
  641. if ( !bOK || !bResult || !dwGranted )
  642. {
  643. return IsAdmin(hAccessToken) ? true : false ;
  644. }
  645. }
  646. bOK = AccessCheck(m_sd.GetPtr(), hAccessToken, dwRequired, &map, ps, &dwSize, &dwGranted, &bResult);
  647. bool bRet = (bOK && bResult && dwGranted);
  648. // Having full repository write gives access to the "lower" write capabilities. So if the lower
  649. // right is rejected, double check for the full access right.
  650. if(bRet == false && (dwRequiredCheck == WBEM_PARTIAL_WRITE_REP || dwRequiredCheck == WBEM_WRITE_PROVIDER))
  651. {
  652. bOK = AccessCheck(m_sd.GetPtr(), hAccessToken, WBEM_FULL_WRITE_REP|WBEM_ENABLE, &map, ps, &dwSize,
  653. &dwGranted, &bResult);
  654. bRet = (bOK && bResult && dwGranted);
  655. }
  656. if(bRet == FALSE)
  657. bRet = TRUE == IsAdmin(hAccessToken);
  658. return bRet;
  659. }
  660. //***************************************************************************
  661. //
  662. // HRESULT CWbemNamespace::InitializeSD()
  663. //
  664. // Description. Creates the SD
  665. //
  666. //***************************************************************************
  667. HRESULT CWbemNamespace::InitializeSD(IWmiDbSession *pSession)
  668. {
  669. HRESULT hr;
  670. if (pSession == NULL)
  671. {
  672. hr = CRepository::GetDefaultSession(&pSession);
  673. if (FAILED(hr))
  674. return hr;
  675. }
  676. else
  677. pSession->AddRef();
  678. CReleaseMe relMe2(pSession);
  679. IWbemClassObject * pThisNSObject = NULL;
  680. //AutoRevert av; // switches to system and back to client
  681. BOOL bWasImpersonating = WbemIsImpersonating();
  682. if( bWasImpersonating )
  683. {
  684. if (FAILED(hr = CoRevertToSelf())) return hr;
  685. }
  686. //
  687. // Lets disable security checks here. This is a special case. If we didnt do this
  688. // a connection to a namespace would fail if the user didnt have the right to see
  689. // the security descriptor.
  690. //
  691. AutoRevertSecTlsFlag secFlag ( (LPVOID)0 ) ;
  692. hr = CRepository::GetObject(pSession, m_pNsHandle, L"__thisnamespace=@",
  693. WBEM_FLAG_USE_SECURITY_DESCRIPTOR | WMIDB_FLAG_ADMIN_VERIFIED,
  694. &pThisNSObject);
  695. if(FAILED(hr))
  696. {
  697. if(bWasImpersonating)
  698. {
  699. if (FAILED(CoImpersonateClient()))
  700. {
  701. hr = WBEM_E_FAILED ;
  702. }
  703. }
  704. return hr;
  705. }
  706. CReleaseMe rm1(pThisNSObject);
  707. hr = GetSDFromProperty(L"SECURITY_DESCRIPTOR", m_sd, pThisNSObject);
  708. if(bWasImpersonating)
  709. {
  710. if ( FAILED (CoImpersonateClient()))
  711. {
  712. hr = WBEM_E_FAILED ;
  713. }
  714. }
  715. return hr ;
  716. }
  717. //***************************************************************************
  718. //
  719. // HRESULT CWbemNamespace::EnsureSecurity()
  720. //
  721. // Description. Generally doesnt do anything except for the first time
  722. //
  723. //***************************************************************************
  724. HRESULT CWbemNamespace::EnsureSecurity()
  725. {
  726. SCODE sc = S_OK;
  727. CInCritSec cs(&m_cs); // SEC:REVIEWED 2002-03-22 : Assumes entry
  728. if(m_bSecurityInitialized)
  729. return S_OK;
  730. sc = InitializeSD(NULL);
  731. if(sc == S_OK)
  732. m_bSecurityInitialized = true;
  733. return sc;
  734. }
  735. CBaseAce * ConvertOldObjectToAce(IWbemClassObject * pObj, bool bGroup)
  736. {
  737. // Get the properties out of the old object
  738. CVARIANT vName;
  739. pObj->Get(L"Name", 0, &vName, 0, 0);
  740. LPWSTR pName = NULL;
  741. if(vName.GetType() != VT_BSTR)
  742. return NULL; // ignore this one.
  743. pName = LPWSTR(vName);
  744. CVARIANT vDomain;
  745. LPWSTR pDomain = L".";
  746. pObj->Get(L"Authority", 0, &vDomain, 0, 0);
  747. if(vDomain.GetType() == VT_BSTR)
  748. pDomain = LPWSTR(vDomain);
  749. bool bEditSecurity = false;
  750. bool bEnabled = false;
  751. bool bExecMethods = false;
  752. DWORD dwMask = 0;
  753. CVARIANT vEnabled;
  754. CVARIANT vEditSecurity;
  755. CVARIANT vExecMethods;
  756. CVARIANT vPermission;
  757. pObj->Get(L"Enabled", 0, &vEnabled, 0, 0);
  758. pObj->Get(L"EditSecurity", 0, &vEditSecurity, 0, 0);
  759. pObj->Get(L"ExecuteMethods", 0, &vExecMethods, 0, 0);
  760. pObj->Get(L"Permissions", 0, &vPermission, 0, 0);
  761. if (vEnabled.GetType() != VT_NULL && vEnabled.GetBool())
  762. bEnabled = true;
  763. if (vEditSecurity.GetType() != VT_NULL && vEditSecurity.GetBool())
  764. bEditSecurity = true;
  765. if (vExecMethods.GetType() != VT_NULL && vExecMethods.GetBool())
  766. bExecMethods = true;
  767. DWORD dwPermission = 0;
  768. if (vPermission.GetType() != VT_NULL && vPermission.GetLONG() > dwPermission)
  769. dwPermission = vPermission.GetLONG();
  770. // Now translate the old settings into new ones
  771. if(bEnabled)
  772. dwMask = WBEM_ENABLE | WBEM_REMOTE_ACCESS | WBEM_WRITE_PROVIDER;
  773. if(bEditSecurity)
  774. dwMask |= READ_CONTROL;
  775. if(bEditSecurity && dwPermission > 0)
  776. dwMask |= WRITE_DAC;
  777. if(bExecMethods)
  778. dwMask |= WBEM_METHOD_EXECUTE;
  779. if(dwPermission >= 1)
  780. dwMask |= WBEM_PARTIAL_WRITE_REP;
  781. if(dwPermission >= 2)
  782. dwMask |= WBEM_FULL_WRITE_REP | WBEM_PARTIAL_WRITE_REP | WBEM_WRITE_PROVIDER;
  783. // By default, CNtSid will look up the group name from either the local machine,
  784. // the domain, or a trusted domain. So we need to be explicit
  785. WString wc;
  786. if(pDomain)
  787. if(wbem_wcsicmp(pDomain, L".") )
  788. {
  789. wc = pDomain;
  790. wc += L"\\";
  791. }
  792. wc += pName;
  793. // under m1, groups that were not enabled were just ignored. Therefore the bits
  794. // cannot be transfer over since m3 has allows and denies, but no noops. Also,
  795. // win9x doesnt have denies, do we want to noop those users also.
  796. if(!bEnabled && bGroup)
  797. dwMask = 0;
  798. // In general, m1 just supported allows. However, a user entry that was not enabled was
  799. // treated as a deny. Note that win9x does not allow actual denies.
  800. DWORD dwType = ACCESS_ALLOWED_ACE_TYPE;
  801. if(!bGroup && !bEnabled)
  802. {
  803. dwMask |= (WBEM_ENABLE | WBEM_REMOTE_ACCESS | WBEM_WRITE_PROVIDER);
  804. dwType = ACCESS_DENIED_ACE_TYPE;
  805. }
  806. CNtSid Sid(wc, NULL);
  807. if(Sid.GetStatus() != CNtSid::NoError)
  808. {
  809. ERRORTRACE((LOG_WBEMCORE, "Error converting m1 security ace, name = %S, error = 0x%x",
  810. wc, Sid.GetStatus()));
  811. return NULL;
  812. }
  813. CNtAce * pace = new CNtAce(dwMask, dwType, CONTAINER_INHERIT_ACE, Sid);
  814. if (pace && CNtAce::NoError != pace->GetStatus())
  815. {
  816. delete pace;
  817. pace = NULL;
  818. }
  819. return pace;
  820. }
  821. //***************************************************************************
  822. //
  823. // BOOL IsRemote()
  824. //
  825. // Description. returns true if the box is NT and the caller remote
  826. //
  827. //***************************************************************************
  828. BOOL IsRemote(HANDLE hToken)
  829. {
  830. PSID pRawSid;
  831. SID_IDENTIFIER_AUTHORITY id = SECURITY_NT_AUTHORITY;
  832. BOOL bRet = TRUE;
  833. if(AllocateAndInitializeSid( &id, 1, // SEC:REVIEWED 2002-03-22 : OK
  834. SECURITY_INTERACTIVE_RID, 0,
  835. 0,0,0,0,0,0,&pRawSid)) // S-1-5-4
  836. {
  837. CNtSid Sid(pRawSid);
  838. FreeSid(pRawSid);
  839. if (CNtSid::NoError == Sid.GetStatus())
  840. {
  841. if(CNtSecurity::IsUserInGroup(hToken, Sid))
  842. bRet = FALSE;
  843. }
  844. }
  845. //
  846. //Add proper check for remotness. In addition to the INTERACTIVE group,
  847. //we also check NETWORK_RID membership
  848. //
  849. if ( bRet )
  850. {
  851. if(AllocateAndInitializeSid( &id, 1, // SEC:REVIEWED 2002-03-22 : OK
  852. SECURITY_NETWORK_RID, 0,
  853. 0,0,0,0,0,0,&pRawSid)) // S-1-5-4
  854. {
  855. CNtSid Sid(pRawSid);
  856. FreeSid(pRawSid);
  857. if (CNtSid::NoError == Sid.GetStatus())
  858. {
  859. if(!CNtSecurity::IsUserInGroup(hToken, Sid))
  860. bRet = FALSE;
  861. }
  862. }
  863. }
  864. return bRet;
  865. }
  866. HRESULT AddDefaultRootAces(CNtAcl * pacl)
  867. {
  868. PSID pRawSid;
  869. SID_IDENTIFIER_AUTHORITY id = SECURITY_NT_AUTHORITY;
  870. if(AllocateAndInitializeSid( &id, 2, // SEC:REVIEWED 2002-03-22 : OK
  871. SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
  872. 0,0,0,0,0,0,&pRawSid))
  873. {
  874. CNtSid SidAdmin(pRawSid);
  875. FreeSid(pRawSid);
  876. if (CNtSid::NoError != SidAdmin.GetStatus()) return WBEM_E_FAILED;
  877. DWORD dwMask = FULL_RIGHTS;
  878. wmilib::auto_ptr<CNtAce> pace( new CNtAce(dwMask, ACCESS_ALLOWED_ACE_TYPE,
  879. CONTAINER_INHERIT_ACE, SidAdmin));
  880. if ( NULL == pace.get() ) return WBEM_E_OUT_OF_MEMORY;
  881. if (CNtAce::NoError != pace->GetStatus()) return WBEM_E_OUT_OF_MEMORY;
  882. pacl->AddAce(pace.get());
  883. }
  884. //
  885. // Add ACE's for NETWORK_SERVICE ACCOUNT. These accounts have the following rights:
  886. // 1. WBEM_ENABLE
  887. // 2. WBEM_METHOD_EXECUTE
  888. // 3. WBEM_WRITE_PROVIDER
  889. //
  890. DWORD dwAccessMaskNetworkLocalService = WBEM_ENABLE | WBEM_METHOD_EXECUTE | WBEM_WRITE_PROVIDER ;
  891. if(AllocateAndInitializeSid( &id, 1, // SEC:REVIEWED 2002-03-22 : OK
  892. SECURITY_NETWORK_SERVICE_RID,0,0,0,0,0,0,0,&pRawSid))
  893. {
  894. CNtSid SidUsers(pRawSid);
  895. FreeSid(pRawSid);
  896. if (CNtSid::NoError != SidUsers.GetStatus()) return WBEM_E_FAILED;
  897. wmilib::auto_ptr<CNtAce> pace( new CNtAce(dwAccessMaskNetworkLocalService, ACCESS_ALLOWED_ACE_TYPE,
  898. CONTAINER_INHERIT_ACE, SidUsers));
  899. if ( NULL == pace.get() ) return WBEM_E_OUT_OF_MEMORY;
  900. if (CNtAce::NoError != pace->GetStatus()) return WBEM_E_OUT_OF_MEMORY;
  901. pacl->AddAce(pace.get());
  902. }
  903. //
  904. // Add ACE's for NETWORK_SERVICE ACCOUNT. These accounts have the following rights:
  905. // 1. WBEM_ENABLE
  906. // 2. WBEM_METHOD_EXECUTE
  907. // 3. WBEM_WRITE_PROVIDER
  908. //
  909. if(AllocateAndInitializeSid( &id, 1, // SEC:REVIEWED 2002-03-22 : OK
  910. SECURITY_LOCAL_SERVICE_RID,0,0,0,0,0,0,0,&pRawSid))
  911. {
  912. CNtSid SidUsers(pRawSid);
  913. FreeSid(pRawSid);
  914. if (CNtSid::NoError != SidUsers.GetStatus()) return WBEM_E_FAILED;
  915. wmilib::auto_ptr<CNtAce> pace( new CNtAce(dwAccessMaskNetworkLocalService, ACCESS_ALLOWED_ACE_TYPE,
  916. CONTAINER_INHERIT_ACE, SidUsers));
  917. if (NULL == pace.get()) return WBEM_E_OUT_OF_MEMORY;
  918. if (CNtAce::NoError != pace->GetStatus()) return WBEM_E_OUT_OF_MEMORY;
  919. pacl->AddAce(pace.get());
  920. }
  921. SID_IDENTIFIER_AUTHORITY id2 = SECURITY_WORLD_SID_AUTHORITY; // SEC:REVIEWED 2002-03-22 : OK
  922. if(AllocateAndInitializeSid( &id2, 1, // SEC:REVIEWED 2002-03-22 : OK
  923. 0,0,0,0,0,0,0,0,&pRawSid))
  924. {
  925. CNtSid SidUsers(pRawSid);
  926. FreeSid(pRawSid);
  927. if (CNtSid::NoError != SidUsers.GetStatus()) return WBEM_E_FAILED;
  928. DWORD dwMask = WBEM_ENABLE | WBEM_METHOD_EXECUTE | WBEM_WRITE_PROVIDER;
  929. wmilib::auto_ptr<CNtAce> pace( new CNtAce(dwMask, ACCESS_ALLOWED_ACE_TYPE,
  930. CONTAINER_INHERIT_ACE, SidUsers));
  931. if (NULL == pace.get()) return WBEM_E_OUT_OF_MEMORY;
  932. if (CNtAce::NoError != pace->GetStatus()) return WBEM_E_OUT_OF_MEMORY;
  933. pacl->AddAce(pace.get());
  934. }
  935. return S_OK;
  936. }
  937. HRESULT CopySDIntoProperty(LPWSTR pPropName, CNtSecurityDescriptor &sd, IWbemClassObject *pThisNSObject)
  938. {
  939. if (sd.GetStatus() != CNtSecurityDescriptor::NoError)
  940. return WBEM_E_FAILED;
  941. // move the SD into a variant.
  942. SAFEARRAY FAR* psa;
  943. SAFEARRAYBOUND rgsabound[1];
  944. rgsabound[0].lLbound = 0;
  945. long lSize = sd.GetSize();
  946. rgsabound[0].cElements = lSize;
  947. psa = SafeArrayCreate( VT_UI1, 1 , rgsabound );
  948. if(psa == NULL)
  949. return DumpErrorMsgAndReturn(WBEM_E_FAILED, "GetSDMethod failed creating a safe array");
  950. char * pData = NULL;
  951. SCODE sc = SafeArrayAccessData(psa, (void HUGEP* FAR*)&pData);
  952. if(sc != S_OK)
  953. return DumpErrorMsgAndReturn(sc, "GetSDMethod failed accessing safe array data");
  954. memcpy(pData, sd.GetPtr(), lSize); // SEC:REVIEWED 2002-03-22 : OK
  955. SafeArrayUnaccessData(psa);
  956. VARIANT var;
  957. var.vt = VT_UI1|VT_ARRAY;
  958. var.parray = psa;
  959. sc = pThisNSObject->Put(pPropName , 0, &var, 0);
  960. VariantClear(&var);
  961. return sc;
  962. }
  963. HRESULT GetSDFromProperty(LPWSTR pPropName, CNtSecurityDescriptor &sd, IWbemClassObject *pThisNSObject)
  964. {
  965. // Get the security descriptor argument
  966. HRESULT hRes = S_OK ;
  967. _variant_t var;
  968. SCODE sc = pThisNSObject->Get(pPropName , 0, &var, NULL, NULL);
  969. if (sc != S_OK)
  970. {
  971. CVARIANT vPath;
  972. pThisNSObject->Get(L"__PATH", 0, &vPath, 0, 0);
  973. DEBUGTRACE((LOG_WBEMCORE, "Getting SD from %S failed due to code 0x%X\n", V_BSTR(&vPath), sc));
  974. return WBEM_E_CRITICAL_ERROR;
  975. }
  976. if(var.vt != (VT_ARRAY | VT_UI1))
  977. {
  978. CVARIANT vPath;
  979. pThisNSObject->Get(L"__PATH", 0, &vPath, 0, 0);
  980. DEBUGTRACE((LOG_WBEMCORE, "Getting SD from %S failed due to incorrect VARIANT type\n", V_BSTR(&vPath) ));
  981. return WBEM_E_INVALID_PARAMETER;
  982. }
  983. SAFEARRAY * psa = V_ARRAY(&var);
  984. PSECURITY_DESCRIPTOR pSD = NULL;
  985. sc = SafeArrayAccessData(psa, (void HUGEP* FAR*)&pSD);
  986. if (FAILED(sc)) return DumpErrorMsgAndReturn(WBEM_E_INVALID_PARAMETER, "SetSD failed trying accessing SD property");
  987. OnDelete<SAFEARRAY *,HRESULT (*)(SAFEARRAY *),SafeArrayUnaccessData> unacc(psa);
  988. if (0 == psa->rgsabound[0].cElements) return WBEM_E_INVALID_PARAMETER;
  989. if (!IsValidSecurityDescriptor(pSD)) return WBEM_E_INVALID_PARAMETER;
  990. CNtSecurityDescriptor sdNew(pSD);
  991. CNtSid *pTmpSid = sdNew.GetOwner();
  992. if ( pTmpSid == NULL )
  993. {
  994. ERRORTRACE((LOG_WBEMCORE, "ERROR: Security descriptor was retrieved and it had no owner\n"));
  995. }
  996. delete pTmpSid;
  997. pTmpSid = sdNew.GetGroup();
  998. if (pTmpSid == NULL )
  999. {
  1000. ERRORTRACE((LOG_WBEMCORE, "ERROR: Security descriptor was retrieved and it had no group\n"));
  1001. }
  1002. delete pTmpSid;
  1003. sd = sdNew;
  1004. if ( sd.GetStatus ( ) != CNtSecurityDescriptor::NoError )
  1005. {
  1006. hRes = WBEM_E_OUT_OF_MEMORY ;
  1007. }
  1008. return hRes ;
  1009. }
  1010. HRESULT CopyInheritAces(CNtSecurityDescriptor & sd, CNtSecurityDescriptor & sdParent)
  1011. {
  1012. // Get the acl list for both SDs
  1013. CNtAcl * pacl = sd.GetDacl();
  1014. if(pacl == NULL)
  1015. return WBEM_E_OUT_OF_MEMORY;
  1016. CDeleteMe<CNtAcl> dm0(pacl);
  1017. CNtAcl * paclParent = sdParent.GetDacl();
  1018. if(paclParent == NULL)
  1019. return WBEM_E_OUT_OF_MEMORY;
  1020. CDeleteMe<CNtAcl> dm1(paclParent);
  1021. int iNumParent = paclParent->GetNumAces();
  1022. for(int iCnt = 0; iCnt < iNumParent; iCnt++)
  1023. {
  1024. CNtAce *pParentAce = paclParent->GetAce(iCnt);
  1025. if (pParentAce == NULL)
  1026. return WBEM_E_OUT_OF_MEMORY;
  1027. CDeleteMe<CNtAce> dm2(pParentAce);
  1028. if (CNtAce::NoError != pParentAce->GetStatus()) continue;
  1029. long lFlags = pParentAce->GetFlags();
  1030. if(lFlags & CONTAINER_INHERIT_ACE)
  1031. {
  1032. if(lFlags & NO_PROPAGATE_INHERIT_ACE)
  1033. lFlags ^= CONTAINER_INHERIT_ACE;
  1034. lFlags |= INHERITED_ACE;
  1035. // If this is an inherit only ace we need to clear this
  1036. // in the children.
  1037. // NT RAID: 161761 [marioh]
  1038. if ( lFlags & INHERIT_ONLY_ACE )
  1039. lFlags ^= INHERIT_ONLY_ACE;
  1040. pParentAce->SetFlags(lFlags);
  1041. pacl->AddAce(pParentAce);
  1042. }
  1043. }
  1044. sd.SetDacl(pacl);
  1045. return S_OK;
  1046. }
  1047. HRESULT StoreSDIntoNamespace(IWmiDbSession * pSession, IWmiDbHandle *pNSToSet, CNtSecurityDescriptor & sd)
  1048. {
  1049. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1050. // Check to make sure the SD DACL is valid before attempting to put
  1051. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1052. CNtAcl* pAcl = sd.GetDacl ( );
  1053. if ( NULL == pAcl ) return WBEM_E_INVALID_PARAMETER;
  1054. CDeleteMe<CNtAcl> dm (pAcl);
  1055. if ( !IsValidAclForNSSecurity ( pAcl ) )
  1056. {
  1057. return WBEM_E_INVALID_PARAMETER;
  1058. }
  1059. AutoRevertSecTlsFlag secFlag ( (LPVOID) 0 ) ;
  1060. IWbemClassObject * pThisNSObject = NULL;
  1061. HRESULT hr = CRepository::GetObject(pSession, pNSToSet, L"__thisnamespace=@",
  1062. WBEM_FLAG_USE_SECURITY_DESCRIPTOR, &pThisNSObject);
  1063. if(FAILED(hr))
  1064. return hr;
  1065. CReleaseMe rm1(pThisNSObject);
  1066. hr = CopySDIntoProperty(L"SECURITY_DESCRIPTOR", sd, pThisNSObject);
  1067. if(FAILED(hr))
  1068. return hr;
  1069. return CRepository::PutObject(pSession, pNSToSet, IID_IWbemClassObject, pThisNSObject,
  1070. WMIDB_DISABLE_EVENTS | WBEM_FLAG_USE_SECURITY_DESCRIPTOR);
  1071. }
  1072. HRESULT SetSecurityForNS(IWmiDbSession * pSession, IWmiDbHandle *pNSToSet,
  1073. IWmiDbSession * pParentSession, IWmiDbHandle * pNSParent, BOOL bExisting)
  1074. {
  1075. IWbemClassObject * pThisNSObject = NULL;
  1076. // Get the __thisnamespace object
  1077. AutoRevertSecTlsFlag secFlag ( (LPVOID) 0 ) ;
  1078. HRESULT hr = CRepository::GetObject(pSession, pNSToSet, L"__thisnamespace=@",
  1079. WBEM_FLAG_USE_SECURITY_DESCRIPTOR, &pThisNSObject);
  1080. if(FAILED(hr))
  1081. {
  1082. ERRORTRACE((LOG_WBEMCORE, "SetSecurityForNS: Failed to get __thisnamespace=@ object for current namespace <0x%X>!\n", hr));
  1083. return hr;
  1084. }
  1085. CReleaseMe rm1(pThisNSObject);
  1086. // Create the new SD
  1087. CNtSecurityDescriptor sd;
  1088. CNtAcl DestAcl;
  1089. if(bExisting)
  1090. {
  1091. // Fill in the security descriptor
  1092. hr = GetSDFromProperty(L"SECURITY_DESCRIPTOR", sd, pThisNSObject);
  1093. if(FAILED(hr))
  1094. {
  1095. ERRORTRACE((LOG_WBEMCORE, "SetSecurityForNS: Failure in GetSDFromProperty <0x%X>!\n", hr));
  1096. return hr;
  1097. }
  1098. hr = StripOutInheritedAces (sd);
  1099. if ( FAILED (hr) )
  1100. {
  1101. ERRORTRACE((LOG_WBEMCORE, "SetSecurityForNS: Failure in StripOutInheritedAces <0x%X>!\n", hr));
  1102. return hr;
  1103. }
  1104. }
  1105. else
  1106. {
  1107. // NT RAID: 198935 Prefix [marioh]
  1108. if ( !SetOwnerAndGroup(sd) )
  1109. {
  1110. ERRORTRACE((LOG_WBEMCORE, "SetSecurityForNS: Failure in SetOwnerAndGroup <0x%X>!\n", hr));
  1111. return WBEM_E_FAILED;
  1112. }
  1113. if ( !sd.SetDacl(&DestAcl) )
  1114. {
  1115. ERRORTRACE((LOG_WBEMCORE, "SetSecurityForNS: Failure in SetDacl <0x%X>!\n", hr));
  1116. return WBEM_E_FAILED;
  1117. }
  1118. }
  1119. CNtAcl * pacl = sd.GetDacl();
  1120. if (pacl == NULL)
  1121. {
  1122. ERRORTRACE((LOG_WBEMCORE, "SetSecurityForNS: Failure in GetDacl <0x%X>!\n", hr));
  1123. return WBEM_E_FAILED;
  1124. }
  1125. CDeleteMe<CNtAcl> del1(pacl);
  1126. if(pNSParent == NULL)
  1127. {
  1128. // If there is no parent, this must be root. Create a default one
  1129. hr = AddDefaultRootAces(pacl);
  1130. if (FAILED(hr))
  1131. {
  1132. ERRORTRACE((LOG_WBEMCORE, "SetSecurityForNS: Failure for AddDefaultRootAces <0x%X>!\n", hr));
  1133. return hr;
  1134. }
  1135. BOOL bRet = sd.SetDacl(pacl);
  1136. if (bRet == FALSE)
  1137. {
  1138. ERRORTRACE((LOG_WBEMCORE, "SetSecurityForNS: Failure for SetDacl (2) <0x%X>!\n", hr));
  1139. return WBEM_E_FAILED ;
  1140. }
  1141. }
  1142. else
  1143. {
  1144. // Get the parents __thisnamespace
  1145. IWbemClassObject * pParentThisNSObject = NULL;
  1146. hr = CRepository::GetObject(pParentSession, pNSParent, L"__thisnamespace=@",
  1147. WBEM_FLAG_USE_SECURITY_DESCRIPTOR, &pParentThisNSObject);
  1148. if(FAILED(hr))
  1149. {
  1150. ERRORTRACE((LOG_WBEMCORE, "SetSecurityForNS: Failed to get __thisnamespace=@ object for parent namespace <0x%X>!\n", hr));
  1151. return hr;
  1152. }
  1153. CReleaseMe rm11(pParentThisNSObject);
  1154. CNtSecurityDescriptor sdParent;
  1155. hr = GetSDFromProperty(L"SECURITY_DESCRIPTOR", sdParent, pParentThisNSObject);
  1156. if(FAILED(hr))
  1157. {
  1158. ERRORTRACE((LOG_WBEMCORE, "SetSecurityForNS: Failure for GetSDFromProperty <0x%X>!\n", hr));
  1159. return hr;
  1160. }
  1161. hr = CopyInheritAces(sd, sdParent);
  1162. if (FAILED(hr))
  1163. {
  1164. ERRORTRACE((LOG_WBEMCORE, "SetSecurityForNS: Failure for CopyInheritAces <0x%X>!\n", hr));
  1165. return hr;
  1166. }
  1167. }
  1168. if(FAILED(hr))
  1169. return hr;
  1170. hr = CopySDIntoProperty(L"SECURITY_DESCRIPTOR", sd, pThisNSObject);
  1171. if(FAILED(hr))
  1172. {
  1173. ERRORTRACE((LOG_WBEMCORE, "SetSecurityForNS: Failure for CopySDIntoProperty <0x%X>!\n", hr));
  1174. return hr;
  1175. }
  1176. // Extract sd property once more.
  1177. // ==============================
  1178. CNtSecurityDescriptor VerifiedSd;
  1179. hr = GetSDFromProperty(L"SECURITY_DESCRIPTOR", VerifiedSd, pThisNSObject);
  1180. if (FAILED(hr))
  1181. {
  1182. ERRORTRACE((LOG_WBEMCORE, "SetSecurityForNS: Failure for GetSDFromProperty (2) <0x%X>!\n", hr));
  1183. CVARIANT vPath;
  1184. pThisNSObject->Get(L"__PATH", 0, &vPath, 0, 0);
  1185. DEBUGTRACE((LOG_WBEMCORE, "Error creating security descriptor for new namespace %S", V_BSTR(&vPath) ));
  1186. return WBEM_E_CRITICAL_ERROR;
  1187. }
  1188. // Go ahead and store the object.
  1189. // ==============================
  1190. hr = CRepository::PutObject(pSession, pNSToSet, IID_IWbemClassObject, pThisNSObject,
  1191. WMIDB_DISABLE_EVENTS | WBEM_FLAG_USE_SECURITY_DESCRIPTOR);
  1192. if (FAILED(hr))
  1193. {
  1194. ERRORTRACE((LOG_WBEMCORE, "SetSecurityForNS: Failed to put secured object back <0x%X>!\n", hr));
  1195. }
  1196. return hr;
  1197. }
  1198. //***************************************************************************
  1199. //
  1200. // IsValidAclForNSSecurity
  1201. //
  1202. // Checks the ACEs for the following:
  1203. // 2. Standard NT ACE correctness [IsValidAce]
  1204. // 1. ACE inheritance/propogation flag correctness for WMI namespace
  1205. // security
  1206. //
  1207. // Parameters:
  1208. // <CNtAcl&> ACL to be checked
  1209. //
  1210. // Return:
  1211. // TRUE if ACL is valid
  1212. // FALSE if ACL is invalid
  1213. //
  1214. //***************************************************************************
  1215. BOOL IsValidAclForNSSecurity (CNtAcl* pAcl)
  1216. {
  1217. BOOL bRet = TRUE;
  1218. // Standard NT ACL check
  1219. if (!pAcl->IsValid()) return FALSE;
  1220. // Loop through all the ACEs in the list
  1221. ULONG ulNum = pAcl->GetNumAces( );
  1222. for ( ULONG ulCnt = 0; ulCnt < ulNum; ulCnt++ )
  1223. {
  1224. CNtAce* pAce = pAcl->GetAce ( ulCnt );
  1225. if (NULL == pAce) return FALSE;
  1226. CDeleteMe<CNtAce> autoDel ( pAce );
  1227. if ( !IsAceValid ( pAce->GetAccessMask(), pAce->GetType(), pAce->GetFlags() ) )
  1228. {
  1229. return FALSE;
  1230. }
  1231. }
  1232. return bRet;
  1233. }