1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Base API Server DLL 4 * FILE: subsystems/win/basesrv/nls.c 5 * PURPOSE: National Language Support (NLS) 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include "basesrv.h" 12 13 #include <ndk/mmfuncs.h> 14 15 #define NDEBUG 16 #include <debug.h> 17 18 /* GLOBALS ********************************************************************/ 19 20 RTL_CRITICAL_SECTION NlsCacheCriticalSection; 21 PNLS_USER_INFO pNlsRegUserInfo; 22 23 BOOLEAN BaseSrvKernel32DelayLoadComplete; 24 HANDLE BaseSrvKernel32DllHandle; 25 UNICODE_STRING BaseSrvKernel32DllPath; 26 27 POPEN_DATA_FILE pOpenDataFile; 28 PVOID /*PGET_DEFAULT_SORTKEY_SIZE */ pGetDefaultSortkeySize; 29 PVOID /*PGET_LINGUIST_LANG_SIZE*/ pGetLinguistLangSize; 30 PVOID /*PNLS_CONVERT_INTEGER_TO_STRING*/ pNlsConvertIntegerToString; 31 PVOID /*PVALIDATE_LCTYPE*/ pValidateLCType; 32 PVALIDATE_LOCALE pValidateLocale; 33 PGET_NLS_SECTION_NAME pGetNlsSectionName; 34 PVOID /*PGET_USER_DEFAULT_LANGID*/ pGetUserDefaultLangID; 35 PGET_CP_FILE_NAME_FROM_REGISTRY pGetCPFileNameFromRegistry; 36 37 NTSTATUS 38 (WINAPI *pCreateNlsSecurityDescriptor)( 39 _Out_ PSECURITY_DESCRIPTOR SecurityDescriptor, 40 _In_ SIZE_T DescriptorSize, 41 _In_ ULONG AccessMask); 42 43 BASESRV_KERNEL_IMPORTS BaseSrvKernel32Imports[10] = 44 { 45 { "OpenDataFile", (PVOID*) &pOpenDataFile }, 46 { "GetDefaultSortkeySize", (PVOID*) &pGetDefaultSortkeySize }, 47 { "GetLinguistLangSize", (PVOID*) &pGetLinguistLangSize }, 48 { "NlsConvertIntegerToString", (PVOID*) &pNlsConvertIntegerToString }, 49 { "ValidateLCType", (PVOID*) &pValidateLCType }, 50 { "ValidateLocale", (PVOID*) &pValidateLocale }, 51 { "GetNlsSectionName", (PVOID*) &pGetNlsSectionName }, 52 { "GetUserDefaultLangID", (PVOID*) &pGetUserDefaultLangID }, 53 { "GetCPFileNameFromRegistry", (PVOID*) &pGetCPFileNameFromRegistry }, 54 { "CreateNlsSecurityDescriptor", (PVOID*) &pCreateNlsSecurityDescriptor }, 55 }; 56 57 /* FUNCTIONS *****************************************************************/ 58 59 NTSTATUS 60 NTAPI 61 BaseSrvDelayLoadKernel32(VOID) 62 { 63 NTSTATUS Status; 64 ULONG i; 65 ANSI_STRING ProcedureName; 66 67 /* Only do this once */ 68 if (BaseSrvKernel32DelayLoadComplete) return STATUS_SUCCESS; 69 70 /* Loop all imports */ 71 for (i = 0; i < RTL_NUMBER_OF(BaseSrvKernel32Imports); i++) 72 { 73 /* Only look them up once */ 74 if (!*BaseSrvKernel32Imports[i].FunctionPointer) 75 { 76 /* If we haven't loaded the DLL yet, do it now */ 77 if (!BaseSrvKernel32DllHandle) 78 { 79 Status = LdrLoadDll(0, 80 0, 81 &BaseSrvKernel32DllPath, 82 &BaseSrvKernel32DllHandle); 83 if (!NT_SUCCESS(Status)) 84 { 85 DPRINT1("Failed to load %wZ\n", &BaseSrvKernel32DllPath); 86 return Status; 87 } 88 } 89 90 /* Get the address of the routine being looked up*/ 91 RtlInitAnsiString(&ProcedureName, BaseSrvKernel32Imports[i].FunctionName); 92 Status = LdrGetProcedureAddress(BaseSrvKernel32DllHandle, 93 &ProcedureName, 94 0, 95 BaseSrvKernel32Imports[i].FunctionPointer); 96 DPRINT1("NLS: Found %Z at 0x%p\n", 97 &ProcedureName, 98 BaseSrvKernel32Imports[i].FunctionPointer); 99 if (!NT_SUCCESS(Status)) break; 100 } 101 } 102 103 /* Did we find them all? */ 104 if (i == RTL_NUMBER_OF(BaseSrvKernel32Imports)) 105 { 106 /* Excellent */ 107 BaseSrvKernel32DelayLoadComplete = TRUE; 108 return STATUS_SUCCESS; 109 } 110 111 /* Nope, fail */ 112 return Status; 113 } 114 115 VOID 116 NTAPI 117 BaseSrvNLSInit(IN PBASE_STATIC_SERVER_DATA StaticData) 118 { 119 /* Initialize the lock */ 120 RtlInitializeCriticalSection(&NlsCacheCriticalSection); 121 122 /* Initialize the data with all F's */ 123 pNlsRegUserInfo = &StaticData->NlsUserInfo; 124 RtlFillMemory(&StaticData->NlsUserInfo, sizeof(StaticData->NlsUserInfo), 0xFF); 125 126 /* Set empty LCID */ 127 pNlsRegUserInfo->UserLocaleId = 0; 128 129 /* Reset the cache update counter */ 130 RtlEnterCriticalSection(&NlsCacheCriticalSection); 131 pNlsRegUserInfo->ulCacheUpdateCount = 0; 132 RtlLeaveCriticalSection(&NlsCacheCriticalSection); 133 134 /* Get the LCID */ 135 NtQueryDefaultLocale(0, &pNlsRegUserInfo->UserLocaleId); 136 } 137 138 NTSTATUS 139 NTAPI 140 BaseSrvNlsConnect(IN PCSR_PROCESS CsrProcess, 141 IN OUT PVOID ConnectionInfo, 142 IN OUT PULONG ConnectionInfoLength) 143 { 144 /* Does nothing */ 145 return STATUS_SUCCESS; 146 } 147 148 /* PUBLIC SERVER APIS *********************************************************/ 149 150 CSR_API(BaseSrvNlsSetUserInfo) 151 { 152 DPRINT1("%s not yet implemented\n", __FUNCTION__); 153 return STATUS_NOT_IMPLEMENTED; 154 } 155 156 CSR_API(BaseSrvNlsSetMultipleUserInfo) 157 { 158 DPRINT1("%s not yet implemented\n", __FUNCTION__); 159 return STATUS_NOT_IMPLEMENTED; 160 } 161 162 CSR_API(BaseSrvNlsCreateSection) 163 { 164 NTSTATUS Status; 165 HANDLE SectionHandle, ProcessHandle, FileHandle; 166 ULONG LocaleId; 167 UNICODE_STRING NlsSectionName; 168 PWCHAR NlsFileName; 169 UCHAR SecurityDescriptor[NLS_SECTION_SECURITY_DESCRIPTOR_SIZE]; 170 OBJECT_ATTRIBUTES ObjectAttributes; 171 WCHAR FileNameBuffer[32]; 172 WCHAR NlsSectionNameBuffer[32]; 173 PBASE_NLS_CREATE_SECTION NlsMsg = &((PBASE_API_MESSAGE)ApiMessage)->Data.NlsCreateSection; 174 175 /* Load kernel32 first and import the NLS routines */ 176 Status = BaseSrvDelayLoadKernel32(); 177 if (!NT_SUCCESS(Status)) return Status; 178 179 /* Assume failure */ 180 NlsMsg->SectionHandle = NULL; 181 182 /* Check and validate the locale ID, if one is present */ 183 LocaleId = NlsMsg->LocaleId; 184 DPRINT1("NLS: Create Section with LCID: %lx for Type: %d\n", LocaleId, NlsMsg->Type); 185 if (LocaleId) 186 { 187 if (!pValidateLocale(LocaleId)) return STATUS_INVALID_PARAMETER; 188 } 189 190 /* Check which NLS section is being created */ 191 switch (NlsMsg->Type) 192 { 193 /* For each one, set the correct filename and object name */ 194 case 1: 195 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionUnicode"); 196 NlsFileName = L"unicode.nls"; 197 break; 198 case 2: 199 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionLocale"); 200 NlsFileName = L"locale.nls"; 201 break; 202 case 3: 203 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionCType"); 204 NlsFileName = L"ctype.nls"; 205 break; 206 case 4: 207 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionSortkey"); 208 NlsFileName = L"sortkey.nls"; 209 break; 210 case 5: 211 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionSortTbls"); 212 NlsFileName = L"sorttbls.nls"; 213 break; 214 case 6: 215 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionCP437"); 216 NlsFileName = L"c_437.nls"; 217 break; 218 case 7: 219 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionCP1252"); 220 NlsFileName = L"c_1252.nls"; 221 break; 222 case 8: 223 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionLANG_EXCEPT"); 224 NlsFileName = L"l_except.nls"; 225 break; 226 case 9: 227 DPRINT1("This type not yet supported\n"); 228 return STATUS_NOT_IMPLEMENTED; 229 case 10: 230 DPRINT1("This type not yet supported\n"); 231 return STATUS_NOT_IMPLEMENTED; 232 case 11: 233 /* Get the filename for this locale */ 234 if (!pGetCPFileNameFromRegistry(NlsMsg->LocaleId, 235 FileNameBuffer, 236 RTL_NUMBER_OF(FileNameBuffer))) 237 { 238 DPRINT1("File name query failed\n"); 239 return STATUS_INVALID_PARAMETER; 240 } 241 242 /* Get the name of the section for this locale */ 243 DPRINT1("File name: %S\n", FileNameBuffer); 244 Status = pGetNlsSectionName(NlsMsg->LocaleId, 245 10, 246 0, 247 L"\\NLS\\NlsSectionCP", 248 NlsSectionNameBuffer, 249 RTL_NUMBER_OF(NlsSectionNameBuffer)); 250 if (!NT_SUCCESS(Status)) 251 { 252 DPRINT1("Section name query failed: %lx\n", Status); 253 return Status; 254 } 255 256 /* Setup the name and go open it */ 257 NlsFileName = FileNameBuffer; 258 DPRINT1("Section name: %S\n", NlsSectionNameBuffer); 259 RtlInitUnicodeString(&NlsSectionName, NlsSectionNameBuffer); 260 break; 261 case 12: 262 RtlInitUnicodeString(&NlsSectionName, L"\\NLS\\NlsSectionGeo"); 263 NlsFileName = L"geo.nls"; 264 break; 265 default: 266 DPRINT1("NLS: Invalid NLS type!\n"); 267 return STATUS_INVALID_PARAMETER; 268 } 269 270 /* Open the specified NLS file */ 271 Status = pOpenDataFile(&FileHandle, NlsFileName); 272 if (Status != STATUS_SUCCESS) 273 { 274 DPRINT1("NLS: Failed to open file: %lx\n", Status); 275 return Status; 276 } 277 278 /* Create an SD for the section object */ 279 Status = pCreateNlsSecurityDescriptor(&SecurityDescriptor, 280 sizeof(SecurityDescriptor), 281 SECTION_MAP_READ); 282 if (!NT_SUCCESS(Status)) 283 { 284 DPRINT1("NLS: CreateNlsSecurityDescriptor FAILED!: %lx\n", Status); 285 NtClose(FileHandle); 286 return Status; 287 } 288 289 /* Create the section object proper */ 290 InitializeObjectAttributes(&ObjectAttributes, 291 &NlsSectionName, 292 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT | OBJ_OPENIF, 293 NULL, 294 &SecurityDescriptor); 295 Status = NtCreateSection(&SectionHandle, 296 SECTION_MAP_READ, 297 &ObjectAttributes, 298 0, 299 PAGE_READONLY, 300 SEC_COMMIT, 301 FileHandle); 302 NtClose(FileHandle); 303 if (!NT_SUCCESS(Status)) 304 { 305 DPRINT1("NLS: Failed to create section! %lx\n", Status); 306 return Status; 307 } 308 309 /* Open a handle to the calling process */ 310 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL); 311 Status = NtOpenProcess(&ProcessHandle, 312 PROCESS_DUP_HANDLE, 313 &ObjectAttributes, 314 &ApiMessage->Header.ClientId); 315 if (!NT_SUCCESS(Status)) 316 { 317 DPRINT1("NLS: Failed to open process! %lx\n", Status); 318 NtClose(SectionHandle); 319 return Status; 320 } 321 322 /* Duplicate the handle to the section object into it */ 323 Status = NtDuplicateObject(NtCurrentProcess(), 324 SectionHandle, 325 ProcessHandle, 326 &NlsMsg->SectionHandle, 327 0, 328 0, 329 3); 330 NtClose(ProcessHandle); 331 return Status; 332 } 333 334 CSR_API(BaseSrvNlsUpdateCacheCount) 335 { 336 DPRINT1("%s not yet implemented\n", __FUNCTION__); 337 return STATUS_NOT_IMPLEMENTED; 338 } 339 340 CSR_API(BaseSrvNlsGetUserInfo) 341 { 342 NTSTATUS Status; 343 PBASE_NLS_GET_USER_INFO NlsMsg = &((PBASE_API_MESSAGE)ApiMessage)->Data.NlsGetUserInfo; 344 345 /* Make sure the buffer is valid and of the right size */ 346 if ((CsrValidateMessageBuffer(ApiMessage, &NlsMsg->NlsUserInfo, NlsMsg->Size, sizeof(BYTE))) && 347 (NlsMsg->Size == sizeof(NLS_USER_INFO))) 348 { 349 /* Acquire the lock to prevent updates while we copy */ 350 Status = RtlEnterCriticalSection(&NlsCacheCriticalSection); 351 if (NT_SUCCESS(Status)) 352 { 353 /* Do the copy now, then drop the lock */ 354 RtlCopyMemory(NlsMsg->NlsUserInfo, pNlsRegUserInfo, NlsMsg->Size); 355 DPRINT1("NLS Data copy complete\n"); 356 RtlLeaveCriticalSection(&NlsCacheCriticalSection); 357 } 358 } 359 else 360 { 361 /* The data was invalid, bail out */ 362 DPRINT1("NLS: Size of info is invalid: %lx vs %lx\n", NlsMsg->Size, sizeof(NLS_USER_INFO)); 363 Status = STATUS_INVALID_PARAMETER; 364 } 365 366 /* All done */ 367 return Status; 368 } 369 370 /* PUBLIC APIS ****************************************************************/ 371 372 NTSTATUS 373 NTAPI 374 BaseSrvNlsLogon(DWORD Unknown) 375 { 376 DPRINT1("%s(%lu) not yet implemented\n", __FUNCTION__, Unknown); 377 return STATUS_NOT_IMPLEMENTED; 378 } 379 380 NTSTATUS 381 NTAPI 382 BaseSrvNlsUpdateRegistryCache(DWORD Unknown1, 383 DWORD Unknown2) 384 { 385 DPRINT1("%s(%lu, %lu) not yet implemented\n", __FUNCTION__, Unknown1, Unknown2); 386 return STATUS_NOT_IMPLEMENTED; 387 } 388 389 /* EOF */ 390