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