2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * PURPOSE: Boot Data implementation
5 * FILE: lib/rtl/bootdata.c
9 /* INCLUDES *****************************************************************/
16 typedef struct _RTL_BSD_ITEM
20 } RTL_BSD_ITEM
, *PRTL_BSD_ITEM
;
22 /* FUNCTIONS *****************************************************************/
24 static SID_IDENTIFIER_AUTHORITY LocalSystemAuthority
= {SECURITY_NT_AUTHORITY
};
26 static RTL_BSD_ITEM BsdItemTable
[6] = {{0, 4}, {4, 4,}, {8, 1}, {9, 1}, {10, 1}, {11, 1}};
29 RtlpSysVolCreateSecurityDescriptor(OUT PISECURITY_DESCRIPTOR
*SecurityDescriptor
,
32 PSECURITY_DESCRIPTOR AbsSD
= NULL
;
33 PSID LocalSystemSid
= NULL
;
38 /* create the local SYSTEM SID */
39 Status
= RtlAllocateAndInitializeSid(&LocalSystemAuthority
,
41 SECURITY_LOCAL_SYSTEM_RID
,
50 if (!NT_SUCCESS(Status
))
55 /* allocate and initialize the security descriptor */
56 AbsSD
= RtlpAllocateMemory(sizeof(SECURITY_DESCRIPTOR
),
60 Status
= STATUS_NO_MEMORY
;
64 Status
= RtlCreateSecurityDescriptor(AbsSD
,
65 SECURITY_DESCRIPTOR_REVISION
);
66 if (!NT_SUCCESS(Status
))
71 /* allocate and create the DACL */
72 DaclSize
= sizeof(ACL
) + sizeof(ACE
) +
73 RtlLengthSid(LocalSystemSid
);
74 Dacl
= RtlpAllocateMemory(DaclSize
,
78 Status
= STATUS_NO_MEMORY
;
82 Status
= RtlCreateAcl(Dacl
,
85 if (!NT_SUCCESS(Status
))
90 Status
= RtlAddAccessAllowedAceEx(Dacl
,
92 OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
,
93 STANDARD_RIGHTS_ALL
| SPECIFIC_RIGHTS_ALL
,
95 if (!NT_SUCCESS(Status
))
100 /* set the DACL in the security descriptor */
101 Status
= RtlSetDaclSecurityDescriptor(AbsSD
,
107 if (NT_SUCCESS(Status
))
109 *SecurityDescriptor
= AbsSD
;
110 *SystemSid
= LocalSystemSid
;
115 if (LocalSystemSid
!= NULL
)
117 RtlFreeSid(LocalSystemSid
);
128 RtlpFreeMemory(AbsSD
,
137 RtlpSysVolCheckOwnerAndSecurity(IN HANDLE DirectoryHandle
,
138 IN PISECURITY_DESCRIPTOR SecurityDescriptor
)
140 PSECURITY_DESCRIPTOR RelSD
= NULL
;
141 PSECURITY_DESCRIPTOR NewRelSD
= NULL
;
142 PSECURITY_DESCRIPTOR AbsSD
= NULL
;
144 BOOLEAN AbsSDAllocated
= FALSE
;
146 PSID AdminSid
= NULL
;
147 PSID LocalSystemSid
= NULL
;
148 ULONG DescriptorSize
;
149 ULONG AbsSDSize
, RelSDSize
= 0;
151 BOOLEAN DaclPresent
, DaclDefaulted
;
153 BOOLEAN OwnerDefaulted
;
158 /* find out how much memory we need to allocate for the self-relative
159 descriptor we're querying */
160 Status
= ZwQuerySecurityObject(DirectoryHandle
,
161 OWNER_SECURITY_INFORMATION
| DACL_SECURITY_INFORMATION
,
165 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
167 /* looks like the FS doesn't support security... return success */
168 Status
= STATUS_SUCCESS
;
172 /* allocate enough memory for the security descriptor */
173 RelSD
= RtlpAllocateMemory(DescriptorSize
,
177 Status
= STATUS_NO_MEMORY
;
181 /* query the self-relative security descriptor */
182 Status
= ZwQuerySecurityObject(DirectoryHandle
,
183 OWNER_SECURITY_INFORMATION
| DACL_SECURITY_INFORMATION
,
187 if (!NT_SUCCESS(Status
))
189 /* FIXME - handle the case where someone else modified the owner and/or
190 DACL while we allocated memory. But that should be *very*
195 /* query the owner and DACL from the descriptor */
196 Status
= RtlGetOwnerSecurityDescriptor(RelSD
,
199 if (!NT_SUCCESS(Status
))
204 Status
= RtlGetDaclSecurityDescriptor(RelSD
,
208 if (!NT_SUCCESS(Status
))
213 /* create the Administrators SID */
214 Status
= RtlAllocateAndInitializeSid(&LocalSystemAuthority
,
216 SECURITY_BUILTIN_DOMAIN_RID
,
217 DOMAIN_ALIAS_RID_ADMINS
,
225 if (!NT_SUCCESS(Status
))
230 /* create the local SYSTEM SID */
231 Status
= RtlAllocateAndInitializeSid(&LocalSystemAuthority
,
233 SECURITY_LOCAL_SYSTEM_RID
,
242 if (!NT_SUCCESS(Status
))
247 /* check if the Administrators are the owner and at least a not-NULL DACL
249 if (OwnerSid
!= NULL
&&
250 RtlEqualSid(OwnerSid
,
252 DaclPresent
&& Dacl
!= NULL
)
254 /* check the DACL for an Allowed ACE for the SYSTEM account */
258 Status
= RtlGetAce(Dacl
,
261 if (!NT_SUCCESS(Status
))
265 else if (Ace
!= NULL
&& Ace
->Header
.AceType
== ACCESS_ALLOWED_ACE_TYPE
)
267 /* check if the the ACE is a set of allowed permissions for the
268 local SYSTEM account */
269 if (RtlEqualSid((PSID
)(Ace
+ 1),
272 /* check if the ACE is inherited by noncontainer and
273 container objects, if not attempt to change that */
274 if (!(Ace
->Header
.AceFlags
& OBJECT_INHERIT_ACE
) ||
275 !(Ace
->Header
.AceFlags
& CONTAINER_INHERIT_ACE
))
277 Ace
->Header
.AceFlags
|= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
;
278 Status
= ZwSetSecurityObject(DirectoryHandle
,
279 DACL_SECURITY_INFORMATION
,
284 /* all done, we have access */
285 Status
= STATUS_SUCCESS
;
291 } while (Ace
!= NULL
);
294 AbsSDSize
= DescriptorSize
;
296 /* because we need to change any existing data we need to convert it to
297 an absolute security descriptor first */
298 Status
= RtlSelfRelativeToAbsoluteSD2(RelSD
,
301 if (Status
== STATUS_BUFFER_TOO_SMALL
)
303 /* this error code can only be returned on 64 bit builds because
304 the size of an absolute security descriptor is greater than the
305 size of a self-relative security descriptor */
306 ASSERT(AbsSDSize
> DescriptorSize
);
308 AbsSD
= RtlpAllocateMemory(DescriptorSize
,
312 Status
= STATUS_NO_MEMORY
;
316 AbsSDAllocated
= TRUE
;
318 /* make a raw copy of the self-relative descriptor */
323 /* finally convert it */
324 Status
= RtlSelfRelativeToAbsoluteSD2(AbsSD
,
333 if (!NT_SUCCESS(Status
))
338 /* set the owner SID */
339 Status
= RtlSetOwnerSecurityDescriptor(AbsSD
,
342 if (!NT_SUCCESS(Status
))
347 /* set the DACL in the security descriptor */
348 Status
= RtlSetDaclSecurityDescriptor(AbsSD
,
350 SecurityDescriptor
->Dacl
,
352 if (!NT_SUCCESS(Status
))
357 /* convert it back to a self-relative descriptor, find out how much
359 Status
= RtlAbsoluteToSelfRelativeSD(AbsSD
,
362 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
367 /* allocate enough memory for the new self-relative descriptor */
368 NewRelSD
= RtlpAllocateMemory(RelSDSize
,
370 if (NewRelSD
== NULL
)
372 Status
= STATUS_NO_MEMORY
;
376 /* convert the security descriptor to self-relative format */
377 Status
= RtlAbsoluteToSelfRelativeSD(AbsSD
,
380 if (Status
== STATUS_BUFFER_TOO_SMALL
)
385 /* finally attempt to change the security information */
386 Status
= ZwSetSecurityObject(DirectoryHandle
,
387 OWNER_SECURITY_INFORMATION
| DACL_SECURITY_INFORMATION
,
391 if (AdminSid
!= NULL
)
393 RtlFreeSid(AdminSid
);
396 if (LocalSystemSid
!= NULL
)
398 RtlFreeSid(LocalSystemSid
);
403 RtlpFreeMemory(RelSD
,
407 if (NewRelSD
!= NULL
)
409 RtlpFreeMemory(NewRelSD
,
416 RtlpFreeMemory(AbsSD
,
425 RtlpSysVolTakeOwnership(IN PUNICODE_STRING DirectoryPath
,
426 IN PSECURITY_DESCRIPTOR SecurityDescriptor
)
428 TOKEN_PRIVILEGES TokenPrivileges
;
429 OBJECT_ATTRIBUTES ObjectAttributes
;
430 SECURITY_DESCRIPTOR AbsSD
;
431 PSID AdminSid
= NULL
;
432 IO_STATUS_BLOCK IoStatusBlock
;
433 BOOLEAN TokenEnabled
= FALSE
;
434 HANDLE hToken
= NULL
;
435 HANDLE hDirectory
= NULL
;
439 Status
= ZwOpenProcessToken(NtCurrentProcess(),
440 TOKEN_QUERY
| TOKEN_ADJUST_PRIVILEGES
,
442 if (!NT_SUCCESS(Status
))
447 /* attempt to enable the SE_TAKE_OWNERSHIP_PRIVILEGE privilege */
448 TokenPrivileges
.PrivilegeCount
= 1;
449 TokenPrivileges
.Privileges
[0].Luid
.LowPart
= SE_TAKE_OWNERSHIP_PRIVILEGE
;
450 TokenPrivileges
.Privileges
[0].Luid
.HighPart
= 0;
451 TokenPrivileges
.Privileges
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
452 Status
= ZwAdjustPrivilegesToken(hToken
,
455 sizeof(TokenPrivileges
),
458 if (!NT_SUCCESS(Status
))
462 TokenEnabled
= (TokenPrivileges
.PrivilegeCount
!= 0);
464 /* open the directory */
465 InitializeObjectAttributes(&ObjectAttributes
,
471 Status
= ZwOpenFile(&hDirectory
,
472 SYNCHRONIZE
| WRITE_OWNER
,
475 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
476 FILE_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
477 if (!NT_SUCCESS(Status
))
482 /* create the Administrators SID */
483 Status
= RtlAllocateAndInitializeSid(&LocalSystemAuthority
,
485 SECURITY_BUILTIN_DOMAIN_RID
,
486 DOMAIN_ALIAS_RID_ADMINS
,
494 if (!NT_SUCCESS(Status
))
499 /* create the security descriptor */
500 Status
= RtlCreateSecurityDescriptor(&AbsSD
,
501 SECURITY_DESCRIPTOR_REVISION
);
502 if (!NT_SUCCESS(Status
))
507 Status
= RtlSetOwnerSecurityDescriptor(&AbsSD
,
510 if (!NT_SUCCESS(Status
))
515 /* attempt to take ownership */
516 Status
= ZwSetSecurityObject(hDirectory
,
517 OWNER_SECURITY_INFORMATION
,
523 ZwAdjustPrivilegesToken(hToken
,
531 if (AdminSid
!= NULL
)
533 RtlFreeSid(AdminSid
);
536 if (hDirectory
!= NULL
)
554 RtlCreateSystemVolumeInformationFolder(IN PUNICODE_STRING VolumeRootPath
)
556 OBJECT_ATTRIBUTES ObjectAttributes
;
557 IO_STATUS_BLOCK IoStatusBlock
;
559 UNICODE_STRING DirectoryName
, NewPath
;
561 PISECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
562 PSID SystemSid
= NULL
;
563 BOOLEAN AddSep
= FALSE
;
568 RtlInitUnicodeString(&DirectoryName
,
569 L
"System Volume Information");
571 PathLen
= VolumeRootPath
->Length
+ DirectoryName
.Length
;
573 /* make sure we don't overflow while appending the strings */
574 if (PathLen
> 0xFFFC)
576 return STATUS_INVALID_PARAMETER
;
579 if (VolumeRootPath
->Buffer
[(VolumeRootPath
->Length
/ sizeof(WCHAR
)) - 1] != L
'\\')
582 PathLen
+= sizeof(WCHAR
);
585 /* allocate the new string */
586 NewPath
.MaximumLength
= (USHORT
)PathLen
+ sizeof(WCHAR
);
587 NewPath
.Buffer
= RtlpAllocateStringMemory(NewPath
.MaximumLength
,
589 if (NewPath
.Buffer
== NULL
)
591 return STATUS_INSUFFICIENT_RESOURCES
;
594 /* create the new path string */
595 NewPath
.Length
= VolumeRootPath
->Length
;
596 RtlCopyMemory(NewPath
.Buffer
,
597 VolumeRootPath
->Buffer
,
601 NewPath
.Buffer
[NewPath
.Length
/ sizeof(WCHAR
)] = L
'\\';
602 NewPath
.Length
+= sizeof(WCHAR
);
604 RtlCopyMemory(NewPath
.Buffer
+ (NewPath
.Length
/ sizeof(WCHAR
)),
605 DirectoryName
.Buffer
,
606 DirectoryName
.Length
);
607 NewPath
.Length
+= DirectoryName
.Length
;
608 NewPath
.Buffer
[NewPath
.Length
/ sizeof(WCHAR
)] = L
'\0';
610 ASSERT(NewPath
.Length
== PathLen
);
611 ASSERT(NewPath
.Length
== NewPath
.MaximumLength
- sizeof(WCHAR
));
613 /* create the security descriptor for the new directory */
614 Status
= RtlpSysVolCreateSecurityDescriptor(&SecurityDescriptor
,
616 if (NT_SUCCESS(Status
))
618 /* create or open the directory */
619 InitializeObjectAttributes(&ObjectAttributes
,
625 Status
= ZwCreateFile(&hDirectory
,
626 SYNCHRONIZE
| WRITE_OWNER
| WRITE_DAC
| READ_CONTROL
,
630 FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
,
631 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
633 FILE_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
636 if (!NT_SUCCESS(Status
))
638 Status
= RtlpSysVolTakeOwnership(&NewPath
,
641 if (NT_SUCCESS(Status
))
643 /* successfully took ownership, attempt to open it */
644 Status
= ZwCreateFile(&hDirectory
,
645 SYNCHRONIZE
| WRITE_OWNER
| WRITE_DAC
| READ_CONTROL
,
649 FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
,
650 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
652 FILE_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
658 if (NT_SUCCESS(Status
))
660 /* check security now and adjust it if neccessary */
661 Status
= RtlpSysVolCheckOwnerAndSecurity(hDirectory
,
666 /* free allocated memory */
667 ASSERT(SecurityDescriptor
!= NULL
);
668 ASSERT(SecurityDescriptor
->Dacl
!= NULL
);
670 RtlpFreeMemory(SecurityDescriptor
->Dacl
,
672 RtlpFreeMemory(SecurityDescriptor
,
675 RtlFreeSid(SystemSid
);
678 RtlpFreeStringMemory(NewPath
.Buffer
,
688 RtlCreateBootStatusDataFile(VOID
)
690 OBJECT_ATTRIBUTES ObjectAttributes
;
691 IO_STATUS_BLOCK IoStatusBlock
;
692 LARGE_INTEGER AllocationSize
;
693 LARGE_INTEGER ByteOffset
;
694 UNICODE_STRING FileName
;
698 /* Initialize the file name */
699 RtlInitUnicodeString(&FileName
,
700 L
"\\SystemRoot\\bootstat.dat");
702 /* Initialize the object attributes */
703 InitializeObjectAttributes(&ObjectAttributes
,
705 OBJ_CASE_INSENSITIVE
,
709 AllocationSize
.QuadPart
= 0x800;
710 DBG_UNREFERENCED_LOCAL_VARIABLE(AllocationSize
);
712 /* Create the boot status data file */
713 Status
= ZwCreateFile(&FileHandle
,
714 FILE_GENERIC_READ
| FILE_GENERIC_WRITE
,
717 NULL
, //&AllocationSize,
718 FILE_ATTRIBUTE_SYSTEM
,
721 FILE_SYNCHRONOUS_IO_NONALERT
,
724 if (NT_SUCCESS(Status
))
726 // FIXME: Initialize the buffer in a better way.
727 UCHAR Buffer
[12] = {0xC,0,0,0, 1,0,0,0, 1, 0x1e, 1, 0};
729 ByteOffset
.QuadPart
= 0;
730 Status
= ZwWriteFile(FileHandle
,
752 RtlGetSetBootStatusData(IN HANDLE FileHandle
,
753 IN BOOLEAN WriteMode
,
754 IN RTL_BSD_ITEM_TYPE DataClass
,
757 OUT PULONG ReturnLength
)
759 IO_STATUS_BLOCK IoStatusBlock
;
760 LARGE_INTEGER ByteOffset
;
763 DPRINT("RtlGetSetBootStatusData (%p %u %d %p %lu %p)\n",
764 FileHandle
, WriteMode
, DataClass
, Buffer
, BufferSize
, ReturnLength
);
766 if (DataClass
>= RtlBsdItemMax
)
767 return STATUS_INVALID_PARAMETER
;
769 if (BufferSize
> BsdItemTable
[DataClass
].Size
)
770 return STATUS_BUFFER_TOO_SMALL
;
772 ByteOffset
.HighPart
= 0;
773 ByteOffset
.LowPart
= BsdItemTable
[DataClass
].Offset
;
777 Status
= ZwReadFile(FileHandle
,
789 Status
= ZwWriteFile(FileHandle
,
800 if (NT_SUCCESS(Status
))
803 *ReturnLength
= BsdItemTable
[DataClass
].Size
;
814 RtlLockBootStatusData(OUT PHANDLE FileHandle
)
816 OBJECT_ATTRIBUTES ObjectAttributes
;
817 IO_STATUS_BLOCK IoStatusBlock
;
818 UNICODE_STRING FileName
;
819 HANDLE LocalFileHandle
;
822 /* Intialize the file handle */
825 /* Initialize the file name */
826 RtlInitUnicodeString(&FileName
,
827 L
"\\SystemRoot\\bootstat.dat");
829 /* Initialize the object attributes */
830 InitializeObjectAttributes(&ObjectAttributes
,
836 /* Open the boot status data file */
837 Status
= ZwOpenFile(&LocalFileHandle
,
842 FILE_SYNCHRONOUS_IO_NONALERT
);
843 if (NT_SUCCESS(Status
))
845 /* Return the file handle */
846 *FileHandle
= LocalFileHandle
;
857 RtlUnlockBootStatusData(IN HANDLE FileHandle
)
859 IO_STATUS_BLOCK IoStatusBlock
;
861 /* Flush the file and close it */
862 ZwFlushBuffersFile(FileHandle
,
865 return ZwClose(FileHandle
);