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
15 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. SysVol.c
  5. Abstract:
  6. Creation and Maintenance of the NTFS "System Volume Information"
  7. directory.
  8. Author:
  9. Norbert P. Kusters (NorbertK) 1-Nov-2000
  10. Revision History:
  11. --*/
  12. #include "ntrtlp.h"
  13. PVOID
  14. RtlpSysVolAllocate(
  15. IN ULONG Size
  16. );
  17. VOID
  18. RtlpSysVolFree(
  19. IN PVOID Buffer
  20. );
  21. NTSTATUS
  22. RtlpSysVolCreateSecurityDescriptor(
  23. OUT PSECURITY_DESCRIPTOR* SecurityDescriptor,
  24. OUT PACL* Acl
  25. );
  26. NTSTATUS
  27. RtlpSysVolCheckOwnerAndSecurity(
  28. IN HANDLE Handle,
  29. IN PACL StandardAcl
  30. );
  31. VOID
  32. RtlpSysVolAdminSid(
  33. IN OUT SID* Sid
  34. );
  35. static const SID_IDENTIFIER_AUTHORITY ntAuthority = SECURITY_NT_AUTHORITY;
  36. #if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
  37. #pragma alloc_text(PAGE,RtlCreateSystemVolumeInformationFolder)
  38. #pragma alloc_text(PAGE,RtlpSysVolAllocate)
  39. #pragma alloc_text(PAGE,RtlpSysVolFree)
  40. #pragma alloc_text(PAGE,RtlpSysVolCreateSecurityDescriptor)
  41. #pragma alloc_text(PAGE,RtlpSysVolCheckOwnerAndSecurity)
  42. #pragma alloc_text(PAGE,RtlpSysVolAdminSid)
  43. #endif
  44. PVOID
  45. RtlpSysVolAllocate(
  46. IN ULONG Size
  47. )
  48. {
  49. PVOID p;
  50. #ifdef NTOS_KERNEL_RUNTIME
  51. p = ExAllocatePoolWithTag(PagedPool, Size, 'SloV');
  52. #else
  53. p = RtlAllocateHeap(RtlProcessHeap(), 0, Size);
  54. #endif
  55. return p;
  56. }
  57. VOID
  58. RtlpSysVolFree(
  59. IN PVOID Buffer
  60. )
  61. {
  62. #ifdef NTOS_KERNEL_RUNTIME
  63. ExFreePool(Buffer);
  64. #else
  65. RtlFreeHeap(RtlProcessHeap(), 0, Buffer);
  66. #endif
  67. }
  68. VOID
  69. RtlpSysVolAdminSid(
  70. IN OUT SID* Sid
  71. )
  72. {
  73. Sid->Revision = SID_REVISION;
  74. Sid->SubAuthorityCount = 2;
  75. Sid->IdentifierAuthority = ntAuthority;
  76. Sid->SubAuthority[0] = SECURITY_BUILTIN_DOMAIN_RID;
  77. Sid->SubAuthority[1] = DOMAIN_ALIAS_RID_ADMINS;
  78. }
  79. VOID
  80. RtlpSysVolSystemSid(
  81. IN OUT SID* Sid
  82. )
  83. {
  84. Sid->Revision = SID_REVISION;
  85. Sid->SubAuthorityCount = 1;
  86. Sid->IdentifierAuthority = ntAuthority;
  87. Sid->SubAuthority[0] = SECURITY_LOCAL_SYSTEM_RID;
  88. }
  89. NTSTATUS
  90. RtlpSysVolCreateSecurityDescriptor(
  91. OUT PSECURITY_DESCRIPTOR* SecurityDescriptor,
  92. OUT PACL* Acl
  93. )
  94. {
  95. PSECURITY_DESCRIPTOR sd;
  96. NTSTATUS status;
  97. PSID systemSid;
  98. UCHAR sidBuffer[2*sizeof(SID)];
  99. ULONG aclLength;
  100. PACL acl;
  101. sd = RtlpSysVolAllocate(sizeof(SECURITY_DESCRIPTOR));
  102. if (!sd) {
  103. return STATUS_INSUFFICIENT_RESOURCES;
  104. }
  105. status = RtlCreateSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION);
  106. if (!NT_SUCCESS(status)) {
  107. RtlpSysVolFree(sd);
  108. return status;
  109. }
  110. systemSid = (PSID) sidBuffer;
  111. RtlpSysVolSystemSid(systemSid);
  112. aclLength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) +
  113. RtlLengthSid(systemSid) - sizeof(ULONG);
  114. acl = RtlpSysVolAllocate(aclLength);
  115. if (!acl) {
  116. RtlpSysVolFree(sd);
  117. return STATUS_INSUFFICIENT_RESOURCES;
  118. }
  119. status = RtlCreateAcl(acl, aclLength, ACL_REVISION);
  120. if (!NT_SUCCESS(status)) {
  121. RtlpSysVolFree(acl);
  122. RtlpSysVolFree(sd);
  123. return status;
  124. }
  125. status = RtlAddAccessAllowedAceEx(acl, ACL_REVISION, OBJECT_INHERIT_ACE |
  126. CONTAINER_INHERIT_ACE,
  127. STANDARD_RIGHTS_ALL |
  128. SPECIFIC_RIGHTS_ALL, systemSid);
  129. if (!NT_SUCCESS(status)) {
  130. RtlpSysVolFree(acl);
  131. RtlpSysVolFree(sd);
  132. return status;
  133. }
  134. status = RtlSetDaclSecurityDescriptor(sd, TRUE, acl, FALSE);
  135. if (!NT_SUCCESS(status)) {
  136. RtlpSysVolFree(acl);
  137. RtlpSysVolFree(sd);
  138. return status;
  139. }
  140. *SecurityDescriptor = sd;
  141. *Acl = acl;
  142. return STATUS_SUCCESS;
  143. }
  144. NTSTATUS
  145. RtlpSysVolCheckOwnerAndSecurity(
  146. IN HANDLE Handle,
  147. IN PACL StandardAcl
  148. )
  149. {
  150. NTSTATUS status;
  151. ULONG sdLength, sdLength2;
  152. PSECURITY_DESCRIPTOR sd, sd2;
  153. PSID sid;
  154. BOOLEAN ownerDefaulted, daclPresent, daclDefaulted;
  155. PACL acl;
  156. ULONG i;
  157. PACCESS_ALLOWED_ACE ace;
  158. PSID systemSid;
  159. UCHAR sidBuffer[2*sizeof(SID)];
  160. PSID adminSid;
  161. UCHAR sidBuffer2[2*sizeof(SID)];
  162. status = NtQuerySecurityObject(Handle, OWNER_SECURITY_INFORMATION |
  163. DACL_SECURITY_INFORMATION, NULL, 0,
  164. &sdLength);
  165. if (status != STATUS_BUFFER_TOO_SMALL) {
  166. // The file system does not support security.
  167. return STATUS_SUCCESS;
  168. }
  169. sd = RtlpSysVolAllocate(sdLength);
  170. if (!sd) {
  171. return STATUS_INSUFFICIENT_RESOURCES;
  172. }
  173. status = NtQuerySecurityObject(Handle, OWNER_SECURITY_INFORMATION |
  174. DACL_SECURITY_INFORMATION, sd, sdLength,
  175. &sdLength);
  176. if (!NT_SUCCESS(status)) {
  177. RtlpSysVolFree(sd);
  178. return status;
  179. }
  180. status = RtlGetDaclSecurityDescriptor(sd, &daclPresent, &acl,
  181. &daclDefaulted);
  182. if (!NT_SUCCESS(status)) {
  183. RtlpSysVolFree(sd);
  184. return status;
  185. }
  186. status = RtlGetOwnerSecurityDescriptor(sd, &sid, &ownerDefaulted);
  187. if (!NT_SUCCESS(status)) {
  188. RtlpSysVolFree(sd);
  189. return status;
  190. }
  191. //
  192. // Setup well know SIDs
  193. //
  194. systemSid = (PSID) sidBuffer;
  195. adminSid = (PSID) sidBuffer2;
  196. RtlpSysVolSystemSid(systemSid);
  197. RtlpSysVolAdminSid(adminSid);
  198. if (!sid) {
  199. goto ResetSecurity;
  200. }
  201. if (!RtlEqualSid(sid, adminSid)) {
  202. goto ResetSecurity;
  203. }
  204. if (!daclPresent || (daclPresent && !acl)) {
  205. goto ResetSecurity;
  206. }
  207. for (i = 0; ; i++) {
  208. status = RtlGetAce(acl, i, &ace);
  209. if (!NT_SUCCESS(status)) {
  210. ace = NULL;
  211. }
  212. if (!ace) {
  213. break;
  214. }
  215. if (ace->Header.AceType != ACCESS_ALLOWED_ACE_TYPE) {
  216. continue;
  217. }
  218. sid = (PSID) &ace->SidStart;
  219. if (!RtlEqualSid(sid, systemSid)) {
  220. continue;
  221. }
  222. break;
  223. }
  224. if (!ace) {
  225. goto ResetSecurity;
  226. }
  227. if (!(ace->Header.AceFlags&OBJECT_INHERIT_ACE) ||
  228. !(ace->Header.AceFlags&CONTAINER_INHERIT_ACE)) {
  229. ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
  230. status = NtSetSecurityObject(Handle, DACL_SECURITY_INFORMATION, sd);
  231. } else {
  232. status = STATUS_SUCCESS;
  233. }
  234. RtlpSysVolFree(sd);
  235. return status;
  236. ResetSecurity:
  237. sdLength2 = sdLength;
  238. status = RtlSelfRelativeToAbsoluteSD2(sd, &sdLength2);
  239. if (status == STATUS_BUFFER_TOO_SMALL) {
  240. sd2 = RtlpSysVolAllocate(sdLength2);
  241. if (!sd2) {
  242. RtlpSysVolFree(sd);
  243. return STATUS_INSUFFICIENT_RESOURCES;
  244. }
  245. RtlCopyMemory(sd2, sd, sdLength);
  246. RtlpSysVolFree(sd);
  247. sd = sd2;
  248. sdLength = sdLength2;
  249. status = RtlSelfRelativeToAbsoluteSD2(sd, &sdLength);
  250. if (!NT_SUCCESS(status)) {
  251. RtlpSysVolFree(sd);
  252. return status;
  253. }
  254. }
  255. status = RtlSetOwnerSecurityDescriptor(sd, adminSid, FALSE);
  256. if (!NT_SUCCESS(status)) {
  257. RtlpSysVolFree(sd);
  258. return status;
  259. }
  260. status = RtlSetDaclSecurityDescriptor(sd, TRUE, StandardAcl, FALSE);
  261. if (!NT_SUCCESS(status)) {
  262. RtlpSysVolFree(sd);
  263. return status;
  264. }
  265. sdLength2 = 0;
  266. status = RtlMakeSelfRelativeSD(sd, NULL, &sdLength2);
  267. if (status != STATUS_BUFFER_TOO_SMALL) {
  268. RtlpSysVolFree(sd);
  269. return status;
  270. }
  271. sd2 = RtlpSysVolAllocate(sdLength2);
  272. if (!sd2) {
  273. RtlpSysVolFree(sd);
  274. return STATUS_INSUFFICIENT_RESOURCES;
  275. }
  276. status = RtlMakeSelfRelativeSD(sd, sd2, &sdLength2);
  277. RtlpSysVolFree(sd);
  278. if (!NT_SUCCESS(status)) {
  279. RtlpSysVolFree(sd2);
  280. return status;
  281. }
  282. sd = sd2;
  283. sdLength = sdLength2;
  284. status = NtSetSecurityObject(Handle, OWNER_SECURITY_INFORMATION |
  285. DACL_SECURITY_INFORMATION, sd);
  286. RtlpSysVolFree(sd);
  287. return status;
  288. }
  289. VOID
  290. RtlpSysVolTakeOwnership(
  291. IN PUNICODE_STRING DirectoryName
  292. )
  293. /*++
  294. Routine Description:
  295. This routine is called when the open for the directory failed. This
  296. routine will attempt to set the owner of the file to the caller's
  297. ownership so that another attempt to open the file can be attempted.
  298. Arguments:
  299. DirectoryName - Supplies the directory name.
  300. Return Value:
  301. None.
  302. --*/
  303. {
  304. NTSTATUS status;
  305. HANDLE tokenHandle, fileHandle;
  306. TOKEN_PRIVILEGES tokenPrivileges;
  307. OBJECT_ATTRIBUTES oa;
  308. IO_STATUS_BLOCK ioStatus;
  309. SECURITY_DESCRIPTOR sd;
  310. PSID adminSid;
  311. UCHAR sidBuffer[2*sizeof(SID)];
  312. status = NtOpenProcessToken(NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES |
  313. TOKEN_QUERY, &tokenHandle);
  314. if (!NT_SUCCESS(status)) {
  315. return;
  316. }
  317. tokenPrivileges.PrivilegeCount = 1;
  318. tokenPrivileges.Privileges[0].Luid =
  319. RtlConvertLongToLuid(SE_TAKE_OWNERSHIP_PRIVILEGE);
  320. tokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  321. status = NtAdjustPrivilegesToken(tokenHandle, FALSE, &tokenPrivileges,
  322. sizeof(tokenPrivileges), NULL, NULL);
  323. if (!NT_SUCCESS(status)) {
  324. NtClose(tokenHandle);
  325. return;
  326. }
  327. InitializeObjectAttributes(&oa, DirectoryName, OBJ_CASE_INSENSITIVE, NULL,
  328. NULL);
  329. status = NtOpenFile(&fileHandle, WRITE_OWNER | SYNCHRONIZE, &oa, &ioStatus,
  330. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  331. FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
  332. if (!NT_SUCCESS(status)) {
  333. NtClose(tokenHandle);
  334. return;
  335. }
  336. RtlCreateSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
  337. adminSid = (PSID) sidBuffer;
  338. RtlpSysVolAdminSid(adminSid);
  339. status = RtlSetOwnerSecurityDescriptor(&sd, adminSid, FALSE);
  340. if (!NT_SUCCESS(status)) {
  341. NtClose(fileHandle);
  342. NtClose(tokenHandle);
  343. return;
  344. }
  345. status = NtSetSecurityObject(fileHandle, OWNER_SECURITY_INFORMATION, &sd);
  346. if (!NT_SUCCESS(status)) {
  347. NtClose(fileHandle);
  348. NtClose(tokenHandle);
  349. return;
  350. }
  351. NtClose(fileHandle);
  352. NtClose(tokenHandle);
  353. }
  354. NTSTATUS
  355. RtlCreateSystemVolumeInformationFolder(
  356. IN PUNICODE_STRING VolumeRootPath
  357. )
  358. /*++
  359. Routine Description:
  360. This routine verifies the existence of the "System Volume Information"
  361. folder on the given volume. If the folder is not present, then the
  362. folder is created with one ACE indicating full access for SYSTEM. The ACE
  363. will have the inheritance bits set. The folder will be created with
  364. the HIDDEN and SYSTEM attributes set.
  365. If the folder is already present, the ACE that indicates full control
  366. for SYSTEM will be checked and if necessary modified to have the
  367. inheritance bits set.
  368. Arguments:
  369. VolumeRootPath - Supplies a path to the root of an NTFS volume.
  370. Return Value:
  371. NTSTATUS
  372. --*/
  373. {
  374. UNICODE_STRING sysVolName;
  375. UNICODE_STRING dirName;
  376. BOOLEAN needBackslash;
  377. NTSTATUS status;
  378. PSECURITY_DESCRIPTOR securityDescriptor;
  379. PACL acl;
  380. OBJECT_ATTRIBUTES oa;
  381. HANDLE h;
  382. IO_STATUS_BLOCK ioStatus;
  383. RtlInitUnicodeString(&sysVolName, RTL_SYSTEM_VOLUME_INFORMATION_FOLDER);
  384. dirName.Length = VolumeRootPath->Length + sysVolName.Length;
  385. if (VolumeRootPath->Buffer[VolumeRootPath->Length/sizeof(WCHAR) - 1] !=
  386. '\\') {
  387. dirName.Length += sizeof(WCHAR);
  388. needBackslash = TRUE;
  389. } else {
  390. needBackslash = FALSE;
  391. }
  392. dirName.MaximumLength = dirName.Length + sizeof(WCHAR);
  393. dirName.Buffer = RtlpSysVolAllocate(dirName.MaximumLength);
  394. if (!dirName.Buffer) {
  395. return STATUS_INSUFFICIENT_RESOURCES;
  396. }
  397. RtlCopyMemory(dirName.Buffer, VolumeRootPath->Buffer,
  398. VolumeRootPath->Length);
  399. dirName.Length = VolumeRootPath->Length;
  400. if (needBackslash) {
  401. dirName.Buffer[VolumeRootPath->Length/sizeof(WCHAR)] = '\\';
  402. dirName.Length += sizeof(WCHAR);
  403. }
  404. RtlCopyMemory((PCHAR) dirName.Buffer + dirName.Length,
  405. sysVolName.Buffer, sysVolName.Length);
  406. dirName.Length += sysVolName.Length;
  407. dirName.Buffer[dirName.Length/sizeof(WCHAR)] = 0;
  408. status = RtlpSysVolCreateSecurityDescriptor(&securityDescriptor, &acl);
  409. if (!NT_SUCCESS(status)) {
  410. RtlpSysVolFree(dirName.Buffer);
  411. return status;
  412. }
  413. InitializeObjectAttributes(&oa, &dirName, OBJ_CASE_INSENSITIVE, NULL,
  414. securityDescriptor);
  415. status = NtCreateFile(&h, READ_CONTROL | WRITE_DAC | WRITE_OWNER |
  416. SYNCHRONIZE, &oa, &ioStatus, NULL,
  417. FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM,
  418. FILE_SHARE_READ | FILE_SHARE_WRITE |
  419. FILE_SHARE_DELETE, FILE_OPEN_IF,
  420. FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE,
  421. NULL, 0);
  422. if (!NT_SUCCESS(status)) {
  423. RtlpSysVolTakeOwnership(&dirName);
  424. status = NtCreateFile(&h, READ_CONTROL | WRITE_DAC | WRITE_OWNER |
  425. SYNCHRONIZE, &oa, &ioStatus, NULL,
  426. FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM,
  427. FILE_SHARE_READ | FILE_SHARE_WRITE |
  428. FILE_SHARE_DELETE, FILE_OPEN_IF,
  429. FILE_SYNCHRONOUS_IO_NONALERT |
  430. FILE_DIRECTORY_FILE, NULL, 0);
  431. }
  432. RtlpSysVolFree(dirName.Buffer);
  433. if (!NT_SUCCESS(status)) {
  434. RtlpSysVolFree(acl);
  435. RtlpSysVolFree(securityDescriptor);
  436. return status;
  437. }
  438. RtlpSysVolFree(securityDescriptor);
  439. status = RtlpSysVolCheckOwnerAndSecurity(h, acl);
  440. NtClose(h);
  441. RtlpSysVolFree(acl);
  442. return status;
  443. }