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.

562 lines
19 KiB

  1. // --------------------------------------------------------------------------
  2. // Module Name: Access.cpp
  3. //
  4. // Copyright (c) 1999, Microsoft Corporation
  5. //
  6. // This file contains a few classes that assist with ACL manipulation on
  7. // objects to which a handle has already been opened. This handle must have
  8. // (obvisouly) have WRITE_DAC access.
  9. //
  10. // History: 1999-10-05 vtan created
  11. // 2000-02-01 vtan moved from Neptune to Whistler
  12. // --------------------------------------------------------------------------
  13. #include "StandardHeader.h"
  14. #include "Access.h"
  15. #include "StatusCode.h"
  16. // --------------------------------------------------------------------------
  17. // CSecurityDescriptor::CSecurityDescriptor
  18. //
  19. // Arguments: iCount = Count of ACCESS_CONTROLS passed in.
  20. // pAccessControl = Pointer to ACCESS_CONTROLS.
  21. //
  22. // Returns: <none>
  23. //
  24. // Purpose: Allocates and assigns the PSECURITY_DESCRIPTOR that
  25. // corresponds to the description given by the parameters. The
  26. // caller must release the memory allocated via LocalFree.
  27. //
  28. // History: 2000-10-05 vtan created
  29. // --------------------------------------------------------------------------
  30. PSECURITY_DESCRIPTOR CSecurityDescriptor::Create (int iCount, const ACCESS_CONTROL *pAccessControl)
  31. {
  32. PSECURITY_DESCRIPTOR pSecurityDescriptor;
  33. PSID *pSIDs;
  34. pSecurityDescriptor = NULL;
  35. // Allocate an array of PSIDs required to hold all the SIDs to add.
  36. pSIDs = reinterpret_cast<PSID*>(LocalAlloc(LPTR, iCount * sizeof(PSID)));
  37. if (pSIDs != NULL)
  38. {
  39. bool fSuccessfulAllocate;
  40. int i;
  41. const ACCESS_CONTROL *pAC;
  42. for (fSuccessfulAllocate = true, pAC = pAccessControl, i = 0; fSuccessfulAllocate && (i < iCount); ++pAC, ++i)
  43. {
  44. fSuccessfulAllocate = (AllocateAndInitializeSid(pAC->pSIDAuthority,
  45. static_cast<BYTE>(pAC->iSubAuthorityCount),
  46. pAC->dwSubAuthority0,
  47. pAC->dwSubAuthority1,
  48. pAC->dwSubAuthority2,
  49. pAC->dwSubAuthority3,
  50. pAC->dwSubAuthority4,
  51. pAC->dwSubAuthority5,
  52. pAC->dwSubAuthority6,
  53. pAC->dwSubAuthority7,
  54. &pSIDs[i]) != FALSE);
  55. }
  56. if (fSuccessfulAllocate)
  57. {
  58. DWORD dwACLSize;
  59. unsigned char *pBuffer;
  60. // Calculate the size of the ACL required by totalling the ACL header
  61. // struct and the 2 ACCESS_ALLOWED_ACE structs with the SID sizes.
  62. // Add the SECURITY_DESCRIPTOR struct size as well.
  63. dwACLSize = sizeof(ACL) + ((sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)) * 3);
  64. for (i = 0; i < iCount; ++i)
  65. {
  66. dwACLSize += GetLengthSid(pSIDs[i]);
  67. }
  68. // Allocate the buffer for everything and portion off the buffer to
  69. // the right place.
  70. pBuffer = static_cast<unsigned char*>(LocalAlloc(LMEM_FIXED, sizeof(SECURITY_DESCRIPTOR) + dwACLSize));
  71. if (pBuffer != NULL)
  72. {
  73. PSECURITY_DESCRIPTOR pSD;
  74. PACL pACL;
  75. pSD = reinterpret_cast<PSECURITY_DESCRIPTOR>(pBuffer);
  76. pACL = reinterpret_cast<PACL>(pBuffer + sizeof(SECURITY_DESCRIPTOR));
  77. // Initialize the ACL. Fill in the ACL.
  78. // Initialize the SECURITY_DESCRIPTOR. Set the security descriptor.
  79. if ((InitializeAcl(pACL, dwACLSize, ACL_REVISION) != FALSE) &&
  80. AddAces(pACL, pSIDs, iCount, pAccessControl) &&
  81. (InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION) != FALSE) &&
  82. (SetSecurityDescriptorDacl(pSD, TRUE, pACL, FALSE) != FALSE))
  83. {
  84. pSecurityDescriptor = pSD;
  85. }
  86. else
  87. {
  88. (HLOCAL)LocalFree(pBuffer);
  89. }
  90. }
  91. }
  92. for (i = iCount - 1; i >= 0; --i)
  93. {
  94. if (pSIDs[i] != NULL)
  95. {
  96. (void*)FreeSid(pSIDs[i]);
  97. }
  98. }
  99. (HLOCAL)LocalFree(pSIDs);
  100. }
  101. return(pSecurityDescriptor);
  102. }
  103. // --------------------------------------------------------------------------
  104. // CSecurityDescriptor::AddAces
  105. //
  106. // Arguments: pACL = PACL to add ACEs to.
  107. // pSIDs = Pointer to SIDs.
  108. // iCount = Count of ACCESS_CONTROLS passed in.
  109. // pAccessControl = Pointer to ACCESS_CONTROLS.
  110. //
  111. // Returns: bool
  112. //
  113. // Purpose: Adds access allowed ACEs to the given ACL.
  114. //
  115. // History: 2000-10-05 vtan created
  116. // --------------------------------------------------------------------------
  117. bool CSecurityDescriptor::AddAces (PACL pACL, PSID *pSIDs, int iCount, const ACCESS_CONTROL *pAC)
  118. {
  119. bool fResult;
  120. int i;
  121. for (fResult = true, i = 0; fResult && (i < iCount); ++pSIDs, ++pAC, ++i)
  122. {
  123. fResult = (AddAccessAllowedAce(pACL, ACL_REVISION, pAC->dwAccessMask, *pSIDs) != FALSE);
  124. }
  125. return(fResult);
  126. }
  127. // --------------------------------------------------------------------------
  128. // CAccessControlList::CAccessControlList
  129. //
  130. // Arguments: <none>
  131. //
  132. // Returns: <none>
  133. //
  134. // Purpose: Initializes the CAccessControlList object.
  135. //
  136. // History: 1999-10-05 vtan created
  137. // --------------------------------------------------------------------------
  138. CAccessControlList::CAccessControlList (void) :
  139. _pACL(NULL)
  140. {
  141. }
  142. // --------------------------------------------------------------------------
  143. // CAccessControlList::~CAccessControlList
  144. //
  145. // Arguments: <none>
  146. //
  147. // Returns: <none>
  148. //
  149. // Purpose: Releases resources used by the CAccessControlList object.
  150. //
  151. // History: 1999-10-05 vtan created
  152. // --------------------------------------------------------------------------
  153. CAccessControlList::~CAccessControlList (void)
  154. {
  155. ReleaseMemory(_pACL);
  156. }
  157. // --------------------------------------------------------------------------
  158. // CAccessControlList::operator PACL
  159. //
  160. // Arguments: <none>
  161. //
  162. // Returns: PACL
  163. //
  164. // Purpose: If the ACL has been constructed returns that value. If not
  165. // then the ACL is constructed from the ACEs and then returned.
  166. //
  167. // History: 1999-10-05 vtan created
  168. // --------------------------------------------------------------------------
  169. CAccessControlList::operator PACL (void)
  170. {
  171. PACL pACL;
  172. if (_pACL == NULL)
  173. {
  174. int i;
  175. DWORD dwACLSize, dwSizeOfAllACEs;
  176. pACL = NULL;
  177. dwSizeOfAllACEs = 0;
  178. // Walk thru all the ACEs to calculate the total size
  179. // required for the ACL.
  180. for (i = _ACEArray.GetCount() - 1; i >= 0; --i)
  181. {
  182. ACCESS_ALLOWED_ACE *pACE;
  183. pACE = static_cast<ACCESS_ALLOWED_ACE*>(_ACEArray.Get(i));
  184. dwSizeOfAllACEs += pACE->Header.AceSize;
  185. }
  186. dwACLSize = sizeof(ACL) + dwSizeOfAllACEs;
  187. _pACL = pACL = static_cast<ACL*>(LocalAlloc(LMEM_FIXED, dwACLSize));
  188. if (pACL != NULL)
  189. {
  190. TBOOL(InitializeAcl(pACL, dwACLSize, ACL_REVISION));
  191. // Construct the ACL in reverse order of the ACEs. This
  192. // allows CAccessControlList::Add to actually insert the
  193. // granted access at the head of the list which is usually
  194. // the desired result. The order of the ACEs is important!
  195. for (i = _ACEArray.GetCount() - 1; i >= 0; --i)
  196. {
  197. ACCESS_ALLOWED_ACE *pACE;
  198. pACE = static_cast<ACCESS_ALLOWED_ACE*>(_ACEArray.Get(i));
  199. TBOOL(AddAccessAllowedAceEx(pACL, ACL_REVISION, pACE->Header.AceFlags, pACE->Mask, reinterpret_cast<PSID>(&pACE->SidStart)));
  200. }
  201. }
  202. }
  203. else
  204. {
  205. pACL = _pACL;
  206. }
  207. return(pACL);
  208. }
  209. // --------------------------------------------------------------------------
  210. // CAccessControlList::Add
  211. //
  212. // Arguments: pSID = SID to grant access to.
  213. // dwMask = Level of access to grant.
  214. // ucInheritence = Type of inheritence for this access.
  215. //
  216. // Returns: NTSTATUS
  217. //
  218. // Purpose: Adds the given SID, access and inheritence type as an ACE to
  219. // the list of ACEs to build into an ACL. The ACE array is
  220. // allocated in blocks of 16 pointers to reduce repeated calls
  221. // to allocate memory if many ACEs are added.
  222. //
  223. // History: 1999-10-05 vtan created
  224. // --------------------------------------------------------------------------
  225. NTSTATUS CAccessControlList::Add (PSID pSID, ACCESS_MASK dwMask, UCHAR ucInheritence)
  226. {
  227. NTSTATUS status;
  228. DWORD dwSIDLength, dwACESize;
  229. ACCESS_ALLOWED_ACE *pACE;
  230. dwSIDLength = GetLengthSid(pSID);
  231. dwACESize = sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + dwSIDLength;
  232. pACE = static_cast<ACCESS_ALLOWED_ACE*>(LocalAlloc(LMEM_FIXED, dwACESize));
  233. if (pACE != NULL)
  234. {
  235. pACE->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
  236. pACE->Header.AceFlags = ucInheritence;
  237. pACE->Header.AceSize = static_cast<USHORT>(dwACESize);
  238. pACE->Mask = dwMask;
  239. CopyMemory(&pACE->SidStart, pSID, dwSIDLength);
  240. status = _ACEArray.Add(pACE);
  241. if (STATUS_NO_MEMORY == status)
  242. {
  243. (HLOCAL)LocalFree(pACE);
  244. }
  245. }
  246. else
  247. {
  248. status = STATUS_NO_MEMORY;
  249. }
  250. return(status);
  251. }
  252. // --------------------------------------------------------------------------
  253. // CAccessControlList::Remove
  254. //
  255. // Arguments: pSID = SID to revoke access from.
  256. //
  257. // Returns: NTSTATUS
  258. //
  259. // Purpose: Removes all references to the given SID from the ACE list.
  260. //
  261. // History: 1999-10-05 vtan created
  262. // --------------------------------------------------------------------------
  263. NTSTATUS CAccessControlList::Remove (PSID pSID)
  264. {
  265. NTSTATUS status;
  266. // Set up for an iteration of the array.
  267. _searchSID = pSID;
  268. _iFoundIndex = -1;
  269. status = _ACEArray.Iterate(this);
  270. while (NT_SUCCESS(status) && (_iFoundIndex >= 0))
  271. {
  272. // When the SIDs are found to match remove this entry.
  273. // ALL matching SID entries are removed!
  274. status = _ACEArray.Remove(_iFoundIndex);
  275. if (NT_SUCCESS(status))
  276. {
  277. _iFoundIndex = -1;
  278. status = _ACEArray.Iterate(this);
  279. }
  280. }
  281. return(status);
  282. }
  283. // --------------------------------------------------------------------------
  284. // CAccessControlList::Callback
  285. //
  286. // Arguments: pvData = Pointer to the array index data.
  287. // iElementIndex = Index into the array.
  288. //
  289. // Returns: NTSTATUS
  290. //
  291. // Purpose: Callback from the CDynamicArray::Iterate function. This
  292. // method can be used to process the array contents by index or
  293. // by content when iterating thru the array. Return an error
  294. // status to stop the iteration and have that value returned to
  295. // the caller of CDynamicArray::Iterate.
  296. //
  297. // Converts the pointer into a pointer to an ACCESS_ALLOWED_ACE.
  298. // The compares the SID in that ACE to the desired search SID.
  299. // Saves the index if found.
  300. //
  301. // History: 1999-11-15 vtan created
  302. // --------------------------------------------------------------------------
  303. NTSTATUS CAccessControlList::Callback (const void *pvData, int iElementIndex)
  304. {
  305. const ACCESS_ALLOWED_ACE *pACE;
  306. pACE = *reinterpret_cast<const ACCESS_ALLOWED_ACE* const*>(pvData);
  307. if (EqualSid(reinterpret_cast<PSID>(const_cast<unsigned long*>((&pACE->SidStart))), _searchSID) != FALSE)
  308. {
  309. _iFoundIndex = iElementIndex;
  310. }
  311. return(STATUS_SUCCESS);
  312. }
  313. // --------------------------------------------------------------------------
  314. // CSecuredObject::CSecuredObject
  315. //
  316. // Arguments: hObject = Optional HANDLE to the object to secure.
  317. // seObjectType = Type of object specified in handle.
  318. //
  319. // Returns: <none>
  320. //
  321. // Purpose: Sets the optionally given HANDLE into the member variables.
  322. // The HANDLE is duplicated so the caller must release their
  323. // HANDLE.
  324. //
  325. // In order for this class to work the handle you pass it MUST
  326. // have DUPLICATE access as well as READ_CONTROL and WRITE_DAC.
  327. //
  328. // History: 1999-10-05 vtan created
  329. // --------------------------------------------------------------------------
  330. CSecuredObject::CSecuredObject (HANDLE hObject, SE_OBJECT_TYPE seObjectType) :
  331. _hObject(hObject),
  332. _seObjectType(seObjectType)
  333. {
  334. }
  335. // --------------------------------------------------------------------------
  336. // CSecuredObject::~CSecuredObject
  337. //
  338. // Arguments: <none>
  339. //
  340. // Returns: <none>
  341. //
  342. // Purpose: Release our HANDLE reference.
  343. //
  344. // History: 1999-10-05 vtan created
  345. // --------------------------------------------------------------------------
  346. CSecuredObject::~CSecuredObject (void)
  347. {
  348. }
  349. // --------------------------------------------------------------------------
  350. // CSecuredObject::Allow
  351. //
  352. // Arguments: pSID = SID to grant access to.
  353. // dwMask = Level of access to grant.
  354. // ucInheritence = Type of inheritence for this access.
  355. //
  356. // Returns: NTSTATUS
  357. //
  358. // Purpose: Get the DACL for the object. Add the desired access. Set the
  359. // DACL for the object.
  360. //
  361. // History: 1999-10-05 vtan created
  362. // --------------------------------------------------------------------------
  363. NTSTATUS CSecuredObject::Allow (PSID pSID, ACCESS_MASK dwMask, UCHAR ucInheritence) const
  364. {
  365. NTSTATUS status;
  366. CAccessControlList accessControlList;
  367. status = GetDACL(accessControlList);
  368. if (NT_SUCCESS(status))
  369. {
  370. status = accessControlList.Add(pSID, dwMask, ucInheritence);
  371. if (NT_SUCCESS(status))
  372. {
  373. status = SetDACL(accessControlList);
  374. }
  375. }
  376. return(status);
  377. }
  378. // --------------------------------------------------------------------------
  379. // CSecuredObject::Remove
  380. //
  381. // Arguments: pSID = SID to revoke access from.
  382. //
  383. // Returns: NTSTATUS
  384. //
  385. // Purpose: Get the DACL for the object. Remove the desired access. Set
  386. // the DACL for the object.
  387. //
  388. // History: 1999-10-05 vtan created
  389. // --------------------------------------------------------------------------
  390. NTSTATUS CSecuredObject::Remove (PSID pSID) const
  391. {
  392. NTSTATUS status;
  393. CAccessControlList accessControlList;
  394. status = GetDACL(accessControlList);
  395. if (NT_SUCCESS(status))
  396. {
  397. status = accessControlList.Remove(pSID);
  398. if (NT_SUCCESS(status))
  399. {
  400. status = SetDACL(accessControlList);
  401. }
  402. }
  403. return(status);
  404. }
  405. // --------------------------------------------------------------------------
  406. // CSecuredObject::GetDACL
  407. //
  408. // Arguments: accessControlList = CAccessControlList that gets the
  409. // decomposed DACL into ACEs.
  410. //
  411. // Returns: NTSTATUS
  412. //
  413. // Purpose: Gets the object's DACL and walk the individual ACEs and add
  414. // this access to the CAccessControlList object given. The access
  415. // is walked backward to allow CAccessControlList::Add to add to
  416. // end of the list but actually add to the head of the list.
  417. //
  418. // History: 1999-10-05 vtan created
  419. // --------------------------------------------------------------------------
  420. NTSTATUS CSecuredObject::GetDACL (CAccessControlList& accessControlList) const
  421. {
  422. NTSTATUS status;
  423. DWORD dwResult;
  424. PACL pDACL;
  425. PSECURITY_DESCRIPTOR pSD;
  426. status = STATUS_SUCCESS;
  427. pSD = NULL;
  428. pDACL = NULL;
  429. dwResult = GetSecurityInfo(_hObject,
  430. _seObjectType,
  431. DACL_SECURITY_INFORMATION,
  432. NULL,
  433. NULL,
  434. &pDACL,
  435. NULL,
  436. &pSD);
  437. if ((ERROR_SUCCESS == dwResult) && (pDACL != NULL))
  438. {
  439. int i;
  440. ACCESS_ALLOWED_ACE *pAce;
  441. for (i = pDACL->AceCount - 1; NT_SUCCESS(status) && (i >= 0); --i)
  442. {
  443. if (GetAce(pDACL, i, reinterpret_cast<void**>(&pAce)) != FALSE)
  444. {
  445. ASSERTMSG(pAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE, "Expect only access allowed ACEs in CSecuredObject::MakeIndividualACEs");
  446. status = accessControlList.Add(reinterpret_cast<PSID>(&pAce->SidStart), pAce->Mask, pAce->Header.AceFlags);
  447. }
  448. }
  449. }
  450. ReleaseMemory(pSD);
  451. return(status);
  452. }
  453. // --------------------------------------------------------------------------
  454. // CSecuredObject::SetDACL
  455. //
  456. // Arguments: accessControlList = CAccessControlList that contains all
  457. // ACEs to build into an ACL.
  458. //
  459. // Returns: NTSTATUS
  460. //
  461. // Purpose: Builds the ACL for the given ACE list and sets the DACL into
  462. // the object handle.
  463. //
  464. // History: 1999-10-05 vtan created
  465. // --------------------------------------------------------------------------
  466. NTSTATUS CSecuredObject::SetDACL (CAccessControlList& accessControlList) const
  467. {
  468. NTSTATUS status;
  469. DWORD dwResult;
  470. dwResult = SetSecurityInfo(_hObject,
  471. _seObjectType,
  472. DACL_SECURITY_INFORMATION,
  473. NULL,
  474. NULL,
  475. accessControlList,
  476. NULL);
  477. if (ERROR_SUCCESS == dwResult)
  478. {
  479. status = STATUS_SUCCESS;
  480. }
  481. else
  482. {
  483. status = CStatusCode::StatusCodeOfErrorCode(dwResult);
  484. }
  485. return(status);
  486. }