/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS Base API Server DLL * FILE: subsystems/win/basesrv/nls.c * PURPOSE: National Language Support (NLS) * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) */ /* INCLUDES *******************************************************************/ #include "basesrv.h" #include #define NDEBUG #include /* GLOBALS ********************************************************************/ RTL_CRITICAL_SECTION NlsCacheCriticalSection; PNLS_USER_INFO pNlsRegUserInfo; BOOLEAN BaseSrvKernel32DelayLoadComplete; HANDLE BaseSrvKernel32DllHandle; UNICODE_STRING BaseSrvKernel32DllPath; POPEN_DATA_FILE pOpenDataFile; PVOID /*PGET_DEFAULT_SORTKEY_SIZE */ pGetDefaultSortkeySize; PVOID /*PGET_LINGUIST_LANG_SIZE*/ pGetLinguistLangSize; PVOID /*PNLS_CONVERT_INTEGER_TO_STRING*/ pNlsConvertIntegerToString; PVOID /*PVALIDATE_LCTYPE*/ pValidateLCType; PVALIDATE_LOCALE pValidateLocale; PGET_NLS_SECTION_NAME pGetNlsSectionName; PVOID /*PGET_USER_DEFAULT_LANGID*/ pGetUserDefaultLangID; PGET_CP_FILE_NAME_FROM_REGISTRY pGetCPFileNameFromRegistry; NTSTATUS (WINAPI *pCreateNlsSecurityDescriptor)( _Out_ PSECURITY_DESCRIPTOR SecurityDescriptor, _In_ SIZE_T DescriptorSize, _In_ ULONG AccessMask); BASESRV_KERNEL_IMPORTS BaseSrvKernel32Imports[10] = { { "OpenDataFile", (PVOID*) &pOpenDataFile }, { "GetDefaultSortkeySize", (PVOID*) &pGetDefaultSortkeySize }, { "GetLinguistLangSize", (PVOID*) &pGetLinguistLangSize }, { "NlsConvertIntegerToString", (PVOID*) &pNlsConvertIntegerToString }, { "ValidateLCType", (PVOID*) &pValidateLCType }, { "ValidateLocale", (PVOID*) &pValidateLocale }, { "GetNlsSectionName", (PVOID*) &pGetNlsSectionName }, { "GetUserDefaultLangID", (PVOID*) &pGetUserDefaultLangID }, { "GetCPFileNameFromRegistry", (PVOID*) &pGetCPFileNameFromRegistry }, { "CreateNlsSecurityDescriptor", (PVOID*) &pCreateNlsSecurityDescriptor }, }; /* FUNCTIONS *****************************************************************/ NTSTATUS NTAPI BaseSrvDelayLoadKernel32(VOID) { NTSTATUS Status; ULONG i; ANSI_STRING ProcedureName; /* Only do this once */ if (BaseSrvKernel32DelayLoadComplete) return STATUS_SUCCESS; /* Loop all imports */ for (i = 0; i < RTL_NUMBER_OF(BaseSrvKernel32Imports); i++) { /* Only look them up once */ if (!*BaseSrvKernel32Imports[i].FunctionPointer) { /* If we haven't loaded the DLL yet, do it now */ if (!BaseSrvKernel32DllHandle) { Status = LdrLoadDll(0, 0, &BaseSrvKernel32DllPath, &BaseSrvKernel32DllHandle); if (!NT_SUCCESS(Status)) { DPRINT1("Failed to load %wZ\n", &BaseSrvKernel32DllPath); return Status; } } /* Get the address of the routine being looked up*/ RtlInitAnsiString(&ProcedureName, BaseSrvKernel32Imports[i].FunctionName); Status = LdrGetProcedureAddress(BaseSrvKernel32DllHandle, &ProcedureName, 0, BaseSrvKernel32Imports[i].FunctionPointer); DPRINT1("NLS: Found %Z at 0x%p\n", &ProcedureName, BaseSrvKernel32Imports[i].FunctionPointer); if (!NT_SUCCESS(Status)) break; } } /* Did we find them all? */ if (i == RTL_NUMBER_OF(BaseSrvKernel32Imports)) { /* Excellent */ BaseSrvKernel32DelayLoadComplete = TRUE; return STATUS_SUCCESS; } /* Nope, fail */ return Status; } VOID NTAPI BaseSrvNLSInit(IN PBASE_STATIC_SERVER_DATA StaticData) { /* Initialize the lock */ RtlInitializeCriticalSection(&NlsCacheCriticalSection); /* Initialize the data with all F's */ pNlsRegUserInfo = &StaticData->NlsUserInfo; RtlFillMemory(&StaticData->NlsUserInfo, sizeof(StaticData->NlsUserInfo), 0xFF); /* Set empty LCID */ pNlsRegUserInfo->UserLocaleId = 0; /* Reset the cache update counter */ RtlEnterCriticalSection(&NlsCacheCriticalSection); pNlsRegUserInfo->ulCacheUpdateCount = 0; RtlLeaveCriticalSection(&NlsCacheCriticalSection); /* Get the LCID */ NtQueryDefaultLocale(0, &pNlsRegUserInfo->UserLocaleId); } NTSTATUS NTAPI BaseSrvNlsConnect(IN PCSR_PROCESS CsrProcess, IN OUT PVOID ConnectionInfo, IN OUT PULONG ConnectionInfoLength) { /* Does nothing */ return STATUS_SUCCESS; } /* PUBLIC SERVER APIS *********************************************************/ CSR_API(BaseSrvNlsSetUserInfo) { DPRINT1("%s not yet implemented\n", __FUNCTION__); return STATUS_NOT_IMPLEMENTED; } CSR_API(BaseSrvNlsSetMultipleUserInfo) { DPRINT1("%s not yet implemented\n", __FUNCTION__); return STATUS_NOT_IMPLEMENTED; } CSR_API(BaseSrvNlsCreateSection) { NTSTATUS Status; HANDLE SectionHandle, ProcessHandle, FileHandle; ULONG LocaleId; UNICODE_STRING NlsSectionName; PWCHAR NlsFileName; UCHAR SecurityDescriptor[NLS_SECTION_SECURITY_DESCRIPTOR_SIZE]; OBJECT_ATTRIBUTES ObjectAttributes; WCHAR FileNameBuffer[32]; WCHAR NlsSectionNameBuffer[32]; PBASE_NLS_CREATE_SECTION NlsMsg = &((PBASE_API_MESSAGE)ApiMessage)->Data.NlsCreateSection; /* Load kernel32 first and import the NLS routines */ Status = BaseSrvDelayLoadKernel32(); if (!NT_SUCCESS(Status)) return Status; /* Assume failure */ NlsMsg->SectionHandle = NULL; /* Check and validate the locale ID, if one is present */ LocaleId = NlsMsg->LocaleId; DPRINT1("NLS: Create Section with LCID: %lx for Type: %d\n", LocaleId, NlsMsg->Type); if (LocaleId) { if (!pValidateLocale(LocaleId)) return STATUS_INVALID_PARAMETER; } /* Check which NLS section is being created */ switch (NlsMsg->Type) { /* For each one, set the correct filename and object name */ case 1: RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionUnicode"); NlsFileName = L"unicode.nls"; break; case 2: RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionLocale"); NlsFileName = L"locale.nls"; break; case 3: RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionCType"); NlsFileName = L"ctype.nls"; break; case 4: RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionSortkey"); NlsFileName = L"sortkey.nls"; break; case 5: RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionSortTbls"); NlsFileName = L"sorttbls.nls"; break; case 6: RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionCP437"); NlsFileName = L"c_437.nls"; break; case 7: RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionCP1252"); NlsFileName = L"c_1252.nls"; break; case 8: RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionLANG_EXCEPT"); NlsFileName = L"l_except.nls"; break; case 9: DPRINT1("This type not yet supported\n"); return STATUS_NOT_IMPLEMENTED; case 10: DPRINT1("This type not yet supported\n"); return STATUS_NOT_IMPLEMENTED; case 11: /* Get the filename for this locale */ if (!pGetCPFileNameFromRegistry(NlsMsg->LocaleId, FileNameBuffer, RTL_NUMBER_OF(FileNameBuffer))) { DPRINT1("File name query failed\n"); return STATUS_INVALID_PARAMETER; } /* Get the name of the section for this locale */ DPRINT1("File name: %S\n", FileNameBuffer); Status = pGetNlsSectionName(NlsMsg->LocaleId, 10, 0, L"\\NLS\\NlsSectionCP", NlsSectionNameBuffer, RTL_NUMBER_OF(NlsSectionNameBuffer)); if (!NT_SUCCESS(Status)) { DPRINT1("Section name query failed: %lx\n", Status); return Status; } /* Setup the name and go open it */ NlsFileName = FileNameBuffer; DPRINT1("Section name: %S\n", NlsSectionNameBuffer); RtlInitUnicodeString(&NlsSectionName, NlsSectionNameBuffer); break; case 12: RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionGeo"); NlsFileName = L"geo.nls"; break; default: DPRINT1("NLS: Invalid NLS type!\n"); return STATUS_INVALID_PARAMETER; } /* Open the specified NLS file */ Status = pOpenDataFile(&FileHandle, NlsFileName); if (Status != STATUS_SUCCESS) { DPRINT1("NLS: Failed to open file: %lx\n", Status); return Status; } /* Create an SD for the section object */ Status = pCreateNlsSecurityDescriptor(&SecurityDescriptor, sizeof(SecurityDescriptor), SECTION_MAP_READ); if (!NT_SUCCESS(Status)) { DPRINT1("NLS: CreateNlsSecurityDescriptor FAILED!: %lx\n", Status); NtClose(FileHandle); return Status; } /* Create the section object proper */ InitializeObjectAttributes(&ObjectAttributes, &NlsSectionName, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT | OBJ_OPENIF, NULL, &SecurityDescriptor); Status = NtCreateSection(&SectionHandle, SECTION_MAP_READ, &ObjectAttributes, 0, PAGE_READONLY, SEC_COMMIT, FileHandle); NtClose(FileHandle); if (!NT_SUCCESS(Status)) { DPRINT1("NLS: Failed to create section! %lx\n", Status); return Status; } /* Open a handle to the calling process */ InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL); Status = NtOpenProcess(&ProcessHandle, PROCESS_DUP_HANDLE, &ObjectAttributes, &ApiMessage->Header.ClientId); if (!NT_SUCCESS(Status)) { DPRINT1("NLS: Failed to open process! %lx\n", Status); NtClose(SectionHandle); return Status; } /* Duplicate the handle to the section object into it */ Status = NtDuplicateObject(NtCurrentProcess(), SectionHandle, ProcessHandle, &NlsMsg->SectionHandle, 0, 0, 3); NtClose(ProcessHandle); return Status; } CSR_API(BaseSrvNlsUpdateCacheCount) { DPRINT1("%s not yet implemented\n", __FUNCTION__); return STATUS_NOT_IMPLEMENTED; } CSR_API(BaseSrvNlsGetUserInfo) { NTSTATUS Status; PBASE_NLS_GET_USER_INFO NlsMsg = &((PBASE_API_MESSAGE)ApiMessage)->Data.NlsGetUserInfo; /* Make sure the buffer is valid and of the right size */ if ((CsrValidateMessageBuffer(ApiMessage, &NlsMsg->NlsUserInfo, NlsMsg->Size, sizeof(BYTE))) && (NlsMsg->Size == sizeof(NLS_USER_INFO))) { /* Acquire the lock to prevent updates while we copy */ Status = RtlEnterCriticalSection(&NlsCacheCriticalSection); if (NT_SUCCESS(Status)) { /* Do the copy now, then drop the lock */ RtlCopyMemory(NlsMsg->NlsUserInfo, pNlsRegUserInfo, NlsMsg->Size); DPRINT1("NLS Data copy complete\n"); RtlLeaveCriticalSection(&NlsCacheCriticalSection); } } else { /* The data was invalid, bail out */ DPRINT1("NLS: Size of info is invalid: %lx vs %lx\n", NlsMsg->Size, sizeof(NLS_USER_INFO)); Status = STATUS_INVALID_PARAMETER; } /* All done */ return Status; } /* PUBLIC APIS ****************************************************************/ NTSTATUS NTAPI BaseSrvNlsLogon(DWORD Unknown) { DPRINT1("%s(%lu) not yet implemented\n", __FUNCTION__, Unknown); return STATUS_NOT_IMPLEMENTED; } NTSTATUS NTAPI BaseSrvNlsUpdateRegistryCache(DWORD Unknown1, DWORD Unknown2) { DPRINT1("%s(%lu, %lu) not yet implemented\n", __FUNCTION__, Unknown1, Unknown2); return STATUS_NOT_IMPLEMENTED; } /* EOF */