[RTL]: Document and flesh out Boot Status Data (BSD) API/Structures

[NDK]: Document latest RTL_BSD_DATA as of RS3 based on ext.dll WinDBG
extension "!blackboxbsd" which outputs the entire structure field by
field :).
[NDK]: Update RTL_BSD_ITEM_TYPE thanks to ole32 symbols
[RTL]: Move system volume APIs to sysvol.c
[RTL]: Fill out BsdItemTable based on actual field offsets/sizes and not
hardcoded magic numbers which we won't ask where they came from.
[RTL]: Make RtlCreateBootStatusDataFile use an appropriate structure for
initializing the buffer instead of "UCHAR Buffer[12] = {0xC,0,0,0,
1,0,0,0, 1, 0x1e, 1, 0};" which appears like magic knowledge.
[RTL]: Rename "WriteMode" to "Read" in RtlGetSetBootStatusData since
it's much less confusing.
[RTL]: Some formatting fixes, SAL updates.
This commit is contained in:
Alex Ionescu 2018-02-04 09:33:32 -08:00
parent adcb9bd175
commit 16e0cca7e1
4 changed files with 888 additions and 709 deletions

View file

@ -414,9 +414,6 @@ C_ASSERT(FIELD_OFFSET(LARGE_INTEGER, LowPart) == 0);
#define RTL_CONSTANT_LARGE_INTEGER(quad_part) { { (quad_part), (quad_part)>>32 } }
#define RTL_MAKE_LARGE_INTEGER(low_part, high_part) { { (low_part), (high_part) } }
#ifdef NTOS_MODE_USER
//
// Boot Status Data Field Types
//
@ -428,9 +425,20 @@ typedef enum _RTL_BSD_ITEM_TYPE
RtlBsdItemAabTimeout,
RtlBsdItemBootGood,
RtlBsdItemBootShutdown,
RtlBsdSleepInProgress,
RtlBsdPowerTransition,
RtlBsdItemBootAttemptCount,
RtlBsdItemBootCheckpoint,
RtlBsdItemBootId,
RtlBsdItemShutdownBootId,
RtlBsdItemReportedAbnormalShutdownBootId,
RtlBsdItemErrorInfo,
RtlBsdItemPowerButtonPressInfo,
RtlBsdItemChecksum,
RtlBsdItemMax
} RTL_BSD_ITEM_TYPE, *PRTL_BSD_ITEM_TYPE;
#ifdef NTOS_MODE_USER
//
// Table and Compare result types
//
@ -1238,6 +1246,92 @@ typedef struct _RTL_HANDLE_TABLE
PRTL_HANDLE_TABLE_ENTRY MaxReservedHandles;
} RTL_HANDLE_TABLE, *PRTL_HANDLE_TABLE;
//
// RTL Boot Status Data Item
//
typedef struct _RTL_BSD_ITEM
{
RTL_BSD_ITEM_TYPE Type;
PVOID DataBuffer;
ULONG DataLength;
} RTL_BSD_ITEM, *PRTL_BSD_ITEM;
//
// Data Sub-Structures for "bootstat.dat" RTL Data File
//
typedef struct _RTL_BSD_DATA_POWER_TRANSITION
{
LARGE_INTEGER PowerButtonTimestamp;
struct
{
UCHAR SystemRunning : 1;
UCHAR ConnectedStandbyInProgress : 1;
UCHAR UserShutdownInProgress : 1;
UCHAR SystemShutdownInProgress : 1;
UCHAR SleepInProgress : 4;
} Flags;
UCHAR ConnectedStandbyScenarioInstanceId;
UCHAR ConnectedStandbyEntryReason;
UCHAR ConnectedStandbyExitReason;
USHORT SystemSleepTransitionCount;
LARGE_INTEGER LastReferenceTime;
ULONG LastReferenceTimeChecksum;
ULONG LastUpdateBootId;
} RTL_BSD_DATA_POWER_TRANSITION, *PRTL_BSD_DATA_POWER_TRANSITION;
typedef struct _RTL_BSD_DATA_ERROR_INFO
{
ULONG BootId;
ULONG RepeatCount;
ULONG OtherErrorCount;
ULONG Code;
ULONG OtherErrorCount2;
} RTL_BSD_DATA_ERROR_INFO, *PRTL_BSD_DATA_ERROR_INFO;
typedef struct _RTL_BSD_POWER_BUTTON_PRESS_INFO
{
LARGE_INTEGER LastPressTime;
ULONG CumulativePressCount;
USHORT LastPressBootId;
UCHAR LastPowerWatchdogStage;
struct
{
UCHAR WatchdogArmed : 1;
UCHAR ShutdownInProgress : 1;
} Flags;
LARGE_INTEGER LastReleaseTime;
ULONG CumulativeReleaseCount;
USHORT LastReleaseBootId;
USHORT ErrorCount;
UCHAR CurrentConnectedStandbyPhase;
ULONG TransitionLatestCheckpointId;
ULONG TransitionLatestCheckpointType;
ULONG TransitionLatestCheckpointSequenceNumber;
} RTL_BSD_POWER_BUTTON_PRESS_INFO, *PRTL_BSD_POWER_BUTTON_PRESS_INFO;
//
// Main Structure for "bootstat.dat" RTL Data File
//
typedef struct _RTL_BSD_DATA
{
ULONG Version; // RtlBsdItemVersionNumber
ULONG ProductType; // RtlBsdItemProductType
BOOLEAN AabEnabled; // RtlBsdItemAabEnabled
UCHAR AabTimeout; // RtlBsdItemAabTimeout
BOOLEAN LastBootSucceeded; // RtlBsdItemBootGood
BOOLEAN LastBootShutdown; // RtlBsdItemBootShutdown
BOOLEAN SleepInProgress; // RtlBsdSleepInProgress
RTL_BSD_DATA_POWER_TRANSITION PowerTransition; // RtlBsdPowerTransition
UCHAR BootAttemptCount; // RtlBsdItemBootAttemptCount
UCHAR LastBootCheckpoint; // RtlBsdItemBootCheckpoint
UCHAR Checksum; // RtlBsdItemChecksum
ULONG LastBootId; // RtlBsdItemBootId
ULONG LastSuccessfulShutdownBootId; // RtlBsdItemShutdownBootId
ULONG LastReportedAbnormalShutdownBootId; // RtlBsdItemReportedAbnormalShutdownBootId
RTL_BSD_DATA_ERROR_INFO ErrorInfo; // RtlBsdItemErrorInfo
RTL_BSD_POWER_BUTTON_PRESS_INFO PowerButtonPressInfo; // RtlBsdItemPowerButtonPressInfo
} RTL_BSD_DATA, *PRTL_BSD_DATA;
#ifdef NTOS_MODE_USER
//
// Exception Record

