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
BaseSrvDelayLoadKernel32(VOID)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
BaseSrvNLSInit(IN PBASE_STATIC_SERVER_DATA StaticData)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
BaseSrvNlsConnect(IN PCSR_PROCESS CsrProcess,IN OUT PVOID ConnectionInfo,IN OUT PULONG ConnectionInfoLength)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
CSR_API(BaseSrvNlsSetUserInfo)150 CSR_API(BaseSrvNlsSetUserInfo)
151 {
152 DPRINT1("%s not yet implemented\n", __FUNCTION__);
153 return STATUS_NOT_IMPLEMENTED;
154 }
155
CSR_API(BaseSrvNlsSetMultipleUserInfo)156 CSR_API(BaseSrvNlsSetMultipleUserInfo)
157 {
158 DPRINT1("%s not yet implemented\n", __FUNCTION__);
159 return STATUS_NOT_IMPLEMENTED;
160 }
161
CSR_API(BaseSrvNlsCreateSection)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
CSR_API(BaseSrvNlsUpdateCacheCount)334 CSR_API(BaseSrvNlsUpdateCacheCount)
335 {
336 DPRINT1("%s not yet implemented\n", __FUNCTION__);
337 return STATUS_NOT_IMPLEMENTED;
338 }
339
CSR_API(BaseSrvNlsGetUserInfo)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
BaseSrvNlsLogon(DWORD Unknown)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
BaseSrvNlsUpdateRegistryCache(DWORD Unknown1,DWORD Unknown2)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