diff --git a/dll/win32/kernel32/winnls/string/nls.c b/dll/win32/kernel32/winnls/string/nls.c index a1bad1b2271de..3a096884992dc 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 c758ab435c50d..a1180f0234824 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 ef91866718834..d8bcac32c483e 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);