View file

@ -56,6 +56,7 @@ list(APPEND SOURCE
slist.c
sid.c
splaytree.c
sysvol.c
thread.c
time.c
timezone.c

View file

@ -1,715 +1,118 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
* PURPOSE: Boot Data implementation
* PROJECT: ReactOS Runtime Library
* LICENSE: See COPYING in the top level directory
* FILE: lib/rtl/bootdata.c
* PROGRAMMERS:
* PURPOSE: Boot Status Data Implementation
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
* Eric Kohl
*/
/* INCLUDES *****************************************************************/
#include <rtl.h>
#define NDEBUG
#include <debug.h>
typedef struct _RTL_BSD_ITEM
typedef struct _RTL_BSD_ITEM_TABLE_ENTRY
{
ULONG Offset;
ULONG Size;
} RTL_BSD_ITEM, *PRTL_BSD_ITEM;
UCHAR Offset;
UCHAR Size;
} RTL_BSD_ITEM_TABLE_ENTRY;
/* FUNCTIONS *****************************************************************/
static SID_IDENTIFIER_AUTHORITY LocalSystemAuthority = {SECURITY_NT_AUTHORITY};
static RTL_BSD_ITEM BsdItemTable[6] = {{0, 4}, {4, 4,}, {8, 1}, {9, 1}, {10, 1}, {11, 1}};
static NTSTATUS
RtlpSysVolCreateSecurityDescriptor(OUT PISECURITY_DESCRIPTOR *SecurityDescriptor,
OUT PSID *SystemSid)
PRTL_BSD_DATA DummyBsd;
RTL_BSD_ITEM_TABLE_ENTRY BsdItemTable[RtlBsdItemMax] =
{
PSECURITY_DESCRIPTOR AbsSD = NULL;
PSID LocalSystemSid = NULL;
PACL Dacl = NULL;
ULONG DaclSize;
NTSTATUS Status;
/* create the local SYSTEM SID */
Status = RtlAllocateAndInitializeSid(&LocalSystemAuthority,
1,
SECURITY_LOCAL_SYSTEM_RID,
0,
0,
0,
0,
0,
0,
0,
&LocalSystemSid);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* allocate and initialize the security descriptor */
AbsSD = RtlpAllocateMemory(sizeof(SECURITY_DESCRIPTOR),
'dSeS');
if (AbsSD == NULL)
FIELD_OFFSET(RTL_BSD_DATA, Version),
sizeof(&DummyBsd->Version)
}, // RtlBsdItemVersionNumber
{
Status = STATUS_NO_MEMORY;
goto Cleanup;
}
Status = RtlCreateSecurityDescriptor(AbsSD,
SECURITY_DESCRIPTOR_REVISION);
if (!NT_SUCCESS(Status))
FIELD_OFFSET(RTL_BSD_DATA, ProductType),
sizeof(&DummyBsd->ProductType)
}, // RtlBsdItemProductType
{
goto Cleanup;
}
/* allocate and create the DACL */
DaclSize = sizeof(ACL) + sizeof(ACE) +
RtlLengthSid(LocalSystemSid);
Dacl = RtlpAllocateMemory(DaclSize,
'cAeS');
if (Dacl == NULL)
FIELD_OFFSET(RTL_BSD_DATA, AabEnabled),
sizeof(&DummyBsd->AabEnabled)
}, // RtlBsdItemAabEnabled
{
Status = STATUS_NO_MEMORY;
goto Cleanup;
}
Status = RtlCreateAcl(Dacl,
DaclSize,
ACL_REVISION);
if (!NT_SUCCESS(Status))
FIELD_OFFSET(RTL_BSD_DATA, AabTimeout),
sizeof(&DummyBsd->AabTimeout)
}, // RtlBsdItemAabTimeout
{
goto Cleanup;
}
Status = RtlAddAccessAllowedAceEx(Dacl,
ACL_REVISION,
OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
LocalSystemSid);
if (!NT_SUCCESS(Status))
FIELD_OFFSET(RTL_BSD_DATA, LastBootSucceeded),
sizeof(&DummyBsd->LastBootSucceeded)
}, // RtlBsdItemBootGood
{
goto Cleanup;
}
/* set the DACL in the security descriptor */
Status = RtlSetDaclSecurityDescriptor(AbsSD,
TRUE,
Dacl,
FALSE);
/* all done */
if (NT_SUCCESS(Status))
FIELD_OFFSET(RTL_BSD_DATA, LastBootShutdown),
sizeof(&DummyBsd->LastBootShutdown)
}, // RtlBsdItemBootShutdown
{
*SecurityDescriptor = AbsSD;
*SystemSid = LocalSystemSid;
}
else
FIELD_OFFSET(RTL_BSD_DATA, SleepInProgress),
sizeof(&DummyBsd->SleepInProgress)
}, // RtlBsdSleepInProgress
{
Cleanup:
if (LocalSystemSid != NULL)
{
RtlFreeSid(LocalSystemSid);
}
if (Dacl != NULL)
{
RtlpFreeMemory(Dacl,
'cAeS');
}
if (AbsSD != NULL)
{
RtlpFreeMemory(AbsSD,
'dSeS');
}
}
return Status;
}
static NTSTATUS
RtlpSysVolCheckOwnerAndSecurity(IN HANDLE DirectoryHandle,
IN PISECURITY_DESCRIPTOR SecurityDescriptor)
{
PSECURITY_DESCRIPTOR RelSD = NULL;
PSECURITY_DESCRIPTOR NewRelSD = NULL;
PSECURITY_DESCRIPTOR AbsSD = NULL;
#ifdef _WIN64
BOOLEAN AbsSDAllocated = FALSE;
#endif
PSID AdminSid = NULL;
PSID LocalSystemSid = NULL;
ULONG DescriptorSize;
ULONG AbsSDSize, RelSDSize = 0;
PACL Dacl;
BOOLEAN DaclPresent, DaclDefaulted;
PSID OwnerSid;
BOOLEAN OwnerDefaulted;
ULONG AceIndex;
PACE Ace = NULL;
NTSTATUS Status;
/* find out how much memory we need to allocate for the self-relative
descriptor we're querying */
Status = ZwQuerySecurityObject(DirectoryHandle,
OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
NULL,
0,
&DescriptorSize);
if (Status != STATUS_BUFFER_TOO_SMALL)
FIELD_OFFSET(RTL_BSD_DATA, PowerTransition),
sizeof(&DummyBsd->PowerTransition)
}, // RtlBsdPowerTransition
{
/* looks like the FS doesn't support security... return success */
Status = STATUS_SUCCESS;
goto Cleanup;
}
/* allocate enough memory for the security descriptor */
RelSD = RtlpAllocateMemory(DescriptorSize,
'dSeS');
if (RelSD == NULL)
FIELD_OFFSET(RTL_BSD_DATA, BootAttemptCount),
sizeof(&DummyBsd->BootAttemptCount)
}, // RtlBsdItemBootAttemptCount
{
Status = STATUS_NO_MEMORY;
goto Cleanup;
}
/* query the self-relative security descriptor */
Status = ZwQuerySecurityObject(DirectoryHandle,
OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
RelSD,
DescriptorSize,
&DescriptorSize);
if (!NT_SUCCESS(Status))
FIELD_OFFSET(RTL_BSD_DATA, LastBootCheckpoint),
sizeof(&DummyBsd->LastBootCheckpoint)
}, // RtlBsdItemBootCheckpoint
{
/* FIXME - handle the case where someone else modified the owner and/or
DACL while we allocated memory. But that should be *very*
unlikely.... */
goto Cleanup;
}
/* query the owner and DACL from the descriptor */
Status = RtlGetOwnerSecurityDescriptor(RelSD,
&OwnerSid,
&OwnerDefaulted);
if (!NT_SUCCESS(Status))
FIELD_OFFSET(RTL_BSD_DATA, LastBootId),
sizeof(&DummyBsd->LastBootId)
}, // RtlBsdItemBootId
{
goto Cleanup;
}
Status = RtlGetDaclSecurityDescriptor(RelSD,
&DaclPresent,
&Dacl,
&DaclDefaulted);
if (!NT_SUCCESS(Status))
FIELD_OFFSET(RTL_BSD_DATA, LastSuccessfulShutdownBootId),
sizeof(&DummyBsd->LastSuccessfulShutdownBootId)
}, // RtlBsdItemShutdownBootId
{
goto Cleanup;
}
/* create the Administrators SID */
Status = RtlAllocateAndInitializeSid(&LocalSystemAuthority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0,
0,
0,
0,
0,
0,
&AdminSid);
if (!NT_SUCCESS(Status))
FIELD_OFFSET(RTL_BSD_DATA, LastReportedAbnormalShutdownBootId),
sizeof(&DummyBsd->LastReportedAbnormalShutdownBootId)
}, // RtlBsdItemReportedAbnormalShutdownBootId
{
goto Cleanup;
}
/* create the local SYSTEM SID */
Status = RtlAllocateAndInitializeSid(&LocalSystemAuthority,
1,
SECURITY_LOCAL_SYSTEM_RID,
0,
0,
0,
0,
0,
0,
0,
&LocalSystemSid);
if (!NT_SUCCESS(Status))
FIELD_OFFSET(RTL_BSD_DATA, ErrorInfo),
sizeof(&DummyBsd->ErrorInfo)
}, // RtlBsdItemErrorInfo
{
goto Cleanup;
}
/* check if the Administrators are the owner and at least a not-NULL DACL
is present */
if (OwnerSid != NULL &&
RtlEqualSid(OwnerSid,
AdminSid) &&
DaclPresent && Dacl != NULL)
FIELD_OFFSET(RTL_BSD_DATA, PowerButtonPressInfo),
sizeof(&DummyBsd->PowerButtonPressInfo)
}, // RtlBsdItemPowerButtonPressInfo
{
/* check the DACL for an Allowed ACE for the SYSTEM account */
AceIndex = 0;
do
{
Status = RtlGetAce(Dacl,
AceIndex++,
(PVOID*)&Ace);
if (!NT_SUCCESS(Status))
{
Ace = NULL;
}
else if (Ace != NULL && Ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
{
/* check if the the ACE is a set of allowed permissions for the
local SYSTEM account */
if (RtlEqualSid((PSID)(Ace + 1),
LocalSystemSid))
{
/* check if the ACE is inherited by noncontainer and
container objects, if not attempt to change that */
if (!(Ace->Header.AceFlags & OBJECT_INHERIT_ACE) ||
!(Ace->Header.AceFlags & CONTAINER_INHERIT_ACE))
{
Ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
Status = ZwSetSecurityObject(DirectoryHandle,
DACL_SECURITY_INFORMATION,
RelSD);
}
else
{
/* all done, we have access */
Status = STATUS_SUCCESS;
}
goto Cleanup;
}
}
} while (Ace != NULL);
}
AbsSDSize = DescriptorSize;
/* because we need to change any existing data we need to convert it to
an absolute security descriptor first */
Status = RtlSelfRelativeToAbsoluteSD2(RelSD,
&AbsSDSize);
#ifdef _WIN64
if (Status == STATUS_BUFFER_TOO_SMALL)
{
/* this error code can only be returned on 64 bit builds because
the size of an absolute security descriptor is greater than the
size of a self-relative security descriptor */
ASSERT(AbsSDSize > DescriptorSize);
AbsSD = RtlpAllocateMemory(DescriptorSize,
'dSeS');
if (AbsSD == NULL)
{
Status = STATUS_NO_MEMORY;
goto Cleanup;
}
AbsSDAllocated = TRUE;
/* make a raw copy of the self-relative descriptor */
RtlCopyMemory(AbsSD,
RelSD,
DescriptorSize);
/* finally convert it */
Status = RtlSelfRelativeToAbsoluteSD2(AbsSD,
&AbsSDSize);
}
else
#endif
{
AbsSD = RelSD;
}
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
/* set the owner SID */
Status = RtlSetOwnerSecurityDescriptor(AbsSD,
AdminSid,
FALSE);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
/* set the DACL in the security descriptor */
Status = RtlSetDaclSecurityDescriptor(AbsSD,
TRUE,
SecurityDescriptor->Dacl,
FALSE);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
/* convert it back to a self-relative descriptor, find out how much
memory we need */
Status = RtlAbsoluteToSelfRelativeSD(AbsSD,
NULL,
&RelSDSize);
if (Status != STATUS_BUFFER_TOO_SMALL)
{
goto Cleanup;
}
/* allocate enough memory for the new self-relative descriptor */
NewRelSD = RtlpAllocateMemory(RelSDSize,
'dSeS');
if (NewRelSD == NULL)
{
Status = STATUS_NO_MEMORY;
goto Cleanup;
}
/* convert the security descriptor to self-relative format */
Status = RtlAbsoluteToSelfRelativeSD(AbsSD,
NewRelSD,
&RelSDSize);
if (Status == STATUS_BUFFER_TOO_SMALL)
{
goto Cleanup;
}
/* finally attempt to change the security information */
Status = ZwSetSecurityObject(DirectoryHandle,
OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
NewRelSD);
Cleanup:
if (AdminSid != NULL)
{
RtlFreeSid(AdminSid);
}
if (LocalSystemSid != NULL)
{
RtlFreeSid(LocalSystemSid);
}
if (RelSD != NULL)
{
RtlpFreeMemory(RelSD,
'dSeS');
}
if (NewRelSD != NULL)
{
RtlpFreeMemory(NewRelSD,
'dSeS');
}
#ifdef _WIN64
if (AbsSDAllocated)
{
RtlpFreeMemory(AbsSD,
'dSeS');
}
#endif
return Status;
}
static NTSTATUS
RtlpSysVolTakeOwnership(IN PUNICODE_STRING DirectoryPath,
IN PSECURITY_DESCRIPTOR SecurityDescriptor)
{
TOKEN_PRIVILEGES TokenPrivileges;
OBJECT_ATTRIBUTES ObjectAttributes;
SECURITY_DESCRIPTOR AbsSD;
PSID AdminSid = NULL;
IO_STATUS_BLOCK IoStatusBlock;
BOOLEAN TokenEnabled = FALSE;
HANDLE hToken = NULL;
HANDLE hDirectory = NULL;
NTSTATUS Status;
ULONG ReturnLength;
Status = ZwOpenProcessToken(NtCurrentProcess(),
TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
&hToken);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
/* attempt to enable the SE_TAKE_OWNERSHIP_PRIVILEGE privilege */
TokenPrivileges.PrivilegeCount = 1;
TokenPrivileges.Privileges[0].Luid.LowPart = SE_TAKE_OWNERSHIP_PRIVILEGE;
TokenPrivileges.Privileges[0].Luid.HighPart = 0;
TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
Status = ZwAdjustPrivilegesToken(hToken,
FALSE,
&TokenPrivileges,
sizeof(TokenPrivileges),
&TokenPrivileges,
&ReturnLength);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
TokenEnabled = (TokenPrivileges.PrivilegeCount != 0);
/* open the directory */
InitializeObjectAttributes(&ObjectAttributes,
DirectoryPath,
0,
NULL,
SecurityDescriptor);
Status = ZwOpenFile(&hDirectory,
SYNCHRONIZE | WRITE_OWNER,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
/* create the Administrators SID */
Status = RtlAllocateAndInitializeSid(&LocalSystemAuthority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0,
0,
0,
0,
0,
0,
&AdminSid);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
/* create the security descriptor */
Status = RtlCreateSecurityDescriptor(&AbsSD,
SECURITY_DESCRIPTOR_REVISION);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
Status = RtlSetOwnerSecurityDescriptor(&AbsSD,
AdminSid,
FALSE);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
/* attempt to take ownership */
Status = ZwSetSecurityObject(hDirectory,
OWNER_SECURITY_INFORMATION,
&AbsSD);
Cleanup:
if (TokenEnabled)
{
ZwAdjustPrivilegesToken(hToken,
FALSE,
&TokenPrivileges,
0,
NULL,
NULL);
}
if (AdminSid != NULL)
{
RtlFreeSid(AdminSid);
}
if (hDirectory != NULL)
{
ZwClose(hDirectory);
}
if (hToken != NULL)
{
ZwClose(hToken);
}
return Status;
}
FIELD_OFFSET(RTL_BSD_DATA, Checksum),
sizeof(&DummyBsd->Checksum)
}, // RtlBsdItemChecksum
};
/*
* @implemented
*/
* @implemented
*/
NTSTATUS
NTAPI
RtlCreateSystemVolumeInformationFolder(IN PUNICODE_STRING VolumeRootPath)
RtlCreateBootStatusDataFile (
VOID
)
{
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
HANDLE hDirectory;
UNICODE_STRING DirectoryName, NewPath;
ULONG PathLen;
PISECURITY_DESCRIPTOR SecurityDescriptor = NULL;
PSID SystemSid = NULL;
BOOLEAN AddSep = FALSE;
NTSTATUS Status;
PAGED_CODE_RTL();
RtlInitUnicodeString(&DirectoryName,
L"System Volume Information");
PathLen = VolumeRootPath->Length + DirectoryName.Length;
/* make sure we don't overflow while appending the strings */
if (PathLen > 0xFFFC)
{
return STATUS_INVALID_PARAMETER;
}
if (VolumeRootPath->Buffer[(VolumeRootPath->Length / sizeof(WCHAR)) - 1] != L'\\')
{
AddSep = TRUE;
PathLen += sizeof(WCHAR);
}
/* allocate the new string */
NewPath.MaximumLength = (USHORT)PathLen + sizeof(WCHAR);
NewPath.Buffer = RtlpAllocateStringMemory(NewPath.MaximumLength,
TAG_USTR);
if (NewPath.Buffer == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
/* create the new path string */
NewPath.Length = VolumeRootPath->Length;
RtlCopyMemory(NewPath.Buffer,
VolumeRootPath->Buffer,
NewPath.Length);
if (AddSep)
{
NewPath.Buffer[NewPath.Length / sizeof(WCHAR)] = L'\\';
NewPath.Length += sizeof(WCHAR);
}
RtlCopyMemory(NewPath.Buffer + (NewPath.Length / sizeof(WCHAR)),
DirectoryName.Buffer,
DirectoryName.Length);
NewPath.Length += DirectoryName.Length;
NewPath.Buffer[NewPath.Length / sizeof(WCHAR)] = L'\0';
ASSERT(NewPath.Length == PathLen);
ASSERT(NewPath.Length == NewPath.MaximumLength - sizeof(WCHAR));
/* create the security descriptor for the new directory */
Status = RtlpSysVolCreateSecurityDescriptor(&SecurityDescriptor,
&SystemSid);
if (NT_SUCCESS(Status))
{
/* create or open the directory */
InitializeObjectAttributes(&ObjectAttributes,
&NewPath,
0,
NULL,
SecurityDescriptor);
Status = ZwCreateFile(&hDirectory,
SYNCHRONIZE | WRITE_OWNER | WRITE_DAC | READ_CONTROL,
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_OPEN_IF,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
if (!NT_SUCCESS(Status))
{
Status = RtlpSysVolTakeOwnership(&NewPath,
SecurityDescriptor);
if (NT_SUCCESS(Status))
{
/* successfully took ownership, attempt to open it */
Status = ZwCreateFile(&hDirectory,
SYNCHRONIZE | WRITE_OWNER | WRITE_DAC | READ_CONTROL,
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_OPEN_IF,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
}
}
if (NT_SUCCESS(Status))
{
/* check security now and adjust it if neccessary */
Status = RtlpSysVolCheckOwnerAndSecurity(hDirectory,
SecurityDescriptor);
ZwClose(hDirectory);
}
/* free allocated memory */
ASSERT(SecurityDescriptor != NULL);
ASSERT(SecurityDescriptor->Dacl != NULL);
RtlpFreeMemory(SecurityDescriptor->Dacl,
'cAeS');
RtlpFreeMemory(SecurityDescriptor,
'dSeS');
RtlFreeSid(SystemSid);
}
RtlpFreeStringMemory(NewPath.Buffer,
TAG_USTR);
return Status;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RtlCreateBootStatusDataFile(VOID)
{
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
LARGE_INTEGER AllocationSize;
LARGE_INTEGER ByteOffset;
UNICODE_STRING FileName;
UNICODE_STRING FileName =
RTL_CONSTANT_STRING(L"\\SystemRoot\\bootstat.dat");
OBJECT_ATTRIBUTES ObjectAttributes =
RTL_CONSTANT_OBJECT_ATTRIBUTES(&FileName, OBJ_CASE_INSENSITIVE);
HANDLE FileHandle;
NTSTATUS Status;
/* Initialize the file name */
RtlInitUnicodeString(&FileName,
L"\\SystemRoot\\bootstat.dat");
/* Initialize the object attributes */
InitializeObjectAttributes(&ObjectAttributes,
&FileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
AllocationSize.QuadPart = 0x800;
DBG_UNREFERENCED_LOCAL_VARIABLE(AllocationSize);
RTL_BSD_DATA InitialBsd;
/* Create the boot status data file */
AllocationSize.QuadPart = 0x800;
DBG_UNREFERENCED_LOCAL_VARIABLE(AllocationSize);
Status = ZwCreateFile(&FileHandle,
FILE_GENERIC_READ | FILE_GENERIC_WRITE,
&ObjectAttributes,
@ -723,17 +126,23 @@ RtlCreateBootStatusDataFile(VOID)
0);
if (NT_SUCCESS(Status))
{
// FIXME: Initialize the buffer in a better way.
UCHAR Buffer[12] = {0xC,0,0,0, 1,0,0,0, 1, 0x1e, 1, 0};
/* Setup a sane looking initial BSD */
RtlZeroMemory(&InitialBsd, sizeof(InitialBsd));
InitialBsd.Version = sizeof(InitialBsd);
InitialBsd.ProductType = NtProductWinNt;
InitialBsd.AabEnabled = 1;
InitialBsd.AabTimeout = 30;
InitialBsd.LastBootSucceeded = TRUE;
/* Write it to disk */
ByteOffset.QuadPart = 0;
Status = ZwWriteFile(FileHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
&Buffer,
12, //BufferSize,
&InitialBsd,
sizeof(InitialBsd),
&ByteOffset,
NULL);
}
@ -745,34 +154,40 @@ RtlCreateBootStatusDataFile(VOID)
}
/*
* @implemented
*/
* @implemented
*/
NTSTATUS
NTAPI
RtlGetSetBootStatusData(IN HANDLE FileHandle,
IN BOOLEAN WriteMode,
IN RTL_BSD_ITEM_TYPE DataClass,
IN PVOID Buffer,
IN ULONG BufferSize,
OUT PULONG ReturnLength)
RtlGetSetBootStatusData (
_In_ HANDLE FileHandle,
_In_ BOOLEAN Read,
_In_ RTL_BSD_ITEM_TYPE DataClass,
_In_ PVOID Buffer,
_In_ ULONG BufferSize,
_Out_opt_ PULONG ReturnLength
)
{
IO_STATUS_BLOCK IoStatusBlock;
LARGE_INTEGER ByteOffset;
NTSTATUS Status;
DPRINT("RtlGetSetBootStatusData (%p %u %d %p %lu %p)\n",
FileHandle, WriteMode, DataClass, Buffer, BufferSize, ReturnLength);
FileHandle, Read, DataClass, Buffer, BufferSize, ReturnLength);
if (DataClass >= RtlBsdItemMax)
{
return STATUS_INVALID_PARAMETER;
}
if (BufferSize > BsdItemTable[DataClass].Size)
{
return STATUS_BUFFER_TOO_SMALL;
}
ByteOffset.HighPart = 0;
ByteOffset.LowPart = BsdItemTable[DataClass].Offset;
if (WriteMode)
if (Read)
{
Status = ZwReadFile(FileHandle,
NULL,
@ -800,39 +215,34 @@ RtlGetSetBootStatusData(IN HANDLE FileHandle,
if (NT_SUCCESS(Status))
{
if (ReturnLength)
{
*ReturnLength = BsdItemTable[DataClass].Size;
}
}
return Status;
}
/*
* @implemented
*/
* @implemented
*/
NTSTATUS
NTAPI
RtlLockBootStatusData(OUT PHANDLE FileHandle)
RtlLockBootStatusData (
_Out_ PHANDLE FileHandle
)
{
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
UNICODE_STRING FileName;
UNICODE_STRING FileName =
RTL_CONSTANT_STRING(L"\\SystemRoot\\bootstat.dat");
OBJECT_ATTRIBUTES ObjectAttributes =
RTL_CONSTANT_OBJECT_ATTRIBUTES(&FileName, OBJ_CASE_INSENSITIVE);
HANDLE LocalFileHandle;
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
/* Intialize the file handle */
*FileHandle = NULL;
/* Initialize the file name */
RtlInitUnicodeString(&FileName,
L"\\SystemRoot\\bootstat.dat");
/* Initialize the object attributes */
InitializeObjectAttributes(&ObjectAttributes,
&FileName,
0,
NULL,
NULL);
/* Open the boot status data file */
Status = ZwOpenFile(&LocalFileHandle,
FILE_ALL_ACCESS,
@ -850,18 +260,18 @@ RtlLockBootStatusData(OUT PHANDLE FileHandle)
}
/*
* @implemented
*/
* @implemented
*/
NTSTATUS
NTAPI
RtlUnlockBootStatusData(IN HANDLE FileHandle)
RtlUnlockBootStatusData (
_In_ HANDLE FileHandle
)
{
IO_STATUS_BLOCK IoStatusBlock;
/* Flush the file and close it */
ZwFlushBuffersFile(FileHandle,
&IoStatusBlock);
ZwFlushBuffersFile(FileHandle, &IoStatusBlock);
return ZwClose(FileHandle);
}

674
sdk/lib/rtl/sysvol.c Normal file
View file

@ -0,0 +1,674 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
* PURPOSE: Boot Data implementation
* FILE: lib/rtl/bootdata.c
* PROGRAMMERS:
*/
/* INCLUDES *****************************************************************/
#include <rtl.h>
#define NDEBUG
#include <debug.h>
/* FUNCTIONS *****************************************************************/
static SID_IDENTIFIER_AUTHORITY LocalSystemAuthority = {SECURITY_NT_AUTHORITY};
static NTSTATUS
RtlpSysVolCreateSecurityDescriptor(OUT PISECURITY_DESCRIPTOR *SecurityDescriptor,
OUT PSID *SystemSid)
{
PSECURITY_DESCRIPTOR AbsSD = NULL;
PSID LocalSystemSid = NULL;
PACL Dacl = NULL;
ULONG DaclSize;
NTSTATUS Status;
/* create the local SYSTEM SID */
Status = RtlAllocateAndInitializeSid(&LocalSystemAuthority,
1,
SECURITY_LOCAL_SYSTEM_RID,
0,
0,
0,
0,
0,
0,
0,
&LocalSystemSid);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* allocate and initialize the security descriptor */
AbsSD = RtlpAllocateMemory(sizeof(SECURITY_DESCRIPTOR),
'dSeS');
if (AbsSD == NULL)
{
Status = STATUS_NO_MEMORY;
goto Cleanup;
}
Status = RtlCreateSecurityDescriptor(AbsSD,
SECURITY_DESCRIPTOR_REVISION);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
/* allocate and create the DACL */
DaclSize = sizeof(ACL) + sizeof(ACE) +
RtlLengthSid(LocalSystemSid);
Dacl = RtlpAllocateMemory(DaclSize,
'cAeS');
if (Dacl == NULL)
{
Status = STATUS_NO_MEMORY;
goto Cleanup;
}
Status = RtlCreateAcl(Dacl,
DaclSize,
ACL_REVISION);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
Status = RtlAddAccessAllowedAceEx(Dacl,
ACL_REVISION,
OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
LocalSystemSid);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
/* set the DACL in the security descriptor */
Status = RtlSetDaclSecurityDescriptor(AbsSD,
TRUE,
Dacl,
FALSE);
/* all done */
if (NT_SUCCESS(Status))
{
*SecurityDescriptor = AbsSD;
*SystemSid = LocalSystemSid;
}
else
{
Cleanup:
if (LocalSystemSid != NULL)
{
RtlFreeSid(LocalSystemSid);
}
if (Dacl != NULL)
{
RtlpFreeMemory(Dacl,
'cAeS');
}
if (AbsSD != NULL)
{
RtlpFreeMemory(AbsSD,
'dSeS');
}
}
return Status;
}
static NTSTATUS
RtlpSysVolCheckOwnerAndSecurity(IN HANDLE DirectoryHandle,
IN PISECURITY_DESCRIPTOR SecurityDescriptor)
{
PSECURITY_DESCRIPTOR RelSD = NULL;
PSECURITY_DESCRIPTOR NewRelSD = NULL;
PSECURITY_DESCRIPTOR AbsSD = NULL;
#ifdef _WIN64
BOOLEAN AbsSDAllocated = FALSE;
#endif
PSID AdminSid = NULL;
PSID LocalSystemSid = NULL;
ULONG DescriptorSize;
ULONG AbsSDSize, RelSDSize = 0;
PACL Dacl;
BOOLEAN DaclPresent, DaclDefaulted;
PSID OwnerSid;
BOOLEAN OwnerDefaulted;
ULONG AceIndex;
PACE Ace = NULL;
NTSTATUS Status;
/* find out how much memory we need to allocate for the self-relative
descriptor we're querying */
Status = ZwQuerySecurityObject(DirectoryHandle,
OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
NULL,
0,
&DescriptorSize);
if (Status != STATUS_BUFFER_TOO_SMALL)
{
/* looks like the FS doesn't support security... return success */
Status = STATUS_SUCCESS;
goto Cleanup;
}
/* allocate enough memory for the security descriptor */
RelSD = RtlpAllocateMemory(DescriptorSize,
'dSeS');
if (RelSD == NULL)
{
Status = STATUS_NO_MEMORY;
goto Cleanup;
}
/* query the self-relative security descriptor */
Status = ZwQuerySecurityObject(DirectoryHandle,
OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
RelSD,
DescriptorSize,
&DescriptorSize);
if (!NT_SUCCESS(Status))
{
/* FIXME - handle the case where someone else modified the owner and/or
DACL while we allocated memory. But that should be *very*
unlikely.... */
goto Cleanup;
}
/* query the owner and DACL from the descriptor */
Status = RtlGetOwnerSecurityDescriptor(RelSD,
&OwnerSid,
&OwnerDefaulted);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
Status = RtlGetDaclSecurityDescriptor(RelSD,
&DaclPresent,
&Dacl,
&DaclDefaulted);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
/* create the Administrators SID */
Status = RtlAllocateAndInitializeSid(&LocalSystemAuthority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0,
0,
0,
0,
0,
0,
&AdminSid);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
/* create the local SYSTEM SID */
Status = RtlAllocateAndInitializeSid(&LocalSystemAuthority,
1,
SECURITY_LOCAL_SYSTEM_RID,
0,
0,
0,
0,
0,
0,
0,
&LocalSystemSid);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
/* check if the Administrators are the owner and at least a not-NULL DACL
is present */
if (OwnerSid != NULL &&
RtlEqualSid(OwnerSid,
AdminSid) &&
DaclPresent && Dacl != NULL)
{
/* check the DACL for an Allowed ACE for the SYSTEM account */
AceIndex = 0;
do
{
Status = RtlGetAce(Dacl,
AceIndex++,
(PVOID*)&Ace);
if (!NT_SUCCESS(Status))
{
Ace = NULL;
}
else if (Ace != NULL && Ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
{
/* check if the the ACE is a set of allowed permissions for the
local SYSTEM account */
if (RtlEqualSid((PSID)(Ace + 1),
LocalSystemSid))
{
/* check if the ACE is inherited by noncontainer and
container objects, if not attempt to change that */
if (!(Ace->Header.AceFlags & OBJECT_INHERIT_ACE) ||
!(Ace->Header.AceFlags & CONTAINER_INHERIT_ACE))
{
Ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
Status = ZwSetSecurityObject(DirectoryHandle,
DACL_SECURITY_INFORMATION,
RelSD);
}
else
{
/* all done, we have access */
Status = STATUS_SUCCESS;
}
goto Cleanup;
}
}
} while (Ace != NULL);
}
AbsSDSize = DescriptorSize;
/* because we need to change any existing data we need to convert it to
an absolute security descriptor first */
Status = RtlSelfRelativeToAbsoluteSD2(RelSD,
&AbsSDSize);
#ifdef _WIN64
if (Status == STATUS_BUFFER_TOO_SMALL)
{
/* this error code can only be returned on 64 bit builds because
the size of an absolute security descriptor is greater than the
size of a self-relative security descriptor */
ASSERT(AbsSDSize > DescriptorSize);
AbsSD = RtlpAllocateMemory(DescriptorSize,
'dSeS');
if (AbsSD == NULL)
{
Status = STATUS_NO_MEMORY;
goto Cleanup;
}
AbsSDAllocated = TRUE;
/* make a raw copy of the self-relative descriptor */
RtlCopyMemory(AbsSD,
RelSD,
DescriptorSize);
/* finally convert it */
Status = RtlSelfRelativeToAbsoluteSD2(AbsSD,
&AbsSDSize);
}
else
#endif
{
AbsSD = RelSD;
}
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
/* set the owner SID */
Status = RtlSetOwnerSecurityDescriptor(AbsSD,
AdminSid,
FALSE);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
/* set the DACL in the security descriptor */
Status = RtlSetDaclSecurityDescriptor(AbsSD,
TRUE,
SecurityDescriptor->Dacl,
FALSE);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
/* convert it back to a self-relative descriptor, find out how much
memory we need */
Status = RtlAbsoluteToSelfRelativeSD(AbsSD,
NULL,
&RelSDSize);
if (Status != STATUS_BUFFER_TOO_SMALL)
{
goto Cleanup;
}
/* allocate enough memory for the new self-relative descriptor */
NewRelSD = RtlpAllocateMemory(RelSDSize,
'dSeS');
if (NewRelSD == NULL)
{
Status = STATUS_NO_MEMORY;
goto Cleanup;
}
/* convert the security descriptor to self-relative format */
Status = RtlAbsoluteToSelfRelativeSD(AbsSD,
NewRelSD,
&RelSDSize);
if (Status == STATUS_BUFFER_TOO_SMALL)
{
goto Cleanup;
}
/* finally attempt to change the security information */
Status = ZwSetSecurityObject(DirectoryHandle,
OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
NewRelSD);
Cleanup:
if (AdminSid != NULL)
{
RtlFreeSid(AdminSid);
}
if (LocalSystemSid != NULL)
{
RtlFreeSid(LocalSystemSid);
}
if (RelSD != NULL)
{
RtlpFreeMemory(RelSD,
'dSeS');
}
if (NewRelSD != NULL)
{
RtlpFreeMemory(NewRelSD,
'dSeS');
}
#ifdef _WIN64
if (AbsSDAllocated)
{
RtlpFreeMemory(AbsSD,
'dSeS');
}
#endif
return Status;
}
static NTSTATUS
RtlpSysVolTakeOwnership(IN PUNICODE_STRING DirectoryPath,
IN PSECURITY_DESCRIPTOR SecurityDescriptor)
{
TOKEN_PRIVILEGES TokenPrivileges;
OBJECT_ATTRIBUTES ObjectAttributes;
SECURITY_DESCRIPTOR AbsSD;
PSID AdminSid = NULL;
IO_STATUS_BLOCK IoStatusBlock;
BOOLEAN TokenEnabled = FALSE;
HANDLE hToken = NULL;
HANDLE hDirectory = NULL;
NTSTATUS Status;
ULONG ReturnLength;
Status = ZwOpenProcessToken(NtCurrentProcess(),
TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
&hToken);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
/* attempt to enable the SE_TAKE_OWNERSHIP_PRIVILEGE privilege */
TokenPrivileges.PrivilegeCount = 1;
TokenPrivileges.Privileges[0].Luid.LowPart = SE_TAKE_OWNERSHIP_PRIVILEGE;
TokenPrivileges.Privileges[0].Luid.HighPart = 0;
TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
Status = ZwAdjustPrivilegesToken(hToken,
FALSE,
&TokenPrivileges,
sizeof(TokenPrivileges),
&TokenPrivileges,
&ReturnLength);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
TokenEnabled = (TokenPrivileges.PrivilegeCount != 0);
/* open the directory */
InitializeObjectAttributes(&ObjectAttributes,
DirectoryPath,
0,
NULL,
SecurityDescriptor);
Status = ZwOpenFile(&hDirectory,
SYNCHRONIZE | WRITE_OWNER,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
/* create the Administrators SID */
Status = RtlAllocateAndInitializeSid(&LocalSystemAuthority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0,
0,
0,
0,
0,
0,
&AdminSid);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
/* create the security descriptor */
Status = RtlCreateSecurityDescriptor(&AbsSD,
SECURITY_DESCRIPTOR_REVISION);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
Status = RtlSetOwnerSecurityDescriptor(&AbsSD,
AdminSid,
FALSE);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
/* attempt to take ownership */
Status = ZwSetSecurityObject(hDirectory,
OWNER_SECURITY_INFORMATION,
&AbsSD);
Cleanup:
if (TokenEnabled)
{
ZwAdjustPrivilegesToken(hToken,
FALSE,
&TokenPrivileges,
0,
NULL,
NULL);
}
if (AdminSid != NULL)
{
RtlFreeSid(AdminSid);
}
if (hDirectory != NULL)
{
ZwClose(hDirectory);
}
if (hToken != NULL)
{
ZwClose(hToken);
}
return Status;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RtlCreateSystemVolumeInformationFolder(IN PUNICODE_STRING VolumeRootPath)
{
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
HANDLE hDirectory;
UNICODE_STRING DirectoryName, NewPath;
ULONG PathLen;
PISECURITY_DESCRIPTOR SecurityDescriptor = NULL;
PSID SystemSid = NULL;
BOOLEAN AddSep = FALSE;
NTSTATUS Status;
PAGED_CODE_RTL();
RtlInitUnicodeString(&DirectoryName,
L"System Volume Information");
PathLen = VolumeRootPath->Length + DirectoryName.Length;
/* make sure we don't overflow while appending the strings */
if (PathLen > 0xFFFC)
{
return STATUS_INVALID_PARAMETER;
}
if (VolumeRootPath->Buffer[(VolumeRootPath->Length / sizeof(WCHAR)) - 1] != L'\\')
{
AddSep = TRUE;
PathLen += sizeof(WCHAR);
}
/* allocate the new string */
NewPath.MaximumLength = (USHORT)PathLen + sizeof(WCHAR);
NewPath.Buffer = RtlpAllocateStringMemory(NewPath.MaximumLength,
TAG_USTR);
if (NewPath.Buffer == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
/* create the new path string */
NewPath.Length = VolumeRootPath->Length;
RtlCopyMemory(NewPath.Buffer,
VolumeRootPath->Buffer,
NewPath.Length);
if (AddSep)
{
NewPath.Buffer[NewPath.Length / sizeof(WCHAR)] = L'\\';
NewPath.Length += sizeof(WCHAR);
}
RtlCopyMemory(NewPath.Buffer + (NewPath.Length / sizeof(WCHAR)),
DirectoryName.Buffer,
DirectoryName.Length);
NewPath.Length += DirectoryName.Length;
NewPath.Buffer[NewPath.Length / sizeof(WCHAR)] = L'\0';
ASSERT(NewPath.Length == PathLen);
ASSERT(NewPath.Length == NewPath.MaximumLength - sizeof(WCHAR));
/* create the security descriptor for the new directory */
Status = RtlpSysVolCreateSecurityDescriptor(&SecurityDescriptor,
&SystemSid);
if (NT_SUCCESS(Status))
{
/* create or open the directory */
InitializeObjectAttributes(&ObjectAttributes,
&NewPath,
0,
NULL,
SecurityDescriptor);
Status = ZwCreateFile(&hDirectory,
SYNCHRONIZE | WRITE_OWNER | WRITE_DAC | READ_CONTROL,
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_OPEN_IF,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
if (!NT_SUCCESS(Status))
{
Status = RtlpSysVolTakeOwnership(&NewPath,
SecurityDescriptor);
if (NT_SUCCESS(Status))
{
/* successfully took ownership, attempt to open it */
Status = ZwCreateFile(&hDirectory,
SYNCHRONIZE | WRITE_OWNER | WRITE_DAC | READ_CONTROL,
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_OPEN_IF,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
}
}
if (NT_SUCCESS(Status))
{
/* check security now and adjust it if neccessary */
Status = RtlpSysVolCheckOwnerAndSecurity(hDirectory,
SecurityDescriptor);
ZwClose(hDirectory);
}
/* free allocated memory */
ASSERT(SecurityDescriptor != NULL);
ASSERT(SecurityDescriptor->Dacl != NULL);
RtlpFreeMemory(SecurityDescriptor->Dacl,
'cAeS');
RtlpFreeMemory(SecurityDescriptor,
'dSeS');
RtlFreeSid(SystemSid);
}
RtlpFreeStringMemory(NewPath.Buffer,
TAG_USTR);
return Status;
}
/* EOF */