https://git.reactos.org/?p=reactos.git;a=commitdiff;h=5696e4ba4db719f299c10…
commit 5696e4ba4db719f299c109bde26f676da5c3db97
Author: George Bișoc <george.bisoc(a)reactos.org>
AuthorDate: Sun Apr 10 19:29:03 2022 +0200
Commit: George Bișoc <george.bisoc(a)reactos.org>
CommitDate: Fri May 6 10:09:49 2022 +0200
[KERNEL32][BASESRV] Implement NLS section security
Implement code that deals with the security side of NLS, more specifically, create two
security descriptors for NLS directory and NLS section names and let the server use such
code.
---
dll/win32/kernel32/winnls/string/nls.c | 358 ++++++++++++++++++++++++++++++++-
subsystems/win/basesrv/basesrv.h | 6 +-
subsystems/win/basesrv/nls.c | 11 +-
3 files changed, 360 insertions(+), 15 deletions(-)
diff --git a/dll/win32/kernel32/winnls/string/nls.c
b/dll/win32/kernel32/winnls/string/nls.c
index a1bad1b2271..3a096884992 100644
--- a/dll/win32/kernel32/winnls/string/nls.c
+++ b/dll/win32/kernel32/winnls/string/nls.c
@@ -56,6 +56,9 @@ GetNlsSectionName(UINT CodePage, UINT Base, ULONG Unknown,
BOOL WINAPI
GetCPFileNameFromRegistry(UINT CodePage, LPWSTR FileName, ULONG FileNameSize);
+NTSTATUS
+CreateNlsDirectorySecurity(_Out_ PSECURITY_DESCRIPTOR *NlsSecurityDescriptor);
+
/* PRIVATE FUNCTIONS **********************************************************/
/**
@@ -70,7 +73,9 @@ NlsInit(VOID)
{
UNICODE_STRING DirName;
OBJECT_ATTRIBUTES ObjectAttributes;
+ PSECURITY_DESCRIPTOR NlsDirSd;
HANDLE Handle;
+ NTSTATUS Status;
InitializeListHead(&CodePageListHead);
RtlInitializeCriticalSection(&CodePageListLock);
@@ -82,13 +87,21 @@ NlsInit(VOID)
*/
RtlInitUnicodeString(&DirName, L"\\Nls");
+ /* Create a security descriptor for NLS directory */
+ Status = CreateNlsDirectorySecurity(&NlsDirSd);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to create NLS directory security (Status 0x%08x)\n",
Status);
+ return FALSE;
+ }
+
InitializeObjectAttributes(&ObjectAttributes,
&DirName,
OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
NULL,
- NULL);
+ NlsDirSd);
- if (NT_SUCCESS(NtCreateDirectoryObject(&Handle, DIRECTORY_ALL_ACCESS,
&ObjectAttributes)))
+ if (NT_SUCCESS(NtCreateDirectoryObject(&Handle, DIRECTORY_TRAVERSE |
DIRECTORY_CREATE_OBJECT, &ObjectAttributes)))
{
NtClose(Handle);
}
@@ -112,6 +125,7 @@ NlsInit(VOID)
OemCodePage.CodePage = OemCodePage.CodePageTable.CodePage;
InsertTailList(&CodePageListHead, &OemCodePage.Entry);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, NlsDirSd);
return TRUE;
}
@@ -2237,13 +2251,343 @@ IsDBCSLeadByte(BYTE TestByte)
return IntIsLeadByte(&AnsiCodePage.CodePageTable, TestByte);
}
-/*
- * @unimplemented
+/**
+ * @brief
+ * Creates a security descriptor for the NLS object directory
+ * name.
+ *
+ * @param[out] SecurityDescriptor
+ * A pointer to an allocated and created security descriptor
+ * that is given to the caller.
+ *
+ * @return
+ * STATUS_SUCCESS is returned if the function has successfully
+ * created a security descriptor for a NLS section name. Otherwise
+ * a NTSTATUS failure code is returned.
+ *
+ * @remarks
+ * Everyone (aka World SID) is given read access to the NLS directory
+ * whereas admins are given full power.
*/
-NTSTATUS WINAPI CreateNlsSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,ULONG
Size,ULONG AccessMask)
+NTSTATUS
+CreateNlsDirectorySecurity(_Out_ PSECURITY_DESCRIPTOR *NlsSecurityDescriptor)
{
- STUB;
- return 0;
+ NTSTATUS Status;
+ PACL Dacl;
+ PSID WorldSid = NULL, AdminsSid = NULL;
+ ULONG DaclSize, RelSdSize = 0;
+ PSECURITY_DESCRIPTOR RelativeSd = NULL;
+ SECURITY_DESCRIPTOR AbsoluteSd;
+ static SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY};
+ static SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
+
+ /* Create the World SID */
+ Status = RtlAllocateAndInitializeSid(&WorldAuthority,
+ 1,
+ SECURITY_WORLD_RID,
+ 0, 0, 0, 0, 0, 0, 0,
+ &WorldSid);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CreateNlsDirectorySecurity(): Failed to create world SID (Status
0x%08x)\n", Status);
+ return Status;
+ }
+
+ /* Create the admins SID */
+ Status = RtlAllocateAndInitializeSid(&NtAuthority,
+ 2,
+ SECURITY_BUILTIN_DOMAIN_RID,
+ DOMAIN_ALIAS_RID_ADMINS,
+ 0, 0, 0, 0, 0, 0,
+ &AdminsSid);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CreateNlsDirectorySecurity(): Failed to create admins SID (Status
0x%08x)\n", Status);
+ goto Quit;
+ }
+
+ /* Build up the size of our DACL, including the World and admins SIDs */
+ DaclSize = sizeof(ACL) +
+ sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(WorldSid) +
+ sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(AdminsSid);
+
+ /* Allocate memory for our DACL */
+ Dacl = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, DaclSize);
+ if (Dacl == NULL)
+ {
+ DPRINT1("CreateNlsDirectorySecurity(): Could not allocate memory for DACL,
not enough memory!\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Quit;
+ }
+
+ /* Create the DACL */
+ Status = RtlCreateAcl(Dacl, DaclSize, ACL_REVISION);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CreateNlsDirectorySecurity(): Failed to create the DACL (Status
0x%08x)\n", Status);
+ goto Quit;
+ }
+
+ /* Give everyone basic directory access */
+ Status = RtlAddAccessAllowedAce(Dacl,
+ ACL_REVISION,
+ DIRECTORY_TRAVERSE | DIRECTORY_CREATE_OBJECT,
+ WorldSid);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CreateNlsDirectorySecurity(): Failed to insert allowed access ACE
to DACL for World SID (Status 0x%08x)\n", Status);
+ goto Quit;
+ }
+
+ /* Give admins full power */
+ Status = RtlAddAccessAllowedAce(Dacl,
+ ACL_REVISION,
+ DIRECTORY_ALL_ACCESS,
+ AdminsSid);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CreateNlsDirectorySecurity(): Failed to insert allowed access ACE
to DACL for admins SID (Status 0x%08x)\n", Status);
+ goto Quit;
+ }
+
+ /* Initialize the security descriptor */
+ Status = RtlCreateSecurityDescriptor(&AbsoluteSd,
+ SECURITY_DESCRIPTOR_REVISION);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CreateNlsDirectorySecurity(): Failed to initialize the security
descriptor (Status 0x%08x)\n", Status);
+ goto Quit;
+ }
+
+ /* Set the DACL to descriptor */
+ Status = RtlSetDaclSecurityDescriptor(&AbsoluteSd,
+ TRUE,
+ Dacl,
+ FALSE);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CreateNlsDirectorySecurity(): Failed to insert DACL into the
descriptor (Status 0x%08x)\n", Status);
+ goto Quit;
+ }
+
+ /* Determine how much size is needed to convert the absolute SD into self-relative
one */
+ Status = RtlAbsoluteToSelfRelativeSD(&AbsoluteSd,
+ NULL,
+ &RelSdSize);
+ if (Status != STATUS_BUFFER_TOO_SMALL)
+ {
+ DPRINT1("CreateNlsDirectorySecurity(): Unexpected status code, must be
STATUS_BUFFER_TOO_SMALL (Status 0x%08x)\n", Status);
+ goto Quit;
+ }
+
+ /* Allocate buffer for relative SD */
+ RelativeSd = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, RelSdSize);
+ if (RelativeSd == NULL)
+ {
+ DPRINT1("CreateNlsDirectorySecurity(): Could not allocate memory for
relative SD, not enough memory!\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Quit;
+ }
+
+ /* Convert it now */
+ Status = RtlAbsoluteToSelfRelativeSD(&AbsoluteSd,
+ RelativeSd,
+ &RelSdSize);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CreateNlsDirectorySecurity(): Failed to convert absolute SD to
self-relative format (Status 0x%08x)\n", Status);
+ goto Quit;
+ }
+
+ /* Give the security descriptor to the caller */
+ *NlsSecurityDescriptor = RelativeSd;
+
+Quit:
+ if (WorldSid != NULL)
+ {
+ RtlFreeHeap(RtlGetProcessHeap(), 0, WorldSid);
+ }
+
+ if (AdminsSid != NULL)
+ {
+ RtlFreeHeap(RtlGetProcessHeap(), 0, AdminsSid);
+ }
+
+ if (Dacl != NULL)
+ {
+ RtlFreeHeap(RtlGetProcessHeap(), 0, Dacl);
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ if (RelativeSd != NULL)
+ {
+ RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeSd);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ * @brief
+ * Creates a security descriptor for each NLS section
+ * name.
+ *
+ * @param[in] AccessMask
+ * An access mask bit to supply to the function. This
+ * access mask grants everyone access specific to that
+ * bit mask.
+ *
+ * @param[out] SecurityDescriptor
+ * A pointer to an allocated and created security descriptor
+ * that is given to the caller.
+ *
+ * @return
+ * STATUS_SUCCESS is returned if the function has successfully
+ * created a security descriptor for a NLS section name. Otherwise
+ * a NTSTATUS failure code is returned.
+ *
+ * @remarks
+ * The implementation of CreateNlsSecurityDescriptor on Windows Server
+ * 2003 is slightly different compared to ours. The second parameter
+ * takes the size of a security descriptor, in bytes. This is implied
+ * that on Windows the caller is responsible to submit the exact
+ * size of the descriptor. On ReactOS we're going to do it different,
+ * let the function be responsible for security descriptor creation
+ * and its size. DescriptorSize will act like a dummy parameter for us
+ * in this case. Everyone (aka World SID) is given read access to each
+ * NLS section name.
+ */
+NTSTATUS WINAPI CreateNlsSecurityDescriptor(_Out_ PSECURITY_DESCRIPTOR
*SecurityDescriptor, _In_ SIZE_T DescriptorSize, _In_ ULONG AccessMask)
+{
+ NTSTATUS Status;
+ PACL Dacl;
+ PSID WorldSid = NULL;
+ ULONG DaclSize, RelSdSize = 0;
+ PSECURITY_DESCRIPTOR RelativeSd = NULL;
+ SECURITY_DESCRIPTOR AbsoluteSd;
+ static SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY};
+
+ /* DescriptorSize is just a dummy parameter */
+ UNREFERENCED_PARAMETER(DescriptorSize);
+
+ /* Create the World SID */
+ Status = RtlAllocateAndInitializeSid(&WorldAuthority,
+ 1,
+ SECURITY_WORLD_RID,
+ 0, 0, 0, 0, 0, 0, 0,
+ &WorldSid);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CreateNlsSecurityDescriptor(): Failed to create world SID (Status
0x%08x)\n", Status);
+ return Status;
+ }
+
+ /* Build up the size of our DACL, including the World SID */
+ DaclSize = sizeof(ACL) +
+ sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(WorldSid);
+
+ /* Allocate memory for our DACL */
+ Dacl = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, DaclSize);
+ if (Dacl == NULL)
+ {
+ DPRINT1("CreateNlsSecurityDescriptor(): Could not allocate memory for DACL,
not enough memory!\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Quit;
+ }
+
+ /* Create the DACL */
+ Status = RtlCreateAcl(Dacl, DaclSize, ACL_REVISION);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CreateNlsSecurityDescriptor(): Failed to create the DACL (Status
0x%08x)\n", Status);
+ goto Quit;
+ }
+
+ /* Add a ACE with allow access to the World SID */
+ Status = RtlAddAccessAllowedAce(Dacl,
+ ACL_REVISION,
+ AccessMask,
+ WorldSid);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CreateNlsSecurityDescriptor(): Failed to insert allowed access ACE
to DACL for World SID (Status 0x%08x)\n", Status);
+ goto Quit;
+ }
+
+ /* Initialize the security descriptor */
+ Status = RtlCreateSecurityDescriptor(&AbsoluteSd,
+ SECURITY_DESCRIPTOR_REVISION);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CreateNlsSecurityDescriptor(): Failed to insert allowed access ACE
to DACL for World SID (Status 0x%08x)\n", Status);
+ goto Quit;
+ }
+
+ /* Set the DACL to descriptor */
+ Status = RtlSetDaclSecurityDescriptor(&AbsoluteSd,
+ TRUE,
+ Dacl,
+ FALSE);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CreateNlsSecurityDescriptor(): Failed to insert DACL into the
descriptor (Status 0x%08x)\n", Status);
+ goto Quit;
+ }
+
+ /* Determine how much size is needed to convert the absolute SD into self-relative
one */
+ Status = RtlAbsoluteToSelfRelativeSD(&AbsoluteSd,
+ NULL,
+ &RelSdSize);
+ if (Status != STATUS_BUFFER_TOO_SMALL)
+ {
+ DPRINT1("CreateNlsSecurityDescriptor(): Unexpected status code, must be
STATUS_BUFFER_TOO_SMALL (Status 0x%08x)\n", Status);
+ goto Quit;
+ }
+
+ /* Allocate buffer for relative SD */
+ RelativeSd = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, RelSdSize);
+ if (RelativeSd == NULL)
+ {
+ DPRINT1("CreateNlsSecurityDescriptor(): Could not allocate memory for
relative SD, not enough memory!\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Quit;
+ }
+
+ /* Convert it now */
+ Status = RtlAbsoluteToSelfRelativeSD(&AbsoluteSd,
+ RelativeSd,
+ &RelSdSize);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CreateNlsSecurityDescriptor(): Failed to convert absolute SD to
self-relative format (Status 0x%08x)\n", Status);
+ goto Quit;
+ }
+
+ /* Give the security descriptor to the caller */
+ *SecurityDescriptor = RelativeSd;
+
+Quit:
+ if (WorldSid != NULL)
+ {
+ RtlFreeHeap(RtlGetProcessHeap(), 0, WorldSid);
+ }
+
+ if (Dacl != NULL)
+ {
+ RtlFreeHeap(RtlGetProcessHeap(), 0, Dacl);
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ if (RelativeSd != NULL)
+ {
+ RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeSd);
+ }
+ }
+
+ return Status;
}
/*
diff --git a/subsystems/win/basesrv/basesrv.h b/subsystems/win/basesrv/basesrv.h
index c758ab435c5..a1180f02348 100644
--- a/subsystems/win/basesrv/basesrv.h
+++ b/subsystems/win/basesrv/basesrv.h
@@ -58,9 +58,9 @@ typedef BOOL (WINAPI *PGET_NLS_SECTION_NAME)(UINT CodePage,
ULONG ResultSize);
typedef BOOL (WINAPI *PVALIDATE_LOCALE)(IN ULONG LocaleId);
-typedef NTSTATUS (WINAPI *PCREATE_NLS_SECURTY_DESCRIPTOR)(IN PVOID Buffer,
- IN ULONG BufferSize,
- IN ULONG AceType);
+typedef NTSTATUS (WINAPI *PCREATE_NLS_SECURTY_DESCRIPTOR)(_Out_ PVOID
*SecurityDescriptorBuffer,
+ _In_ ULONG DescriptorSize,
+ _In_ ULONG AccessMask);
/* Globals */
extern HANDLE BaseSrvHeap;
diff --git a/subsystems/win/basesrv/nls.c b/subsystems/win/basesrv/nls.c
index ef918667188..d8bcac32c48 100644
--- a/subsystems/win/basesrv/nls.c
+++ b/subsystems/win/basesrv/nls.c
@@ -161,7 +161,7 @@ CSR_API(BaseSrvNlsCreateSection)
ULONG LocaleId;
UNICODE_STRING NlsSectionName;
PWCHAR NlsFileName;
- UCHAR SecurityDescriptor[52];
+ PSECURITY_DESCRIPTOR NlsSd;
OBJECT_ATTRIBUTES ObjectAttributes;
WCHAR FileNameBuffer[32];
WCHAR NlsSectionNameBuffer[32];
@@ -271,9 +271,9 @@ CSR_API(BaseSrvNlsCreateSection)
}
/* Create an SD for the section object */
- Status = pCreateNlsSecurityDescriptor(&SecurityDescriptor,
- sizeof(SecurityDescriptor),
- 0x80000000);
+ Status = pCreateNlsSecurityDescriptor(&NlsSd,
+ sizeof(SECURITY_DESCRIPTOR),
+ SECTION_MAP_READ);
if (!NT_SUCCESS(Status))
{
DPRINT1("NLS: CreateNlsSecurityDescriptor FAILED!: %lx\n", Status);
@@ -286,7 +286,7 @@ CSR_API(BaseSrvNlsCreateSection)
&NlsSectionName,
OBJ_CASE_INSENSITIVE | OBJ_PERMANENT | OBJ_OPENIF,
NULL,
- &SecurityDescriptor);
+ NlsSd);
Status = NtCreateSection(&SectionHandle,
SECTION_MAP_READ,
&ObjectAttributes,
@@ -295,6 +295,7 @@ CSR_API(BaseSrvNlsCreateSection)
SEC_COMMIT,
FileHandle);
NtClose(FileHandle);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, NlsSd);
if (!NT_SUCCESS(Status))
{
DPRINT1("NLS: Failed to create section! %lx\n", Status);