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.

435 lines
16 KiB

  1. #include "pch.h"
  2. #pragma hdrstop
  3. #include "sfmsec.h"
  4. #define AFP_MIN_ACCESS (FILE_READ_ATTRIBUTES | READ_CONTROL)
  5. #define AFP_READ_ACCESS (READ_CONTROL | \
  6. FILE_READ_ATTRIBUTES | \
  7. FILE_TRAVERSE | \
  8. FILE_LIST_DIRECTORY | \
  9. FILE_READ_EA)
  10. #define AFP_WRITE_ACCESS (FILE_ADD_FILE | \
  11. FILE_ADD_SUBDIRECTORY| \
  12. FILE_WRITE_ATTRIBUTES| \
  13. FILE_WRITE_EA | \
  14. DELETE)
  15. #define AFP_OWNER_ACCESS (WRITE_DAC | \
  16. WRITE_OWNER)
  17. SID AfpSidWorld = { 1, 1, SECURITY_WORLD_SID_AUTHORITY, SECURITY_WORLD_RID };
  18. SID AfpSidNull = { 1, 1, SECURITY_NULL_SID_AUTHORITY, SECURITY_NULL_RID };
  19. SID AfpSidSystem = { 1, 1, SECURITY_NT_AUTHORITY, SECURITY_LOCAL_SYSTEM_RID };
  20. SID AfpSidCrtrOwner = { 1, 1, SECURITY_CREATOR_SID_AUTHORITY, SECURITY_CREATOR_OWNER_RID };
  21. SID AfpSidCrtrGroup = { 1, 1, SECURITY_CREATOR_SID_AUTHORITY, SECURITY_CREATOR_GROUP_RID };
  22. /*** afpAddAceToAcl
  23. *
  24. * Build an Ace corres. to the Sid(s) and mask and add these to the Acl. It is
  25. * assumed that the Acl has space for the Aces. If the Mask is 0 (i.e. no access)
  26. * the Ace added is a DENY Ace, else a ALLOWED ACE is added.
  27. */
  28. PACCESS_ALLOWED_ACE
  29. afpAddAceToAcl(
  30. IN PACL pAcl,
  31. IN PACCESS_ALLOWED_ACE pAce,
  32. IN ACCESS_MASK Mask,
  33. IN PSID pSid,
  34. IN PSID pSidInherit OPTIONAL
  35. )
  36. {
  37. NTSTATUS Status = STATUS_SUCCESS;
  38. // Add a vanilla ace
  39. pAcl->AceCount ++;
  40. pAce->Mask = Mask | SYNCHRONIZE | AFP_MIN_ACCESS;
  41. pAce->Header.AceFlags = 0;
  42. pAce->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
  43. pAce->Header.AceSize = (USHORT)(sizeof(ACE_HEADER) + sizeof(ACCESS_MASK) +
  44. RtlLengthSid(pSid));
  45. Status = RtlCopySid(RtlLengthSid(pSid), (PSID)(&pAce->SidStart), pSid);
  46. if (!NT_SUCCESS(Status))
  47. {
  48. ASSERT(0);
  49. }
  50. // Now add an inherit ace
  51. //
  52. pAce = (PACCESS_ALLOWED_ACE)((PBYTE)pAce + pAce->Header.AceSize);
  53. pAcl->AceCount ++;
  54. pAce->Mask = Mask | SYNCHRONIZE | AFP_MIN_ACCESS;
  55. pAce->Header.AceFlags = CONTAINER_INHERIT_ACE |
  56. OBJECT_INHERIT_ACE |
  57. INHERIT_ONLY_ACE;
  58. pAce->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
  59. pAce->Header.AceSize = (USHORT)(sizeof(ACE_HEADER) + sizeof(ACCESS_MASK) +
  60. RtlLengthSid(pSid));
  61. Status = RtlCopySid(RtlLengthSid(pSid), (PSID)(&pAce->SidStart), pSid);
  62. if (!NT_SUCCESS(Status))
  63. {
  64. ASSERT(0);
  65. }
  66. // Now add an inherit ace for the CreatorOwner/CreatorGroup
  67. if (ARGUMENT_PRESENT(pSidInherit))
  68. {
  69. pAce = (PACCESS_ALLOWED_ACE)((PBYTE)pAce + pAce->Header.AceSize);
  70. pAcl->AceCount ++;
  71. pAce->Mask = Mask | SYNCHRONIZE | AFP_MIN_ACCESS;
  72. pAce->Header.AceFlags = CONTAINER_INHERIT_ACE |
  73. OBJECT_INHERIT_ACE |
  74. INHERIT_ONLY_ACE;
  75. pAce->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
  76. pAce->Header.AceSize = (USHORT)(sizeof(ACE_HEADER) + sizeof(ACCESS_MASK) +
  77. RtlLengthSid(pSidInherit));
  78. Status = RtlCopySid(RtlLengthSid(pSidInherit), (PSID)(&pAce->SidStart), pSidInherit);
  79. if (!NT_SUCCESS(Status))
  80. {
  81. ASSERT(0);
  82. }
  83. }
  84. return ((PACCESS_ALLOWED_ACE)((PBYTE)pAce + pAce->Header.AceSize));
  85. }
  86. /*** afpMoveAces
  87. *
  88. * Move a bunch of aces from the old security descriptor to the new security
  89. * descriptor.
  90. */
  91. PACCESS_ALLOWED_ACE
  92. afpMoveAces(
  93. IN PACL pOldDacl,
  94. IN PACCESS_ALLOWED_ACE pAceStart,
  95. IN PSID pSidOldOwner,
  96. IN PSID pSidNewOwner,
  97. IN PSID pSidOldGroup,
  98. IN PSID pSidNewGroup,
  99. IN BOOLEAN DenyAces,
  100. IN BOOLEAN InheritedAces,
  101. IN OUT PACL pNewDacl
  102. )
  103. {
  104. USHORT i;
  105. PACCESS_ALLOWED_ACE pAceOld;
  106. PSID pSidAce;
  107. for (i = 0, pAceOld = (PACCESS_ALLOWED_ACE)((PBYTE)pOldDacl + sizeof(ACL));
  108. i < pOldDacl->AceCount;
  109. i++, pAceOld = (PACCESS_ALLOWED_ACE)((PBYTE)pAceOld + pAceOld->Header.AceSize))
  110. {
  111. if (InheritedAces && ((pAceOld->Header.AceFlags & INHERITED_ACE) != INHERITED_ACE))
  112. continue;
  113. if ((!InheritedAces) && ((pAceOld->Header.AceFlags & INHERITED_ACE) == INHERITED_ACE))
  114. continue;
  115. // Note: All deny aces are ahead of the grant aces.
  116. if (DenyAces && (pAceOld->Header.AceType != ACCESS_DENIED_ACE_TYPE))
  117. break;
  118. if (!DenyAces && (pAceOld->Header.AceType == ACCESS_DENIED_ACE_TYPE))
  119. continue;
  120. pSidAce = (PSID)(&pAceOld->SidStart);
  121. if (!RtlEqualSid(pSidAce, &AfpSidWorld) &&
  122. !RtlEqualSid(pSidAce, &AfpSidCrtrOwner) &&
  123. !RtlEqualSid(pSidAce, &AfpSidCrtrGroup) &&
  124. !RtlEqualSid(pSidAce, pSidOldOwner) &&
  125. !RtlEqualSid(pSidAce, pSidNewOwner) &&
  126. !RtlEqualSid(pSidAce, pSidOldGroup) &&
  127. !RtlEqualSid(pSidAce, pSidNewGroup))
  128. {
  129. RtlCopyMemory(pAceStart, pAceOld, pAceOld->Header.AceSize);
  130. pNewDacl->AclSize += pAceOld->Header.AceSize;
  131. pNewDacl->AceCount ++;
  132. pAceStart = (PACCESS_ALLOWED_ACE)((PBYTE)pAceStart +
  133. pAceStart->Header.AceSize);
  134. }
  135. }
  136. return pAceStart;
  137. }
  138. /*** FSfmSetUamSecurity
  139. *
  140. * Set the permissions on this directory. Also optionally set the owner and
  141. * group ids. For setting the owner and group ids verify if the user has the
  142. * needed access. This access is however not good enough. We check for this
  143. * access but do the actual setting of the permissions in the special server
  144. * context (RESTORE privilege is needed).
  145. */
  146. HRESULT HrSecureSfmDirectory(PCWSTR wszPath)
  147. {
  148. HRESULT hr = S_OK;
  149. NTSTATUS Status;
  150. DWORD SizeNeeded;
  151. PBYTE pBuffer = NULL;
  152. PBYTE pAbsSecDesc = NULL;
  153. PISECURITY_DESCRIPTOR pSecDesc;
  154. SECURITY_INFORMATION SecInfo = DACL_SECURITY_INFORMATION;
  155. PACL pDaclNew = NULL;
  156. PACCESS_ALLOWED_ACE pAce;
  157. LONG SizeNewDacl;
  158. HANDLE DirHandle;
  159. PWSTR pDirPath = NULL;
  160. UNICODE_STRING DirectoryName;
  161. IO_STATUS_BLOCK IoStatusBlock;
  162. DWORD cbDirPath;
  163. OBJECT_ATTRIBUTES ObjectAttributes;
  164. UINT Size;
  165. //
  166. // Convert the DIR Path to UNICODE
  167. //
  168. pDirPath = (PWSTR)LocalAlloc(LPTR, (wcslen(wszPath) +
  169. wcslen(L"\\DOSDEVICES\\")+1) *
  170. sizeof(WCHAR));
  171. if (pDirPath == NULL)
  172. {
  173. hr = E_OUTOFMEMORY;
  174. goto err;
  175. }
  176. wcscpy(pDirPath, L"\\DOSDEVICES\\");
  177. wcscat(pDirPath, wszPath);
  178. RtlInitUnicodeString(&DirectoryName, pDirPath);
  179. InitializeObjectAttributes(&ObjectAttributes,
  180. &DirectoryName,
  181. OBJ_CASE_INSENSITIVE,
  182. NULL,
  183. NULL);
  184. Status = NtOpenFile(&DirHandle,
  185. WRITE_DAC | READ_CONTROL | SYNCHRONIZE,
  186. &ObjectAttributes,
  187. &IoStatusBlock,
  188. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE ,
  189. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
  190. LocalFree(pDirPath);
  191. if (!NT_SUCCESS(Status))
  192. {
  193. goto err;
  194. }
  195. do
  196. {
  197. //
  198. // Read the security descriptor for this directory
  199. //
  200. SizeNeeded = 256;
  201. do
  202. {
  203. if (pBuffer != NULL)
  204. LocalFree(pBuffer);
  205. if ((pBuffer = (PBYTE)LocalAlloc(LPTR,SizeNewDacl = SizeNeeded)) == NULL)
  206. {
  207. Status = STATUS_NO_MEMORY;
  208. break;
  209. }
  210. Status = NtQuerySecurityObject(DirHandle,
  211. OWNER_SECURITY_INFORMATION |
  212. GROUP_SECURITY_INFORMATION |
  213. DACL_SECURITY_INFORMATION,
  214. (PSECURITY_DESCRIPTOR)pBuffer,
  215. SizeNeeded, &SizeNeeded);
  216. } while ((Status != STATUS_SUCCESS) &&
  217. ((Status == STATUS_BUFFER_TOO_SMALL) ||
  218. (Status == STATUS_BUFFER_OVERFLOW) ||
  219. (Status == STATUS_MORE_ENTRIES)));
  220. if (!NT_SUCCESS(Status))
  221. {
  222. hr = E_FAIL;
  223. break;
  224. }
  225. pSecDesc = (PISECURITY_DESCRIPTOR)pBuffer;
  226. // If the security descriptor is in self-relative form, convert to absolute
  227. if (pSecDesc->Control & SE_SELF_RELATIVE)
  228. {
  229. DWORD AbsoluteSizeNeeded;
  230. //
  231. // An absolute SD is not necessarily the same size as a relative
  232. // SD, so an in-place conversion may not be possible.
  233. //
  234. AbsoluteSizeNeeded = SizeNeeded;
  235. Status = RtlSelfRelativeToAbsoluteSD2(pSecDesc, &AbsoluteSizeNeeded);
  236. if (Status == STATUS_BUFFER_TOO_SMALL) {
  237. //
  238. // Allocate a new buffer in which to store the absolute
  239. // security descriptor, copy the contents of the relative
  240. // descriptor in, and try again.
  241. //
  242. pAbsSecDesc = (PBYTE)LocalAlloc(LPTR,AbsoluteSizeNeeded);
  243. if (pAbsSecDesc == NULL) {
  244. Status = STATUS_NO_MEMORY;
  245. break;
  246. }
  247. RtlCopyMemory(pAbsSecDesc,pSecDesc,SizeNeeded);
  248. Status = RtlSelfRelativeToAbsoluteSD2(pAbsSecDesc,
  249. &AbsoluteSizeNeeded );
  250. if (NT_SUCCESS(Status)) {
  251. pSecDesc = (PISECURITY_DESCRIPTOR)pAbsSecDesc;
  252. }
  253. }
  254. }
  255. if (!NT_SUCCESS(Status))
  256. {
  257. break;
  258. }
  259. // Construct the new Dacl. This consists of Aces for World, Owner and Group
  260. // followed by Old Aces for everybody else, but with Aces for World, OldOwner
  261. // and OldGroup stripped out. First determine space for the new Dacl and
  262. // allocated space for the new Dacl. Lets be exteremely conservative. We
  263. // have two aces each for owner/group/world.
  264. SizeNewDacl +=
  265. (RtlLengthSid(pSecDesc->Owner) + sizeof(ACCESS_ALLOWED_ACE) +
  266. RtlLengthSid(pSecDesc->Group) + sizeof(ACCESS_ALLOWED_ACE) +
  267. RtlLengthSid(&AfpSidSystem) + sizeof(ACCESS_ALLOWED_ACE) +
  268. RtlLengthSid(&AfpSidWorld) + sizeof(ACCESS_ALLOWED_ACE)) * 3;
  269. if ((pDaclNew = (PACL)LocalAlloc(LPTR,SizeNewDacl)) == NULL)
  270. {
  271. Status = STATUS_NO_MEMORY;
  272. hr = E_OUTOFMEMORY;
  273. break;
  274. }
  275. Status = RtlCreateAcl(pDaclNew, SizeNewDacl, ACL_REVISION);
  276. if (!NT_SUCCESS(Status))
  277. {
  278. hr = E_FAIL;
  279. break;
  280. }
  281. pAce = (PACCESS_ALLOWED_ACE)((PBYTE)pDaclNew + sizeof(ACL));
  282. // At this time the Acl list is empty, i.e. no access for anybody
  283. // Start off by copying the the Explicit/Non-inherited Deny Aces
  284. // from the original Dacl list weeding out the Aces
  285. // for World, old and new owner, new and old
  286. // group, creator owner and creator group
  287. if (pSecDesc->Dacl != NULL)
  288. {
  289. pAce = afpMoveAces(pSecDesc->Dacl, pAce, pSecDesc->Owner,
  290. pSecDesc->Owner, pSecDesc->Group, pSecDesc->Group,
  291. TRUE, FALSE, pDaclNew);
  292. }
  293. // Now add Aces for System, World, Group & Owner - in that order
  294. pAce = afpAddAceToAcl(pDaclNew,
  295. pAce,
  296. AFP_READ_ACCESS,
  297. &AfpSidSystem,
  298. &AfpSidSystem);
  299. pAce = afpAddAceToAcl(pDaclNew,
  300. pAce,
  301. AFP_READ_ACCESS,
  302. &AfpSidWorld,
  303. NULL);
  304. pAce = afpAddAceToAcl(pDaclNew,
  305. pAce,
  306. AFP_READ_ACCESS ,
  307. pSecDesc->Group,
  308. &AfpSidCrtrGroup);
  309. pAce = afpAddAceToAcl(pDaclNew,
  310. pAce,
  311. AFP_READ_ACCESS | AFP_WRITE_ACCESS,
  312. pSecDesc->Owner,
  313. &AfpSidCrtrOwner);
  314. // Now add in the Explicit/Non-inherited Grant Aces from the
  315. // original Dacl list weeding out
  316. // the Aces for World, old and new owner, new and old group, creator
  317. // owner and creator group
  318. if (pSecDesc->Dacl != NULL)
  319. {
  320. pAce = afpMoveAces(pSecDesc->Dacl, pAce, pSecDesc->Owner,
  321. pSecDesc->Owner, pSecDesc->Group, pSecDesc->Group,
  322. FALSE, FALSE, pDaclNew);
  323. }
  324. // Now add in the Non-explicit/Inherited Deny Aces from
  325. // the original Dacl list
  326. // weeding out the Aces for World, old and new owner, new and old
  327. // group, creator owner and creator group
  328. if (pSecDesc->Dacl != NULL)
  329. {
  330. pAce = afpMoveAces(pSecDesc->Dacl, pAce, pSecDesc->Owner,
  331. pSecDesc->Owner, pSecDesc->Group, pSecDesc->Group,
  332. TRUE, TRUE, pDaclNew);
  333. }
  334. // Now add in the Non-explicit/Inherited Deny Aces from
  335. // the original Dacl list
  336. // weeding out the Aces for World, old and new owner, new and old
  337. // group, creator owner and creator group
  338. if (pSecDesc->Dacl != NULL)
  339. {
  340. pAce = afpMoveAces(pSecDesc->Dacl, pAce, pSecDesc->Owner,
  341. pSecDesc->Owner, pSecDesc->Group, pSecDesc->Group,
  342. FALSE, TRUE, pDaclNew);
  343. }
  344. // Now set the new security descriptor
  345. pSecDesc->Dacl = pDaclNew;
  346. Status = NtSetSecurityObject(DirHandle, SecInfo, pSecDesc);
  347. } while (FALSE);
  348. // Free the allocated buffers before we return
  349. if (pBuffer != NULL)
  350. LocalFree(pBuffer);
  351. if (pDaclNew != NULL)
  352. LocalFree(pDaclNew);
  353. if (pAbsSecDesc != NULL)
  354. LocalFree(pAbsSecDesc);
  355. if (!NT_SUCCESS(Status))
  356. {
  357. hr = E_FAIL;
  358. }
  359. err:
  360. TraceError("HrSfmSetUamSecurity", hr);
  361. return hr;
  362. }