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.

490 lines
14 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1996 - 1999
  6. //
  7. // File: permset.cpp
  8. //
  9. // This file contains the implementation for the CPermissionSet class
  10. //
  11. //--------------------------------------------------------------------------
  12. #include "aclpriv.h"
  13. #include "permset.h"
  14. void
  15. CPermissionSet::Reset()
  16. {
  17. TraceEnter(TRACE_PERMSET, "CPermissionSet::Reset");
  18. // Clear the lists
  19. if (m_hPermList != NULL)
  20. {
  21. DSA_Destroy(m_hPermList);
  22. m_hPermList = NULL;
  23. }
  24. DestroyDPA(m_hAdvPermList);
  25. m_hAdvPermList = NULL;
  26. m_fObjectAcesPresent = FALSE;
  27. TraceLeaveVoid();
  28. }
  29. void
  30. CPermissionSet::ResetAdvanced()
  31. {
  32. TraceEnter(TRACE_PERMSET, "CPermissionSet::ResetAdvanced");
  33. DestroyDPA(m_hAdvPermList);
  34. m_hAdvPermList = NULL;
  35. TraceLeaveVoid();
  36. }
  37. BOOL
  38. CPermissionSet::AddAce(LPCGUID pguid, ACCESS_MASK mask, DWORD dwFlags)
  39. {
  40. PERMISSION perm = { mask, dwFlags, 0 };
  41. if (pguid != NULL)
  42. perm.guid = *pguid;
  43. return AddPermission(&perm);
  44. }
  45. BOOL
  46. CPermissionSet::AddPermission(PPERMISSION pPerm)
  47. {
  48. BOOL bObjectTypePresent = FALSE;
  49. TraceEnter(TRACE_PERMSET, "CPermissionSet::AddAce");
  50. TraceAssert(pPerm != NULL);
  51. if (!IsEqualGUID(pPerm->guid, GUID_NULL))
  52. bObjectTypePresent = TRUE;
  53. if (m_hPermList == NULL)
  54. {
  55. m_hPermList = DSA_Create(SIZEOF(PERMISSION), 4);
  56. if (m_hPermList == NULL)
  57. TraceLeaveValue(FALSE);
  58. }
  59. else
  60. {
  61. //
  62. // Try to merge with an existing entry in the list.
  63. //
  64. UINT cItems = DSA_GetItemCount(m_hPermList);
  65. while (cItems > 0)
  66. {
  67. PPERMISSION pPermCompare;
  68. DWORD dwMergeFlags;
  69. DWORD dwMergeResult;
  70. DWORD dwMergeStatus;
  71. --cItems;
  72. pPermCompare = (PPERMISSION)DSA_GetItemPtr(m_hPermList, cItems);
  73. dwMergeFlags = 0;
  74. if (bObjectTypePresent)
  75. dwMergeFlags |= MF_OBJECT_TYPE_1_PRESENT;
  76. if (!IsEqualGUID(pPermCompare->guid, GUID_NULL))
  77. dwMergeFlags |= MF_OBJECT_TYPE_2_PRESENT;
  78. if (!(dwMergeFlags & (MF_OBJECT_TYPE_1_PRESENT | MF_OBJECT_TYPE_2_PRESENT)))
  79. {
  80. // Neither are present, so they are the same
  81. dwMergeFlags |= MF_OBJECT_TYPE_EQUAL;
  82. }
  83. else if (IsEqualGUID(pPermCompare->guid, pPerm->guid))
  84. dwMergeFlags |= MF_OBJECT_TYPE_EQUAL;
  85. dwMergeStatus = MergeAceHelper(pPerm->dwFlags, // #1
  86. pPerm->mask,
  87. pPermCompare->dwFlags, // #2
  88. pPermCompare->mask,
  89. dwMergeFlags,
  90. &dwMergeResult);
  91. if (dwMergeStatus == MERGE_MODIFIED_FLAGS)
  92. {
  93. pPerm->dwFlags = dwMergeResult;
  94. dwMergeStatus = MERGE_OK_1;
  95. }
  96. else if (dwMergeStatus == MERGE_MODIFIED_MASK)
  97. {
  98. pPerm->mask = dwMergeResult;
  99. dwMergeStatus = MERGE_OK_1;
  100. }
  101. if (dwMergeStatus == MERGE_OK_1)
  102. {
  103. //
  104. // The new permission implies the existing permission, so
  105. // the existing one can be removed.
  106. //
  107. DSA_DeleteItem(m_hPermList, cItems);
  108. //
  109. // Keep looking. Maybe we can remove some more entries
  110. // before adding the new one.
  111. //
  112. }
  113. else if (dwMergeStatus == MERGE_OK_2)
  114. {
  115. //
  116. // The existing permission implies the new permission, so
  117. // there is nothing to do here.
  118. //
  119. TraceLeaveValue(TRUE);
  120. }
  121. }
  122. }
  123. // Ok, add the new permission to the list.
  124. DSA_AppendItem(m_hPermList, pPerm);
  125. if (bObjectTypePresent)
  126. m_fObjectAcesPresent = TRUE;
  127. TraceLeaveValue(TRUE);
  128. }
  129. BOOL
  130. CPermissionSet::AddAdvancedAce(PACE_HEADER pAce)
  131. {
  132. TraceEnter(TRACE_PERMSET, "CPermissionSet::AddAdvancedAce");
  133. TraceAssert(pAce != NULL);
  134. // Create list if necessary
  135. if (m_hAdvPermList == NULL)
  136. {
  137. m_hAdvPermList = DPA_Create(4);
  138. if (m_hAdvPermList == NULL)
  139. {
  140. TraceMsg("DPA_Create failed");
  141. TraceLeaveValue(FALSE);
  142. }
  143. }
  144. // This is as big as we need, but sometimes incoming ACEs are extra big.
  145. UINT nAceLen = SIZEOF(KNOWN_OBJECT_ACE) + 2*SIZEOF(GUID) - SIZEOF(DWORD)
  146. + GetLengthSid(GetAceSid(pAce));
  147. // Use the incoming AceSize only if it's smaller
  148. if (pAce->AceSize < nAceLen)
  149. nAceLen = pAce->AceSize;
  150. // Copy the ACE and add it to the list.
  151. PACE_HEADER pAceCopy = (PACE_HEADER)LocalAlloc(LMEM_FIXED, nAceLen);
  152. if (pAceCopy == NULL)
  153. {
  154. TraceMsg("LocalAlloc failed");
  155. TraceLeaveValue(FALSE);
  156. }
  157. CopyMemory(pAceCopy, pAce, nAceLen);
  158. pAceCopy->AceSize = (USHORT)nAceLen;
  159. DPA_AppendPtr(m_hAdvPermList, pAceCopy);
  160. TraceLeaveValue(TRUE);
  161. }
  162. UINT
  163. CPermissionSet::GetPermCount(BOOL fIncludeAdvAces) const
  164. {
  165. ULONG cAces = 0;
  166. TraceEnter(TRACE_PERMSET, "CPermissionSet::GetPermCount");
  167. if (m_hPermList != NULL)
  168. cAces = DSA_GetItemCount(m_hPermList);
  169. if (fIncludeAdvAces && m_hAdvPermList != NULL)
  170. cAces += DPA_GetPtrCount(m_hAdvPermList);
  171. TraceLeaveValue(cAces);
  172. }
  173. ULONG
  174. CPermissionSet::GetAclLength(ULONG cbSid) const
  175. {
  176. // Return an estimate of the buffer size needed to hold the
  177. // requested ACEs. The size of the ACL header is NOT INCLUDED.
  178. ULONG nAclLength = 0;
  179. ULONG cAces;
  180. ULONG nAceSize = SIZEOF(KNOWN_ACE) - SIZEOF(DWORD) + cbSid;
  181. ULONG nObjectAceSize = SIZEOF(KNOWN_OBJECT_ACE) + SIZEOF(GUID) - SIZEOF(DWORD) + cbSid;
  182. TraceEnter(TRACE_PERMSET, "CPermissionSet::GetAclLength");
  183. if (m_hPermList != NULL)
  184. {
  185. cAces = DSA_GetItemCount(m_hPermList);
  186. if (m_fObjectAcesPresent)
  187. nAclLength += cAces * nObjectAceSize;
  188. else
  189. nAclLength += cAces * nAceSize;
  190. }
  191. if (m_hAdvPermList != NULL)
  192. {
  193. cAces = DPA_GetPtrCount(m_hAdvPermList);
  194. nAclLength += cAces * (nObjectAceSize + SIZEOF(GUID));
  195. }
  196. TraceLeaveValue(nAclLength);
  197. }
  198. BOOL
  199. CPermissionSet::AppendToAcl(PACL pAcl,
  200. PACE_HEADER *ppAcePos, // position to copy first ACE
  201. PSID pSid,
  202. BOOL fAllowAce,
  203. DWORD dwFlags) const
  204. {
  205. PACE_HEADER pAce;
  206. UINT cAces;
  207. DWORD dwSidSize;
  208. DWORD dwAceSize;
  209. PPERMISSION pPerm;
  210. UCHAR uAceType;
  211. PSID psidT;
  212. TraceEnter(TRACE_PERMSET, "CPermissionSet::AppendToAcl");
  213. TraceAssert(pAcl != NULL);
  214. TraceAssert(ppAcePos != NULL);
  215. TraceAssert(pSid != NULL);
  216. if (*ppAcePos == NULL || (ULONG_PTR)*ppAcePos < (ULONG_PTR)FirstAce(pAcl))
  217. *ppAcePos = (PACE_HEADER)FirstAce(pAcl);
  218. TraceAssert((ULONG_PTR)*ppAcePos >= (ULONG_PTR)FirstAce(pAcl) &&
  219. (ULONG_PTR)*ppAcePos <= (ULONG_PTR)ByteOffset(pAcl, pAcl->AclSize));
  220. dwSidSize = GetLengthSid(pSid);
  221. dwAceSize = SIZEOF(KNOWN_ACE) - SIZEOF(DWORD) + dwSidSize;
  222. uAceType = (UCHAR)(fAllowAce ? ACCESS_ALLOWED_ACE_TYPE : ACCESS_DENIED_ACE_TYPE);
  223. cAces = GetPermCount();
  224. while (cAces > 0)
  225. {
  226. BOOL bObjectAce;
  227. pPerm = (PPERMISSION)DSA_GetItemPtr(m_hPermList, --cAces);
  228. if (pPerm == NULL)
  229. continue;
  230. bObjectAce = !IsEqualGUID(pPerm->guid, GUID_NULL);
  231. if (bObjectAce && !(dwFlags & PS_OBJECT))
  232. continue;
  233. else if (!bObjectAce && !(dwFlags & PS_NONOBJECT))
  234. continue;
  235. pAce = *ppAcePos;
  236. // Make sure the buffer is large enough.
  237. if ((ULONG_PTR)ByteOffset(*ppAcePos, dwAceSize) > (ULONG_PTR)ByteOffset(pAcl, pAcl->AclSize))
  238. {
  239. TraceMsg("ACL buffer too small");
  240. TraceAssert(FALSE);
  241. TraceLeaveValue(FALSE);
  242. }
  243. TraceAssert(!IsBadWritePtr(*ppAcePos, dwAceSize));
  244. // Copy the header and mask
  245. pAce->AceType = uAceType;
  246. pAce->AceFlags = (UCHAR)pPerm->dwFlags;
  247. pAce->AceSize = (USHORT)dwAceSize;
  248. ((PKNOWN_ACE)pAce)->Mask = pPerm->mask;
  249. // Get the normal SID location
  250. psidT = &((PKNOWN_ACE)pAce)->SidStart;
  251. if (bObjectAce)
  252. {
  253. //
  254. // The Object ACEs that we deal with directly do not have an
  255. // Inherit GUID present. Those ACEs end up in m_hAdvPermList.
  256. //
  257. GUID *pGuid;
  258. // Adjust AceType and AceSize and set the object Flags
  259. pAce->AceType += ACCESS_ALLOWED_OBJECT_ACE_TYPE - ACCESS_ALLOWED_ACE_TYPE;
  260. pAce->AceSize += SIZEOF(KNOWN_OBJECT_ACE) - SIZEOF(KNOWN_ACE) + SIZEOF(GUID);
  261. ((PKNOWN_OBJECT_ACE)pAce)->Flags = ACE_OBJECT_TYPE_PRESENT;
  262. // Get the object type guid location
  263. pGuid = RtlObjectAceObjectType(pAce);
  264. // We just set the flag for this, so it can't be NULL
  265. TraceAssert(pGuid);
  266. // Make sure the buffer is large enough.
  267. if ((ULONG_PTR)ByteOffset(pAce, pAce->AceSize) > (ULONG_PTR)ByteOffset(pAcl, pAcl->AclSize))
  268. {
  269. TraceMsg("ACL buffer too small");
  270. TraceAssert(FALSE);
  271. TraceLeaveValue(FALSE);
  272. }
  273. TraceAssert(!IsBadWritePtr(pGuid, SIZEOF(GUID)));
  274. // Copy the object type guid
  275. *pGuid = pPerm->guid;
  276. // Get new SID location
  277. psidT = RtlObjectAceSid(pAce);
  278. // Adjust ACL revision
  279. if (pAcl->AclRevision < ACL_REVISION_DS)
  280. pAcl->AclRevision = ACL_REVISION_DS;
  281. }
  282. // Copy the SID
  283. TraceAssert(!IsBadWritePtr(psidT, dwSidSize));
  284. CopyMemory(psidT, pSid, dwSidSize);
  285. // Move to next ACE position
  286. pAcl->AceCount++;
  287. *ppAcePos = (PACE_HEADER)NextAce(pAce);
  288. }
  289. if ((dwFlags & PS_OBJECT) && m_hAdvPermList != NULL)
  290. {
  291. cAces = DPA_GetPtrCount(m_hAdvPermList);
  292. while (cAces > 0)
  293. {
  294. pAce = (PACE_HEADER)DPA_FastGetPtr(m_hAdvPermList, --cAces);
  295. if (pAce == NULL)
  296. continue;
  297. // Make sure the buffer is large enough.
  298. if ((ULONG_PTR)ByteOffset(*ppAcePos, pAce->AceSize) > (ULONG_PTR)ByteOffset(pAcl, pAcl->AclSize))
  299. {
  300. TraceMsg("ACL buffer too small");
  301. TraceAssert(FALSE);
  302. TraceLeaveValue(FALSE);
  303. }
  304. TraceAssert(!IsBadWritePtr(*ppAcePos, pAce->AceSize));
  305. // Copy the ACE
  306. CopyMemory(*ppAcePos, pAce, pAce->AceSize);
  307. // Adjust ACL revision
  308. if (IsObjectAceType(pAce) && pAcl->AclRevision < ACL_REVISION_DS)
  309. pAcl->AclRevision = ACL_REVISION_DS;
  310. // Move to next ACE position
  311. pAcl->AceCount++;
  312. *ppAcePos = (PACE_HEADER)NextAce(*ppAcePos);
  313. }
  314. }
  315. TraceLeaveValue(TRUE);
  316. }
  317. void
  318. CPermissionSet::ConvertInheritedAces(CPermissionSet &permInherited)
  319. {
  320. UINT cItems;
  321. TraceEnter(TRACE_PERMSET, "CPermissionSet::ConvertInheritedAces");
  322. if (permInherited.m_hPermList != NULL)
  323. {
  324. PPERMISSION pPerm;
  325. cItems = DSA_GetItemCount(permInherited.m_hPermList);
  326. while (cItems)
  327. {
  328. --cItems;
  329. pPerm = (PPERMISSION)DSA_GetItemPtr(permInherited.m_hPermList, cItems);
  330. if (pPerm != NULL)
  331. {
  332. pPerm->dwFlags &= ~INHERITED_ACE;
  333. AddPermission(pPerm);
  334. }
  335. }
  336. }
  337. if (permInherited.m_hAdvPermList != NULL)
  338. {
  339. PACE_HEADER pAceHeader;
  340. cItems = DPA_GetPtrCount(permInherited.m_hAdvPermList);
  341. while (cItems)
  342. {
  343. --cItems;
  344. pAceHeader = (PACE_HEADER)DPA_FastGetPtr(permInherited.m_hAdvPermList, cItems);
  345. if (pAceHeader != NULL)
  346. {
  347. pAceHeader->AceFlags &= ~INHERITED_ACE;
  348. AddAdvancedAce(pAceHeader);
  349. }
  350. }
  351. }
  352. permInherited.Reset();
  353. TraceLeaveVoid();
  354. }
  355. //Removes permission. If bInheritFlag, match inheritance flags before
  356. //removing permission
  357. void
  358. CPermissionSet::RemovePermission(PPERMISSION pPerm, BOOL bInheritFlag )
  359. {
  360. BOOL bObjectAcePresent = FALSE;
  361. TraceEnter(TRACE_PERMSET, "CPermissionSet::RemovePermission");
  362. TraceAssert(pPerm != NULL);
  363. if (m_hPermList)
  364. {
  365. BOOL bNullGuid = IsEqualGUID(pPerm->guid, GUID_NULL);
  366. UINT cItems = DSA_GetItemCount(m_hPermList);
  367. while (cItems > 0)
  368. {
  369. PPERMISSION pPermCompare;
  370. BOOL bNullGuidCompare;
  371. --cItems;
  372. pPermCompare = (PPERMISSION)DSA_GetItemPtr(m_hPermList, cItems);
  373. bNullGuidCompare = IsEqualGUID(pPermCompare->guid, GUID_NULL);
  374. if (bNullGuid || bNullGuidCompare || IsEqualGUID(pPermCompare->guid, pPerm->guid))
  375. {
  376. if( !bInheritFlag || ( (pPermCompare->dwFlags & VALID_INHERIT_FLAGS) == (pPerm->dwFlags & VALID_INHERIT_FLAGS) ) )
  377. {
  378. pPermCompare->mask &= ~pPerm->mask;
  379. if (0 == pPermCompare->mask)
  380. DSA_DeleteItem(m_hPermList, cItems);
  381. else if (!bNullGuidCompare)
  382. bObjectAcePresent = TRUE;
  383. }
  384. }
  385. else if (!bNullGuidCompare)
  386. bObjectAcePresent = TRUE;
  387. }
  388. }
  389. m_fObjectAcesPresent = bObjectAcePresent;
  390. TraceLeaveVoid();
  391. }