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.

417 lines
11 KiB

  1. #include <nt.h>
  2. #include <ntrtl.h>
  3. #include <nturtl.h>
  4. #include <ntdef.h>
  5. #include <ntstatus.h>
  6. #include <windows.h>
  7. #include <winspool.h>
  8. #include <stdlib.h>
  9. #include <ntsam.h>
  10. #include <ntlsa.h>
  11. #include <ntseapi.h>
  12. #include "sfmutil.h"
  13. extern TCHAR ReturnTextBuffer[512];
  14. #define AFP_MIN_ACCESS (FILE_READ_ATTRIBUTES | \
  15. READ_CONTROL)
  16. #define AFP_READ_ACCESS (READ_CONTROL | \
  17. FILE_READ_ATTRIBUTES | \
  18. FILE_TRAVERSE | \
  19. FILE_LIST_DIRECTORY | \
  20. FILE_READ_EA)
  21. #define AFP_WRITE_ACCESS (FILE_ADD_FILE | \
  22. FILE_ADD_SUBDIRECTORY| \
  23. FILE_WRITE_ATTRIBUTES| \
  24. FILE_WRITE_EA | \
  25. DELETE)
  26. #define AFP_OWNER_ACCESS (WRITE_DAC | \
  27. WRITE_OWNER)
  28. SID AfpSidWorld = { 1, 1, SECURITY_WORLD_SID_AUTHORITY, SECURITY_WORLD_RID };
  29. SID AfpSidNull = { 1, 1, SECURITY_NULL_SID_AUTHORITY, SECURITY_NULL_RID };
  30. SID AfpSidSystem = { 1, 1, SECURITY_NT_AUTHORITY, SECURITY_LOCAL_SYSTEM_RID };
  31. SID AfpSidCrtrOwner = { 1, 1, SECURITY_CREATOR_SID_AUTHORITY, SECURITY_CREATOR_OWNER_RID };
  32. SID AfpSidCrtrGroup = { 1, 1, SECURITY_CREATOR_SID_AUTHORITY, SECURITY_CREATOR_GROUP_RID };
  33. /*** afpAddAceToAcl
  34. *
  35. * Build an Ace corres. to the Sid(s) and mask and add these to the Acl. It is
  36. * assumed that the Acl has space for the Aces. If the Mask is 0 (i.e. no access)
  37. * the Ace added is a DENY Ace, else a ALLOWED ACE is added.
  38. */
  39. PACCESS_ALLOWED_ACE
  40. afpAddAceToAcl(
  41. IN PACL pAcl,
  42. IN PACCESS_ALLOWED_ACE pAce,
  43. IN ACCESS_MASK Mask,
  44. IN PSID pSid,
  45. IN PSID pSidInherit OPTIONAL
  46. )
  47. {
  48. // Add a vanilla ace
  49. pAcl->AceCount ++;
  50. pAce->Mask = Mask | SYNCHRONIZE | AFP_MIN_ACCESS;
  51. pAce->Header.AceFlags = 0;
  52. pAce->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
  53. pAce->Header.AceSize = (USHORT)(sizeof(ACE_HEADER) + sizeof(ACCESS_MASK) +
  54. RtlLengthSid(pSid));
  55. RtlCopySid(RtlLengthSid(pSid), (PSID)(&pAce->SidStart), pSid);
  56. // Now add an inherit ace
  57. if (1)
  58. {
  59. pAce = (PACCESS_ALLOWED_ACE)((PBYTE)pAce + pAce->Header.AceSize);
  60. pAcl->AceCount ++;
  61. pAce->Mask = Mask | SYNCHRONIZE | AFP_MIN_ACCESS;
  62. pAce->Header.AceFlags = CONTAINER_INHERIT_ACE |
  63. OBJECT_INHERIT_ACE |
  64. INHERIT_ONLY_ACE;
  65. pAce->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
  66. pAce->Header.AceSize = (USHORT)(sizeof(ACE_HEADER) + sizeof(ACCESS_MASK) +
  67. RtlLengthSid(pSid));
  68. RtlCopySid(RtlLengthSid(pSid), (PSID)(&pAce->SidStart), pSid);
  69. // Now add an inherit ace for the CreatorOwner/CreatorGroup
  70. if (ARGUMENT_PRESENT(pSidInherit))
  71. {
  72. pAce = (PACCESS_ALLOWED_ACE)((PBYTE)pAce + pAce->Header.AceSize);
  73. pAcl->AceCount ++;
  74. pAce->Mask = Mask | SYNCHRONIZE | AFP_MIN_ACCESS;
  75. pAce->Header.AceFlags = CONTAINER_INHERIT_ACE |
  76. OBJECT_INHERIT_ACE |
  77. INHERIT_ONLY_ACE;
  78. pAce->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
  79. pAce->Header.AceSize = (USHORT)(sizeof(ACE_HEADER) + sizeof(ACCESS_MASK) +
  80. RtlLengthSid(pSidInherit));
  81. RtlCopySid(RtlLengthSid(pSidInherit), (PSID)(&pAce->SidStart), pSidInherit);
  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 OUT PACL pNewDacl
  101. )
  102. {
  103. USHORT i;
  104. PACCESS_ALLOWED_ACE pAceOld;
  105. PSID pSidAce;
  106. for (i = 0, pAceOld = (PACCESS_ALLOWED_ACE)((PBYTE)pOldDacl + sizeof(ACL));
  107. i < pOldDacl->AceCount;
  108. i++, pAceOld = (PACCESS_ALLOWED_ACE)((PBYTE)pAceOld + pAceOld->Header.AceSize))
  109. {
  110. // Note: All deny aces are ahead of the grant aces.
  111. if (DenyAces && (pAceOld->Header.AceType != ACCESS_DENIED_ACE_TYPE))
  112. break;
  113. if (!DenyAces && (pAceOld->Header.AceType == ACCESS_DENIED_ACE_TYPE))
  114. continue;
  115. pSidAce = (PSID)(&pAceOld->SidStart);
  116. if (!(RtlEqualSid(pSidAce, &AfpSidWorld) ||
  117. RtlEqualSid(pSidAce, pSidOldOwner) ||
  118. RtlEqualSid(pSidAce, pSidNewOwner) ||
  119. RtlEqualSid(pSidAce, &AfpSidCrtrOwner) ||
  120. RtlEqualSid(pSidAce, pSidOldGroup) ||
  121. RtlEqualSid(pSidAce, pSidNewGroup) ||
  122. RtlEqualSid(pSidAce, &AfpSidCrtrGroup)))
  123. {
  124. RtlCopyMemory(pAceStart, pAceOld, pAceOld->Header.AceSize);
  125. pAceStart = (PACCESS_ALLOWED_ACE)((PBYTE)pAceStart +
  126. pAceStart->Header.AceSize);
  127. pNewDacl->AceCount ++;
  128. }
  129. }
  130. return (pAceStart);
  131. }
  132. /*** AfpSetAfpPermissions
  133. *
  134. * Set the permissions on this directory. Also optionally set the owner and
  135. * group ids. For setting the owner and group ids verify if the user has the
  136. * needed access. This access is however not good enough. We check for this
  137. * access but do the actual setting of the permissions in the special server
  138. * context (RESTORE privilege is needed).
  139. */
  140. BOOL
  141. SfmSetUamSecurity(
  142. DWORD cArgs,
  143. LPTSTR Args[],
  144. LPTSTR *TextOut
  145. )
  146. {
  147. NTSTATUS Status;
  148. DWORD SizeNeeded;
  149. PBYTE pBuffer = NULL;
  150. PISECURITY_DESCRIPTOR pSecDesc;
  151. SECURITY_INFORMATION SecInfo = DACL_SECURITY_INFORMATION;
  152. PACL pDaclNew = NULL;
  153. PACCESS_ALLOWED_ACE pAce;
  154. LONG SizeNewDacl;
  155. HANDLE DirHandle;
  156. LPWSTR lpwsDirPath = NULL;
  157. LPTSTR pDirPath = NULL;
  158. UNICODE_STRING DirectoryName;
  159. IO_STATUS_BLOCK IoStatusBlock;
  160. DWORD cbDirPath;
  161. OBJECT_ATTRIBUTES ObjectAttributes;
  162. UINT Size;
  163. //
  164. // Convert the DIR Path to UNICODE
  165. //
  166. *TextOut = ReturnTextBuffer;
  167. lstrcpy(ReturnTextBuffer, TEXT("FAILED"));
  168. if(cArgs != 1) {
  169. return FALSE;
  170. }
  171. cbDirPath = (strlen((LPSTR)Args[0]) + 1) * sizeof(WCHAR);
  172. if((lpwsDirPath = (LPWSTR)LocalAlloc(LPTR,cbDirPath)) == NULL)
  173. return(FALSE);
  174. if(!MultiByteToWideChar(CP_ACP,
  175. MB_PRECOMPOSED,
  176. (LPSTR)Args[0],
  177. -1,
  178. lpwsDirPath,
  179. cbDirPath
  180. ))
  181. {
  182. LocalFree(lpwsDirPath);
  183. return(FALSE);
  184. }
  185. #ifdef DEBUG
  186. DbgPrint("UAM: Directory = %ws\n",lpwsDirPath);
  187. #endif
  188. pDirPath = (LPTSTR)LocalAlloc(LPTR,
  189. (wcslen(lpwsDirPath) + wcslen(TEXT("\\DOSDEVICES\\"))+1)
  190. * sizeof(WCHAR));
  191. if(pDirPath == NULL) {
  192. #ifdef DEBUG
  193. DbgPrint("UAMSETSECURITY: malloc for dir path failed\n");
  194. #endif
  195. LocalFree(lpwsDirPath);
  196. return(FALSE);
  197. }
  198. wcscpy(pDirPath, TEXT("\\DOSDEVICES\\"));
  199. wcscat(pDirPath, lpwsDirPath);
  200. LocalFree(lpwsDirPath);
  201. RtlInitUnicodeString(&DirectoryName, pDirPath);
  202. InitializeObjectAttributes(&ObjectAttributes,
  203. &DirectoryName,
  204. OBJ_CASE_INSENSITIVE,
  205. NULL,
  206. NULL);
  207. Status = NtOpenFile(&DirHandle,
  208. WRITE_DAC | READ_CONTROL | SYNCHRONIZE,
  209. &ObjectAttributes,
  210. &IoStatusBlock,
  211. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE ,
  212. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
  213. LocalFree(pDirPath);
  214. if(!NT_SUCCESS(Status)) {
  215. #ifdef DEBUG
  216. DbgPrint("UAMSETSECURITY: NtOpen File Failed\n");
  217. #endif
  218. return(FALSE);
  219. }
  220. do
  221. {
  222. //
  223. // Read the security descriptor for this directory
  224. //
  225. SizeNeeded = 256;
  226. do
  227. {
  228. if (pBuffer != NULL)
  229. LocalFree(pBuffer);
  230. if ((pBuffer = (PBYTE)LocalAlloc(LPTR,SizeNewDacl = SizeNeeded)) == NULL)
  231. {
  232. Status = STATUS_NO_MEMORY;
  233. break;
  234. }
  235. Status = NtQuerySecurityObject(DirHandle,
  236. OWNER_SECURITY_INFORMATION |
  237. GROUP_SECURITY_INFORMATION |
  238. DACL_SECURITY_INFORMATION,
  239. (PSECURITY_DESCRIPTOR)pBuffer,
  240. SizeNeeded, &SizeNeeded);
  241. } while ((Status != STATUS_SUCCESS) &&
  242. ((Status == STATUS_BUFFER_TOO_SMALL) ||
  243. (Status == STATUS_BUFFER_OVERFLOW) ||
  244. (Status == STATUS_MORE_ENTRIES)));
  245. if (!NT_SUCCESS(Status)) {
  246. break;
  247. }
  248. pSecDesc = (PSECURITY_DESCRIPTOR)pBuffer;
  249. // If the security descriptor is in self-relative form, convert to absolute
  250. if (pSecDesc->Control & SE_SELF_RELATIVE)
  251. {
  252. pSecDesc->Control &= ~SE_SELF_RELATIVE;
  253. if (pSecDesc->Owner != NULL)
  254. pSecDesc->Owner = (PSID)RtlOffsetToPointer(pSecDesc, pSecDesc->Owner);
  255. if (pSecDesc->Group != NULL)
  256. pSecDesc->Group = (PSID)RtlOffsetToPointer(pSecDesc, pSecDesc->Group);
  257. if (pSecDesc->Dacl != NULL)
  258. pSecDesc->Dacl = (PACL)RtlOffsetToPointer(pSecDesc, pSecDesc->Dacl);
  259. }
  260. // Construct the new Dacl. This consists of Aces for World, Owner and Group
  261. // followed by Old Aces for everybody else, but with Aces for World, OldOwner
  262. // and OldGroup stripped out. First determine space for the new Dacl and
  263. // allocated space for the new Dacl. Lets be exteremely conservative. We
  264. // have two aces each for owner/group/world.
  265. SizeNewDacl +=
  266. (RtlLengthSid(pSecDesc->Owner) + sizeof(ACCESS_ALLOWED_ACE) +
  267. RtlLengthSid(pSecDesc->Group) + sizeof(ACCESS_ALLOWED_ACE) +
  268. RtlLengthSid(&AfpSidSystem) + sizeof(ACCESS_ALLOWED_ACE) +
  269. RtlLengthSid(&AfpSidWorld) + sizeof(ACCESS_ALLOWED_ACE)) * 3;
  270. if ((pDaclNew = (PACL)LocalAlloc(LPTR,SizeNewDacl)) == NULL)
  271. {
  272. Status = STATUS_NO_MEMORY;
  273. break;
  274. }
  275. RtlCreateAcl(pDaclNew, SizeNewDacl, ACL_REVISION);
  276. pAce = (PACCESS_ALLOWED_ACE)((PBYTE)pDaclNew + sizeof(ACL));
  277. // At this time the Acl list is empty, i.e. no access for anybody
  278. // Start off by copying the Deny Aces from the original Dacl list
  279. // weeding out the Aces for World, old and new owner, new and old
  280. // group, creator owner and creator group
  281. if (pSecDesc->Dacl != NULL)
  282. {
  283. pAce = afpMoveAces(pSecDesc->Dacl, pAce, pSecDesc->Owner,
  284. pSecDesc->Owner, pSecDesc->Group, pSecDesc->Group,
  285. TRUE, pDaclNew);
  286. }
  287. // Now add Aces for System, World, Group & Owner - in that order
  288. pAce = afpAddAceToAcl(pDaclNew,
  289. pAce,
  290. AFP_READ_ACCESS,
  291. &AfpSidSystem,
  292. &AfpSidSystem);
  293. pAce = afpAddAceToAcl(pDaclNew,
  294. pAce,
  295. AFP_READ_ACCESS,
  296. &AfpSidWorld,
  297. NULL);
  298. pAce = afpAddAceToAcl(pDaclNew,
  299. pAce,
  300. AFP_READ_ACCESS ,
  301. pSecDesc->Group,
  302. &AfpSidCrtrGroup);
  303. pAce = afpAddAceToAcl(pDaclNew,
  304. pAce,
  305. AFP_READ_ACCESS | AFP_WRITE_ACCESS,
  306. pSecDesc->Owner,
  307. &AfpSidCrtrOwner);
  308. // Now add in the Grant Aces from the original Dacl list weeding out
  309. // the Aces for World, old and new owner, new and old group, creator
  310. // owner and creator group
  311. if (pSecDesc->Dacl != NULL)
  312. {
  313. pAce = afpMoveAces(pSecDesc->Dacl, pAce, pSecDesc->Owner,
  314. pSecDesc->Owner, pSecDesc->Group, pSecDesc->Group,
  315. FALSE, pDaclNew);
  316. }
  317. // Now set the new security descriptor
  318. pSecDesc->Dacl = pDaclNew;
  319. Status = NtSetSecurityObject(DirHandle, SecInfo, pSecDesc);
  320. } while (FALSE);
  321. // Free the allocated buffers before we return
  322. if (pBuffer != NULL)
  323. LocalFree(pBuffer);
  324. if (pDaclNew != NULL)
  325. LocalFree(pDaclNew);
  326. if(NT_SUCCESS(Status)) {
  327. lstrcpy(ReturnTextBuffer, TEXT("SUCCESS"));
  328. return(TRUE);
  329. }
  330. return FALSE;
  331. }
  332.