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.

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