Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1369 lines
39 KiB

  1. /*++
  2. Copyright (c) 1991-2000, Microsoft Corporation All rights reserved.
  3. Module Name:
  4. srvnls.c
  5. Abstract:
  6. This file contains the NLS Server-Side routines.
  7. Author:
  8. Julie Bennett (JulieB) 02-Dec-1992
  9. Revision History:
  10. --*/
  11. //
  12. // Include Files.
  13. //
  14. #include "basesrv.h"
  15. //
  16. // Constant Declarations.
  17. //
  18. #define MAX_PATH_LEN 512 // max length of path name
  19. #define MAX_SMALL_BUF_LEN 32 // C_nlsXXXXX.nls\0 is longest file name (15),
  20. // \NLS\NlsSectionSortkey0000XXXX\0 (31) is longest section name
  21. // Security descriptor buffer is size of SD + size of ACL + size of ACE +
  22. // sizeof SID + sizeof 1 SUB_AUTHORITY.
  23. //
  24. // THIS IS ONLY VALID FOR 1 ACE with 1 SID (SUB_AUTHORITY). If you have more it won't work for you.
  25. //
  26. // ACE is size of ACE_HEADER + size of ACCESS_MASK
  27. // SID includes the first ULONG (pointer) of the PSID_IDENTIFIER_AUTHORITY array, so this
  28. // declaration should be 4 bytes too much for a 1 ACL 1 SID 1 SubAuthority SD.
  29. // This is 52 bytes at the moment, only needs to be 48.
  30. // (I tested this by using -4, which works and -5 which STOPS during the boot.
  31. #define MAX_SMALL_SECURITY_DESCRIPTOR \
  32. (sizeof(SECURITY_DESCRIPTOR) + sizeof(ACL) + \
  33. sizeof(ACE_HEADER) + sizeof(ACCESS_MASK) + \
  34. sizeof(SID) + sizeof(PSID_IDENTIFIER_AUTHORITY ))
  35. #define MAX_KEY_VALUE_PARTINFO \
  36. (FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + MAX_REG_VAL_SIZE)
  37. //
  38. // Get the data pointer for the KEY_VALUE_FULL_INFORMATION structure.
  39. //
  40. #define GET_VALUE_DATA_PTR(p) ((LPWSTR)((PBYTE)(p) + (p)->DataOffset))
  41. //
  42. // Size of stack buffer for PKEY_VALUE_FULL_INFORMATION pointer.
  43. //
  44. #define MAX_KEY_VALUE_FULLINFO \
  45. ( FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION, Name ) + MAX_PATH_LEN )
  46. //
  47. // Typedef Declarations.
  48. //
  49. //
  50. // These MUST remain in the same order as the NLS_USER_INFO structure.
  51. //
  52. LPWSTR pCPanelRegValues[] =
  53. {
  54. L"sLanguage",
  55. L"iCountry",
  56. L"sCountry",
  57. L"sList",
  58. L"iMeasure",
  59. L"iPaperSize",
  60. L"sDecimal",
  61. L"sThousand",
  62. L"sGrouping",
  63. L"iDigits",
  64. L"iLZero",
  65. L"iNegNumber",
  66. L"sNativeDigits",
  67. L"NumShape",
  68. L"sCurrency",
  69. L"sMonDecimalSep",
  70. L"sMonThousandSep",
  71. L"sMonGrouping",
  72. L"iCurrDigits",
  73. L"iCurrency",
  74. L"iNegCurr",
  75. L"sPositiveSign",
  76. L"sNegativeSign",
  77. L"sTimeFormat",
  78. L"sTime",
  79. L"iTime",
  80. L"iTLZero",
  81. L"iTimePrefix",
  82. L"s1159",
  83. L"s2359",
  84. L"sShortDate",
  85. L"sDate",
  86. L"iDate",
  87. L"sYearMonth",
  88. L"sLongDate",
  89. L"iCalendarType",
  90. L"iFirstDayOfWeek",
  91. L"iFirstWeekOfYear",
  92. L"Locale"
  93. };
  94. int NumCPanelRegValues = (sizeof(pCPanelRegValues) / sizeof(LPWSTR));
  95. //
  96. // Global Variables.
  97. //
  98. // Critical Section to protect the NLS cache, which caches the current user settings from registry.
  99. RTL_CRITICAL_SECTION NlsCacheCriticalSection;
  100. HANDLE hCPanelIntlKeyRead = INVALID_HANDLE_VALUE;
  101. HANDLE hCPanelIntlKeyWrite = INVALID_HANDLE_VALUE;
  102. PNLS_USER_INFO pNlsRegUserInfo;
  103. ULONG NlsChangeBuffer;
  104. IO_STATUS_BLOCK IoStatusBlock;
  105. //
  106. // Forward Declarations.
  107. //
  108. ULONG
  109. NlsSetRegAndCache(
  110. LPWSTR pValue,
  111. LPWSTR pCacheString,
  112. LPWSTR pData,
  113. ULONG DataLength);
  114. VOID
  115. NlsUpdateCacheInfo(VOID);
  116. NTSTATUS GetThreadAuthenticationId(
  117. PLUID Luid);
  118. ////////////////////////////////////////////////////////////////////////////
  119. //
  120. // BaseSrvNLSInit
  121. //
  122. // This routine creates the shared heap for the nls information.
  123. // This is called when csrss.exe is initialized.
  124. //
  125. // 08-19-94 JulieB Created.
  126. ////////////////////////////////////////////////////////////////////////////
  127. NTSTATUS
  128. BaseSrvNLSInit(
  129. PBASE_STATIC_SERVER_DATA pStaticServerData)
  130. {
  131. NTSTATUS rc; // return code
  132. //
  133. // Create a critical section to protect the cache.
  134. //
  135. rc = RtlInitializeCriticalSection (&NlsCacheCriticalSection);
  136. if (!NT_SUCCESS(rc))
  137. {
  138. KdPrint(("NLSAPI (BaseSrv): Could NOT Create Cache critical section - %lx.\n", rc));
  139. return (rc);
  140. }
  141. //
  142. // Initialize the cache to zero.
  143. //
  144. pNlsRegUserInfo = &(pStaticServerData->NlsUserInfo);
  145. RtlFillMemory(pNlsRegUserInfo, sizeof(NLS_USER_INFO), (CHAR)NLS_INVALID_INFO_CHAR);
  146. pNlsRegUserInfo->UserLocaleId = 0;
  147. pNlsRegUserInfo->ulCacheUpdateCount = 0;
  148. //
  149. // Make the system locale the user locale.
  150. //
  151. NtQueryDefaultLocale(FALSE, &(pNlsRegUserInfo->UserLocaleId));
  152. //
  153. // Return success.
  154. //
  155. return (STATUS_SUCCESS);
  156. }
  157. ////////////////////////////////////////////////////////////////////////////
  158. //
  159. // BaseSrvNLSConnect
  160. //
  161. // This routine duplicates the mutant handle for the client.
  162. //
  163. // 08-19-94 JulieB Created.
  164. ////////////////////////////////////////////////////////////////////////////
  165. NTSTATUS
  166. BaseSrvNlsConnect(
  167. PCSR_PROCESS Process,
  168. PVOID pConnectionInfo,
  169. PULONG pConnectionInfoLength)
  170. {
  171. return (STATUS_SUCCESS);
  172. }
  173. ////////////////////////////////////////////////////////////////////////////
  174. //
  175. // BaseSrvNlsLogon
  176. //
  177. // This routine initializes the heap for the nls information. If fLogon
  178. // is TRUE, then it opens the registry key, initializes the heap
  179. // information, and registers the key for notification. If fLogon is
  180. // FALSE, then it unregisters the key for notification, zeros out the
  181. // heap information, and closes the registry key.
  182. //
  183. // 08-19-94 JulieB Created.
  184. ////////////////////////////////////////////////////////////////////////////
  185. NTSTATUS
  186. BaseSrvNlsLogon(
  187. BOOL fLogon)
  188. {
  189. HANDLE hKeyRead; // temp handle for read access
  190. HANDLE hKeyWrite; // temp handle for write access
  191. HANDLE hUserHandle; // HKEY_CURRENT_USER equivalent
  192. OBJECT_ATTRIBUTES ObjA; // object attributes structure
  193. UNICODE_STRING ObKeyName; // key name
  194. NTSTATUS rc = STATUS_SUCCESS; // return code
  195. RTL_SOFT_VERIFY(NT_SUCCESS(rc = BaseSrvSxsInvalidateSystemDefaultActivationContextCache()));
  196. if (fLogon)
  197. {
  198. //
  199. // Retreive the currently logged on interactive user's Luid
  200. // authentication id. The currently executing thread is
  201. // impersonating the logged on user.
  202. //
  203. if (pNlsRegUserInfo != NULL)
  204. {
  205. GetThreadAuthenticationId(&pNlsRegUserInfo->InteractiveUserLuid);
  206. //
  207. // Logging ON.
  208. // - open keys
  209. //
  210. // NOTE: Registry Notification is done by the RIT in user server.
  211. //
  212. rc = RtlOpenCurrentUser(MAXIMUM_ALLOWED, &hUserHandle);
  213. if (!NT_SUCCESS(rc))
  214. {
  215. KdPrint(("NLSAPI (BaseSrv): Could NOT Open HKEY_CURRENT_USER - %lx.\n", rc));
  216. return (rc);
  217. }
  218. RtlInitUnicodeString(&ObKeyName, L"Control Panel\\International");
  219. InitializeObjectAttributes( &ObjA,
  220. &ObKeyName,
  221. OBJ_CASE_INSENSITIVE,
  222. hUserHandle,
  223. NULL );
  224. //
  225. // Open key for READ and NOTIFY access.
  226. //
  227. rc = NtOpenKey( &hKeyRead,
  228. KEY_READ | KEY_NOTIFY,
  229. &ObjA );
  230. //
  231. // Open key for WRITE access.
  232. //
  233. if (!NT_SUCCESS(NtOpenKey( &hKeyWrite,
  234. KEY_WRITE,
  235. &ObjA )))
  236. {
  237. KdPrint(("NLSAPI (BaseSrv): Could NOT Open Registry Key %wZ for Write - %lx.\n",
  238. &ObKeyName, rc));
  239. hKeyWrite = INVALID_HANDLE_VALUE;
  240. }
  241. //
  242. // Close the handle to the current user (HKEY_CURRENT_USER).
  243. //
  244. NtClose(hUserHandle);
  245. //
  246. // Check for error from first NtOpenKey.
  247. //
  248. if (!NT_SUCCESS(rc))
  249. {
  250. KdPrint(("NLSAPI (BaseSrv): Could NOT Open Registry Key %wZ for Read - %lx.\n",
  251. &ObKeyName, rc));
  252. if (hKeyWrite != INVALID_HANDLE_VALUE)
  253. {
  254. NtClose(hKeyWrite);
  255. }
  256. return (rc);
  257. }
  258. //
  259. // Enter the critical section so that we don't mess up the public handle.
  260. //
  261. rc = RtlEnterCriticalSection(&NlsCacheCriticalSection);
  262. if (!NT_SUCCESS( rc ))
  263. {
  264. return (rc);
  265. }
  266. //
  267. // Make sure any old handles are closed.
  268. //
  269. if (hCPanelIntlKeyRead != INVALID_HANDLE_VALUE)
  270. {
  271. NtClose(hCPanelIntlKeyRead);
  272. }
  273. if (hCPanelIntlKeyWrite != INVALID_HANDLE_VALUE)
  274. {
  275. NtClose(hCPanelIntlKeyWrite);
  276. }
  277. //
  278. // Save the new handles.
  279. //
  280. hCPanelIntlKeyRead = hKeyRead;
  281. hCPanelIntlKeyWrite = hKeyWrite;
  282. RtlLeaveCriticalSection(&NlsCacheCriticalSection);
  283. }
  284. }
  285. else
  286. {
  287. //
  288. // Logging OFF.
  289. // - close keys
  290. // - zero out info
  291. //
  292. //
  293. // This may come as NULL, during stress memory cond for terminal
  294. // server (when NLS cache mutant couldn't be created).
  295. //
  296. if (pNlsRegUserInfo != NULL)
  297. {
  298. rc = RtlEnterCriticalSection(&NlsCacheCriticalSection);
  299. if (!NT_SUCCESS( rc ))
  300. {
  301. return (rc);
  302. }
  303. if (hCPanelIntlKeyRead != INVALID_HANDLE_VALUE)
  304. {
  305. NtClose(hCPanelIntlKeyRead);
  306. hCPanelIntlKeyRead = INVALID_HANDLE_VALUE;
  307. }
  308. if (hCPanelIntlKeyWrite != INVALID_HANDLE_VALUE)
  309. {
  310. NtClose(hCPanelIntlKeyWrite);
  311. hCPanelIntlKeyWrite = INVALID_HANDLE_VALUE;
  312. }
  313. //
  314. // Fill the cache with NLS_INVALID_INFO_CHAR.
  315. //
  316. RtlFillMemory(pNlsRegUserInfo, sizeof(NLS_USER_INFO), (CHAR)NLS_INVALID_INFO_CHAR);
  317. pNlsRegUserInfo->UserLocaleId = 0;
  318. pNlsRegUserInfo->ulCacheUpdateCount = 0;
  319. //
  320. // Make the system locale the user locale.
  321. //
  322. NtQueryDefaultLocale(FALSE, &(pNlsRegUserInfo->UserLocaleId));
  323. //
  324. // No need to reset the User's Authentication Id, since it's
  325. // being zero'ed out above.
  326. //
  327. RtlLeaveCriticalSection(&NlsCacheCriticalSection);
  328. }
  329. }
  330. //
  331. // Return success.
  332. //
  333. return (STATUS_SUCCESS);
  334. }
  335. ////////////////////////////////////////////////////////////////////////////
  336. //
  337. // BaseSrvNlsUpdateRegistryCache
  338. //
  339. // This routine updates the NLS cache when a registry notification occurs.
  340. //
  341. // 08-19-94 JulieB Created.
  342. ////////////////////////////////////////////////////////////////////////////
  343. VOID
  344. BaseSrvNlsUpdateRegistryCache(
  345. PVOID ApcContext,
  346. PIO_STATUS_BLOCK pIoStatusBlock)
  347. {
  348. ULONG rc = 0L; // return code
  349. if (hCPanelIntlKeyRead == INVALID_HANDLE_VALUE)
  350. {
  351. return;
  352. }
  353. if (!NT_SUCCESS(RtlEnterCriticalSection(&NlsCacheCriticalSection)))
  354. {
  355. return;
  356. }
  357. if (hCPanelIntlKeyRead == INVALID_HANDLE_VALUE)
  358. {
  359. RtlLeaveCriticalSection( &NlsCacheCriticalSection );
  360. return;
  361. }
  362. //
  363. // Update the cache information.
  364. //
  365. NlsUpdateCacheInfo();
  366. RtlLeaveCriticalSection( &NlsCacheCriticalSection );
  367. //
  368. // Call NtNotifyChangeKey.
  369. //
  370. rc = NtNotifyChangeKey( hCPanelIntlKeyRead,
  371. NULL,
  372. (PIO_APC_ROUTINE)BaseSrvNlsUpdateRegistryCache,
  373. NULL,
  374. &IoStatusBlock,
  375. REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_NAME,
  376. FALSE,
  377. &NlsChangeBuffer,
  378. sizeof(NlsChangeBuffer),
  379. TRUE );
  380. #ifdef DBG
  381. //
  382. // Check for error from NtNotifyChangeKey.
  383. //
  384. if (!NT_SUCCESS(rc))
  385. {
  386. KdPrint(("NLSAPI (BaseSrv): Could NOT Set Notification of Control Panel International Registry Key - %lx.\n",
  387. rc));
  388. }
  389. #endif
  390. }
  391. ////////////////////////////////////////////////////////////////////////////
  392. //
  393. // NlsSetRegAndCache
  394. //
  395. // This routine sets the registry with the appropriate string and then
  396. // updates the cache.
  397. //
  398. // NOTE: Must already own the mutant for the cache before calling this
  399. // routine.
  400. //
  401. // 08-19-94 JulieB Created.
  402. ////////////////////////////////////////////////////////////////////////////
  403. ULONG
  404. NlsSetRegAndCache(
  405. LPWSTR pValue,
  406. LPWSTR pCacheString,
  407. LPWSTR pData,
  408. ULONG DataLength)
  409. {
  410. UNICODE_STRING ObValueName; // value name
  411. ULONG rc; // return code
  412. if (hCPanelIntlKeyWrite != INVALID_HANDLE_VALUE)
  413. {
  414. //
  415. // Validate data length to be set in the registry
  416. //
  417. if (DataLength >= MAX_REG_VAL_SIZE)
  418. {
  419. return ((ULONG)STATUS_INVALID_PARAMETER);
  420. }
  421. RTL_SOFT_VERIFY(NT_SUCCESS(rc = BaseSrvSxsInvalidateSystemDefaultActivationContextCache()));
  422. //
  423. // Set the value in the registry.
  424. //
  425. RtlInitUnicodeString(&ObValueName, pValue);
  426. rc = NtSetValueKey( hCPanelIntlKeyWrite,
  427. &ObValueName,
  428. 0,
  429. REG_SZ,
  430. (PVOID)pData,
  431. DataLength );
  432. //
  433. // Copy the new string to the cache.
  434. //
  435. if (NT_SUCCESS(rc))
  436. {
  437. wcsncpy(pCacheString, pData, DataLength);
  438. pCacheString[DataLength / sizeof(WCHAR)] = 0;
  439. }
  440. //
  441. // Return the result.
  442. //
  443. return (rc);
  444. }
  445. //
  446. // Return access denied, since the key is not open for write access.
  447. //
  448. return ((ULONG)STATUS_ACCESS_DENIED);
  449. }
  450. ////////////////////////////////////////////////////////////////////////////
  451. //
  452. // BaseSrvNlsGetUserInfo
  453. //
  454. // This routine gets a particular value in the NLS cache, and copy it
  455. // to the buffer in the capture buffer.
  456. //
  457. // Parameters:
  458. // Locale in BASE_NLS_GET_USER_INFO_MSG contains the locale requested.
  459. // CacheOffset in BASE_NLS_GET_USER_INFO_MSG contains the offset in BYTE into the pNlsRegUserInfo cache.
  460. // pData in BASE_NLS_GET_USER_INFO_MSG points to the target buffer.
  461. // DataLength in BASE_NLS_GET_USER_INFO_MSG is the size of the capture buffer in BYTE. The NULL terminator is included in the count.
  462. //
  463. //
  464. // When this function returns, the capture buffer will contain the data
  465. // of the specified field.
  466. //
  467. //
  468. // 06-06-2002 YSLin Created.
  469. ////////////////////////////////////////////////////////////////////////////
  470. NTSTATUS
  471. BaseSrvNlsGetUserInfo(
  472. IN OUT PCSR_API_MSG m,
  473. IN OUT PCSR_REPLY_STATUS ReplyStatus)
  474. {
  475. PBASE_NLS_GET_USER_INFO_MSG a =
  476. (PBASE_NLS_GET_USER_INFO_MSG)&m->u.ApiMessageData;
  477. NTSTATUS rc; // return code
  478. LPWSTR pValue; // Points to the cached value.
  479. if (!CsrValidateMessageBuffer(m, &a->pData, a->DataLength, sizeof(BYTE)))
  480. {
  481. return (STATUS_INVALID_PARAMETER);
  482. }
  483. // Check the following:
  484. // 1. Make sure that the CacheOffset can not be greater than the offset of the last field. The assumption here is that
  485. // UserLocaleId the FIRST field after any field that contains strings.
  486. // 2. Make sure that CacheOffset is always aligned in WCHAR and is aligned with the beginning of each field.
  487. // 3. DataLength can not be greater than the maximum length in BYTE.
  488. // 4. The pointer to the data is not NULL.
  489. //
  490. // There is a duplicated check in CsrBasepNlsGetUserInfo().
  491. if ((a->CacheOffset > FIELD_OFFSET(NLS_USER_INFO, UserLocaleId) - sizeof(WCHAR) * MAX_REG_VAL_SIZE) ||
  492. ((a->CacheOffset % (sizeof(WCHAR) * MAX_REG_VAL_SIZE)) != 0) ||
  493. (a->DataLength > MAX_REG_VAL_SIZE * sizeof(WCHAR)) ||
  494. (a->pData == NULL))
  495. {
  496. return (STATUS_INVALID_PARAMETER);
  497. }
  498. rc = RtlEnterCriticalSection(&NlsCacheCriticalSection);
  499. if (!NT_SUCCESS( rc ))
  500. {
  501. return (rc);
  502. }
  503. //
  504. // Check if the specified locale is the same as the one stored in the cache.
  505. //
  506. pValue = (LPWSTR)((LPBYTE)pNlsRegUserInfo + a->CacheOffset);
  507. if ((a->Locale == pNlsRegUserInfo->UserLocaleId) && (*pValue != NLS_INVALID_INFO_CHAR))
  508. {
  509. // wcsncpy will do null termination for us.
  510. // Null termination is important in this case, since a local buffer is used in
  511. // GetLocaleInfoW() to call this function.
  512. wcsncpy(a->pData, pValue, (a->DataLength)/sizeof(WCHAR));
  513. rc = STATUS_SUCCESS;
  514. } else
  515. {
  516. // The specified locale is not the current user locale stored in the cache.
  517. rc = STATUS_UNSUCCESSFUL;
  518. }
  519. RtlLeaveCriticalSection( &NlsCacheCriticalSection );
  520. //
  521. // Return the result of NtSetValueKey.
  522. //
  523. return (rc);
  524. ReplyStatus; // get rid of unreferenced parameter warning message
  525. }
  526. ////////////////////////////////////////////////////////////////////////////
  527. //
  528. // BaseSrvNlsSetUserInfo
  529. //
  530. // This routine sets a particular value in the NLS cache and updates the
  531. // registry entry.
  532. //
  533. // 08-19-94 JulieB Created.
  534. ////////////////////////////////////////////////////////////////////////////
  535. ULONG
  536. BaseSrvNlsSetUserInfo(
  537. IN OUT PCSR_API_MSG m,
  538. IN OUT PCSR_REPLY_STATUS ReplyStatus)
  539. {
  540. PBASE_NLS_SET_USER_INFO_MSG a =
  541. (PBASE_NLS_SET_USER_INFO_MSG)&m->u.ApiMessageData;
  542. ULONG rc; // return code
  543. LPWSTR pValue;
  544. LPWSTR pCache;
  545. if (!CsrValidateMessageBuffer(m, &a->pData, a->DataLength, sizeof(BYTE)))
  546. {
  547. return (STATUS_INVALID_PARAMETER);
  548. }
  549. RTL_VERIFY(NT_SUCCESS(rc = BaseSrvDelayLoadKernel32()));
  550. ASSERT(pValidateLCType != NULL);
  551. if (0 == (*pValidateLCType)(pNlsRegUserInfo, a->LCType, &pValue, &pCache))
  552. {
  553. return (STATUS_INVALID_PARAMETER);
  554. }
  555. rc = RtlEnterCriticalSection(&NlsCacheCriticalSection);
  556. if (!NT_SUCCESS( rc ))
  557. {
  558. return (rc);
  559. }
  560. //
  561. // Set the value in the registry and update the cache.
  562. //
  563. rc = NlsSetRegAndCache( pValue,
  564. pCache,
  565. a->pData,
  566. a->DataLength );
  567. if (NT_SUCCESS(rc))
  568. {
  569. pNlsRegUserInfo->ulCacheUpdateCount++;
  570. }
  571. RtlLeaveCriticalSection( &NlsCacheCriticalSection );
  572. //
  573. // Return the result of NtSetValueKey.
  574. //
  575. return (rc);
  576. ReplyStatus; // get rid of unreferenced parameter warning message
  577. }
  578. ////////////////////////////////////////////////////////////////////////////
  579. //
  580. // BaseSrvNlsSetMultipleUserInfo
  581. //
  582. // This routine sets the date/time strings in the NLS cache and updates the
  583. // registry entries.
  584. //
  585. // This call is done so that only one client/server transition is needed
  586. // when setting multiple entries.
  587. //
  588. // 08-19-94 JulieB Created.
  589. ////////////////////////////////////////////////////////////////////////////
  590. ULONG
  591. BaseSrvNlsSetMultipleUserInfo(
  592. IN OUT PCSR_API_MSG m,
  593. IN OUT PCSR_REPLY_STATUS ReplyStatus)
  594. {
  595. PBASE_NLS_SET_MULTIPLE_USER_INFO_MSG a =
  596. (PBASE_NLS_SET_MULTIPLE_USER_INFO_MSG)&m->u.ApiMessageData;
  597. BOOL DoNotUpdateCacheCount = FALSE;
  598. ULONG rc = 0L; // return code
  599. if (!CsrValidateMessageBuffer(m, &a->pPicture, a->DataLength, sizeof(BYTE)))
  600. {
  601. return (STATUS_INVALID_PARAMETER);
  602. }
  603. if (!CsrValidateMessageString(m, &a->pSeparator))
  604. {
  605. return (STATUS_INVALID_PARAMETER);
  606. }
  607. if (!CsrValidateMessageString(m, &a->pOrder))
  608. {
  609. return (STATUS_INVALID_PARAMETER);
  610. }
  611. if (!CsrValidateMessageString(m, &a->pTLZero))
  612. {
  613. return (STATUS_INVALID_PARAMETER);
  614. }
  615. if (!CsrValidateMessageString(m, &a->pTimeMarkPosn))
  616. {
  617. return (STATUS_INVALID_PARAMETER);
  618. }
  619. rc = RtlEnterCriticalSection(&NlsCacheCriticalSection);
  620. if (!NT_SUCCESS( rc ))
  621. {
  622. return (rc);
  623. }
  624. switch (a->Flags)
  625. {
  626. case ( LOCALE_STIMEFORMAT ) :
  627. {
  628. rc = NlsSetRegAndCache( NLS_VALUE_STIMEFORMAT,
  629. pNlsRegUserInfo->sTimeFormat,
  630. a->pPicture,
  631. a->DataLength );
  632. if (NT_SUCCESS(rc))
  633. {
  634. rc = NlsSetRegAndCache( NLS_VALUE_STIME,
  635. pNlsRegUserInfo->sTime,
  636. a->pSeparator,
  637. (wcslen(a->pSeparator) + 1) * sizeof(WCHAR) );
  638. }
  639. if (NT_SUCCESS(rc))
  640. {
  641. rc = NlsSetRegAndCache( NLS_VALUE_ITIME,
  642. pNlsRegUserInfo->iTime,
  643. a->pOrder,
  644. (wcslen(a->pOrder) + 1) * sizeof(WCHAR) );
  645. }
  646. if (NT_SUCCESS(rc))
  647. {
  648. rc = NlsSetRegAndCache( NLS_VALUE_ITLZERO,
  649. pNlsRegUserInfo->iTLZero,
  650. a->pTLZero,
  651. (wcslen(a->pTLZero) + 1) * sizeof(WCHAR) );
  652. }
  653. if (NT_SUCCESS(rc))
  654. {
  655. rc = NlsSetRegAndCache( NLS_VALUE_ITIMEMARKPOSN,
  656. pNlsRegUserInfo->iTimeMarkPosn,
  657. a->pTimeMarkPosn,
  658. (wcslen(a->pTimeMarkPosn) + 1) * sizeof(WCHAR) );
  659. }
  660. break;
  661. }
  662. case ( LOCALE_STIME ) :
  663. {
  664. rc = NlsSetRegAndCache( NLS_VALUE_STIME,
  665. pNlsRegUserInfo->sTime,
  666. a->pSeparator,
  667. a->DataLength );
  668. if (NT_SUCCESS(rc))
  669. {
  670. rc = NlsSetRegAndCache( NLS_VALUE_STIMEFORMAT,
  671. pNlsRegUserInfo->sTimeFormat,
  672. a->pPicture,
  673. (wcslen(a->pPicture) + 1) * sizeof(WCHAR) );
  674. }
  675. break;
  676. }
  677. case ( LOCALE_ITIME ) :
  678. {
  679. rc = NlsSetRegAndCache( NLS_VALUE_ITIME,
  680. pNlsRegUserInfo->iTime,
  681. a->pOrder,
  682. a->DataLength );
  683. if (NT_SUCCESS(rc))
  684. {
  685. rc = NlsSetRegAndCache( NLS_VALUE_STIMEFORMAT,
  686. pNlsRegUserInfo->sTimeFormat,
  687. a->pPicture,
  688. (wcslen(a->pPicture) + 1) * sizeof(WCHAR) );
  689. }
  690. break;
  691. }
  692. case ( LOCALE_SSHORTDATE ) :
  693. {
  694. rc = NlsSetRegAndCache( NLS_VALUE_SSHORTDATE,
  695. pNlsRegUserInfo->sShortDate,
  696. a->pPicture,
  697. a->DataLength );
  698. if (NT_SUCCESS(rc))
  699. {
  700. rc = NlsSetRegAndCache( NLS_VALUE_SDATE,
  701. pNlsRegUserInfo->sDate,
  702. a->pSeparator,
  703. (wcslen(a->pSeparator) + 1) * sizeof(WCHAR) );
  704. }
  705. if (NT_SUCCESS(rc))
  706. {
  707. rc = NlsSetRegAndCache( NLS_VALUE_IDATE,
  708. pNlsRegUserInfo->iDate,
  709. a->pOrder,
  710. (wcslen(a->pOrder) + 1) * sizeof(WCHAR) );
  711. }
  712. break;
  713. }
  714. case ( LOCALE_SDATE ) :
  715. {
  716. rc = NlsSetRegAndCache( NLS_VALUE_SDATE,
  717. pNlsRegUserInfo->sDate,
  718. a->pSeparator,
  719. a->DataLength );
  720. if (NT_SUCCESS(rc))
  721. {
  722. rc = NlsSetRegAndCache( NLS_VALUE_SSHORTDATE,
  723. pNlsRegUserInfo->sShortDate,
  724. a->pPicture,
  725. (wcslen(a->pPicture) + 1) * sizeof(WCHAR) );
  726. }
  727. break;
  728. }
  729. default:
  730. {
  731. DoNotUpdateCacheCount = TRUE;
  732. break;
  733. }
  734. }
  735. if (NT_SUCCESS(rc) && (DoNotUpdateCacheCount == FALSE))
  736. {
  737. pNlsRegUserInfo->ulCacheUpdateCount++;
  738. }
  739. RtlLeaveCriticalSection(&NlsCacheCriticalSection);
  740. //
  741. // Return the result.
  742. //
  743. return (rc);
  744. ReplyStatus; // get rid of unreferenced parameter warning message
  745. }
  746. ////////////////////////////////////////////////////////////////////////////
  747. //
  748. // BaseSrvNlsUpdateCacheCount
  749. //
  750. // This routine forces an increment on pNlsUserInfo->ulNlsCacheUpdateCount
  751. //
  752. // 11-29-99 SamerA Created.
  753. ////////////////////////////////////////////////////////////////////////////
  754. ULONG
  755. BaseSrvNlsUpdateCacheCount(
  756. IN OUT PCSR_API_MSG m,
  757. IN OUT PCSR_REPLY_STATUS ReplyStatus)
  758. {
  759. PBASE_NLS_UPDATE_CACHE_COUNT_MSG a =
  760. (PBASE_NLS_UPDATE_CACHE_COUNT_MSG)&m->u.ApiMessageData;
  761. //
  762. // Increment the cache count.
  763. // We don't use a mutex to protect this, since the only opertation that happens is
  764. // to increment the cache update count, also once pNlsRegUserInfo is set to a valid
  765. // memory location, then it will stay valid during the lifetime of CSRSS.
  766. //
  767. if (pNlsRegUserInfo)
  768. {
  769. pNlsRegUserInfo->ulCacheUpdateCount++;
  770. }
  771. return (0L);
  772. ReplyStatus; // get rid of unreferenced parameter warning message
  773. }
  774. ////////////////////////////////////////////////////////////////////////////
  775. //
  776. // NlsUpdateCacheInfo
  777. //
  778. // This routine updates the NLS cache when a registry notification occurs.
  779. //
  780. // 08-19-94 JulieB Created.
  781. ////////////////////////////////////////////////////////////////////////////
  782. VOID
  783. NlsUpdateCacheInfo()
  784. {
  785. LCID Locale; // locale id
  786. UNICODE_STRING ObKeyName; // key name
  787. LPWSTR pTmp; // tmp string pointer
  788. int ctr; // loop counter
  789. ULONG ResultLength; // result length
  790. ULONG rc = 0L; // return code
  791. BYTE KeyValuePart[MAX_KEY_VALUE_PARTINFO];
  792. PKEY_VALUE_PARTIAL_INFORMATION pValuePart;
  793. //
  794. // NOTE: The caller of this function should already have the
  795. // cache mutant before calling this routine.
  796. //
  797. //
  798. // Update the cache information.
  799. //
  800. pTmp = (LPWSTR)pNlsRegUserInfo;
  801. pValuePart = (PKEY_VALUE_PARTIAL_INFORMATION)KeyValuePart;
  802. for (ctr = 0; ctr < NumCPanelRegValues; ctr++)
  803. {
  804. RtlInitUnicodeString(&ObKeyName, pCPanelRegValues[ctr]);
  805. rc = NtQueryValueKey( hCPanelIntlKeyRead,
  806. &ObKeyName,
  807. KeyValuePartialInformation,
  808. pValuePart,
  809. MAX_KEY_VALUE_PARTINFO,
  810. &ResultLength );
  811. if (NT_SUCCESS(rc))
  812. {
  813. ((LPBYTE)pValuePart)[ResultLength] = UNICODE_NULL;
  814. wcscpy(pTmp, (LPWSTR)(pValuePart->Data));
  815. }
  816. else
  817. {
  818. *pTmp = NLS_INVALID_INFO_CHAR;
  819. *(pTmp + 1) = UNICODE_NULL;
  820. }
  821. //
  822. // Increment pointer to cache structure.
  823. //
  824. pTmp += MAX_REG_VAL_SIZE;
  825. }
  826. //
  827. // Once we finished reading the reg-data, let's increment
  828. // our global update cache count
  829. //
  830. pNlsRegUserInfo->ulCacheUpdateCount++;
  831. //
  832. // Convert the user locale id string to a dword value and store
  833. // it in the cache.
  834. //
  835. pNlsRegUserInfo->UserLocaleId = (LCID)0;
  836. if ((pNlsRegUserInfo->sLocale)[0] != NLS_INVALID_INFO_CHAR)
  837. {
  838. RtlInitUnicodeString(&ObKeyName, pNlsRegUserInfo->sLocale);
  839. if (NT_SUCCESS(RtlUnicodeStringToInteger(&ObKeyName, 16, &Locale)))
  840. {
  841. pNlsRegUserInfo->UserLocaleId = Locale;
  842. }
  843. }
  844. //
  845. // Make sure the user locale id was found. Otherwise, set it to
  846. // the system locale.
  847. //
  848. if (pNlsRegUserInfo->UserLocaleId == 0)
  849. {
  850. NtQueryDefaultLocale(FALSE, &(pNlsRegUserInfo->UserLocaleId));
  851. }
  852. }
  853. ////////////////////////////////////////////////////////////////////////////
  854. //
  855. // BaseSrvNlsCreateSection
  856. //
  857. ////////////////////////////////////////////////////////////////////////////
  858. ULONG
  859. BaseSrvNlsCreateSection(
  860. IN OUT PCSR_API_MSG m,
  861. IN OUT PCSR_REPLY_STATUS ReplyStatus)
  862. {
  863. PBASE_NLS_CREATE_SECTION_MSG a =
  864. (PBASE_NLS_CREATE_SECTION_MSG)&m->u.ApiMessageData;
  865. UNICODE_STRING ObSecName; // section name
  866. LARGE_INTEGER Size;
  867. WCHAR wszFileName[MAX_SMALL_BUF_LEN]; // file name (Actually l2 chars is max: c_nlsXXXXX.nls\0
  868. WCHAR wszSecName[MAX_SMALL_BUF_LEN]; // section name string
  869. HANDLE hNewSec = (HANDLE)0; // new section handle
  870. HANDLE hProcess = (HANDLE)0; // process handle
  871. OBJECT_ATTRIBUTES ObjA; // object attributes structure
  872. NTSTATUS rc = 0L; // return code
  873. LPWSTR pFile = NULL;
  874. HANDLE hFile = (HANDLE)0; // file handle
  875. ANSI_STRING proc;
  876. PVOID pTemp; // temp pointer
  877. BYTE pSecurityDescriptor[MAX_SMALL_SECURITY_DESCRIPTOR]; // Buffer for our security descriptor
  878. RTL_VERIFY(NT_SUCCESS(rc = BaseSrvDelayLoadKernel32()));
  879. //
  880. // Set the handles to null.
  881. //
  882. a->hNewSection = NULL;
  883. if (a->Locale)
  884. {
  885. if (!(*pValidateLocale)(a->Locale))
  886. {
  887. return (STATUS_INVALID_PARAMETER);
  888. }
  889. }
  890. switch (a->uiType)
  891. {
  892. case (NLS_CREATE_SECTION_UNICODE) :
  893. {
  894. RtlInitUnicodeString(&ObSecName, NLS_SECTION_UNICODE);
  895. pFile = NLS_FILE_UNICODE;
  896. break;
  897. }
  898. case (NLS_CREATE_SECTION_GEO) :
  899. {
  900. RtlInitUnicodeString(&ObSecName, NLS_SECTION_GEO);
  901. pFile = NLS_FILE_GEO;
  902. break;
  903. }
  904. case (NLS_CREATE_SECTION_LOCALE) :
  905. {
  906. RtlInitUnicodeString(&ObSecName, NLS_SECTION_LOCALE);
  907. pFile = NLS_FILE_LOCALE;
  908. break;
  909. }
  910. case (NLS_CREATE_SECTION_CTYPE) :
  911. {
  912. RtlInitUnicodeString(&ObSecName, NLS_SECTION_CTYPE);
  913. pFile = NLS_FILE_CTYPE;
  914. break;
  915. }
  916. case (NLS_CREATE_SECTION_SORTKEY) :
  917. {
  918. RtlInitUnicodeString(&ObSecName, NLS_SECTION_SORTKEY);
  919. pFile = NLS_FILE_SORTKEY;
  920. break;
  921. }
  922. case (NLS_CREATE_SECTION_SORTTBLS) :
  923. {
  924. RtlInitUnicodeString(&ObSecName, NLS_SECTION_SORTTBLS);
  925. pFile = NLS_FILE_SORTTBLS;
  926. break;
  927. }
  928. case (NLS_CREATE_SECTION_DEFAULT_OEMCP) :
  929. {
  930. RtlInitUnicodeString(&ObSecName, NLS_DEFAULT_SECTION_OEMCP);
  931. pFile = NLS_DEFAULT_FILE_OEMCP;
  932. break;
  933. }
  934. case (NLS_CREATE_SECTION_DEFAULT_ACP) :
  935. {
  936. RtlInitUnicodeString(&ObSecName, NLS_DEFAULT_SECTION_ACP);
  937. pFile = NLS_DEFAULT_FILE_ACP;
  938. break;
  939. }
  940. case (NLS_CREATE_SECTION_LANG_EXCEPT) :
  941. {
  942. RtlInitUnicodeString(&ObSecName, NLS_SECTION_LANG_EXCEPT);
  943. pFile = NLS_FILE_LANG_EXCEPT;
  944. break;
  945. }
  946. case (NLS_CREATE_CODEPAGE_SECTION) :
  947. {
  948. // Get the Code Page file name from registry
  949. ASSERT(pGetCPFileNameFromRegistry);
  950. if ( FALSE == (*pGetCPFileNameFromRegistry)( a->Locale,
  951. wszFileName,
  952. MAX_SMALL_BUF_LEN ) )
  953. {
  954. return (STATUS_INVALID_PARAMETER);
  955. }
  956. // Remember we're using this file name
  957. pFile = wszFileName;
  958. // Hmm, we'll need the section name for this section.
  959. // Note that this had better be in sync with what we see
  960. // in winnls\tables.c or else the server will be called needlessly.
  961. ASSERT(pGetNlsSectionName != NULL);
  962. if (!NT_SUCCESS((*pGetNlsSectionName)( a->Locale,
  963. 10,
  964. 0,
  965. NLS_SECTION_CPPREFIX,
  966. wszSecName,
  967. MAX_SMALL_BUF_LEN)))
  968. {
  969. return (rc);
  970. }
  971. // Make it a string we can remember/use later
  972. RtlInitUnicodeString(&ObSecName, wszSecName);
  973. break;
  974. }
  975. case ( NLS_CREATE_SORT_SECTION ) :
  976. {
  977. if (a->Locale == 0)
  978. {
  979. return (STATUS_INVALID_PARAMETER);
  980. }
  981. ASSERT(pGetNlsSectionName != NULL);
  982. if (rc = (*pGetNlsSectionName)( a->Locale,
  983. 16,
  984. 8,
  985. NLS_SECTION_SORTKEY,
  986. wszSecName,
  987. MAX_SMALL_BUF_LEN))
  988. {
  989. return (rc);
  990. }
  991. ASSERT(pGetDefaultSortkeySize != NULL);
  992. (*pGetDefaultSortkeySize)(&Size);
  993. RtlInitUnicodeString(&ObSecName, wszSecName);
  994. break;
  995. }
  996. case ( NLS_CREATE_LANG_EXCEPTION_SECTION ) :
  997. {
  998. if (a->Locale == 0)
  999. {
  1000. //
  1001. // Creating the default section.
  1002. //
  1003. RtlInitUnicodeString(&ObSecName, NLS_SECTION_LANG_INTL);
  1004. }
  1005. else
  1006. {
  1007. ASSERT(pGetNlsSectionName != NULL);
  1008. if (rc = (*pGetNlsSectionName)( a->Locale,
  1009. 16,
  1010. 8,
  1011. NLS_SECTION_LANGPREFIX,
  1012. wszSecName,
  1013. MAX_SMALL_BUF_LEN))
  1014. {
  1015. return (rc);
  1016. }
  1017. RtlInitUnicodeString(&ObSecName, wszSecName);
  1018. }
  1019. (*pGetLinguistLangSize)(&Size);
  1020. break;
  1021. }
  1022. default:
  1023. return (STATUS_INVALID_PARAMETER);
  1024. }
  1025. if (pFile)
  1026. {
  1027. //
  1028. // Open the data file.
  1029. //
  1030. ASSERT(pOpenDataFile != NULL);
  1031. if (rc = (*pOpenDataFile)( &hFile,
  1032. pFile ))
  1033. {
  1034. return (rc);
  1035. }
  1036. }
  1037. //
  1038. // Create the NEW Section for Read and Write access.
  1039. // Add a ReadOnly security descriptor so that only the
  1040. // initial creating process may write to the section.
  1041. //
  1042. ASSERT(pCreateNlsSecurityDescriptor);
  1043. rc = (*pCreateNlsSecurityDescriptor)( (PSECURITY_DESCRIPTOR)pSecurityDescriptor,
  1044. MAX_SMALL_SECURITY_DESCRIPTOR,
  1045. GENERIC_READ);
  1046. if (!NT_SUCCESS(rc))
  1047. {
  1048. if (hFile)
  1049. NtClose(hFile);
  1050. return (rc);
  1051. }
  1052. InitializeObjectAttributes( &ObjA,
  1053. &ObSecName,
  1054. OBJ_PERMANENT | OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
  1055. NULL,
  1056. pSecurityDescriptor );
  1057. rc = NtCreateSection( &hNewSec,
  1058. hFile ? SECTION_MAP_READ : SECTION_MAP_READ | SECTION_MAP_WRITE,
  1059. &ObjA,
  1060. hFile? NULL:&Size,
  1061. hFile ? PAGE_READONLY:PAGE_READWRITE,
  1062. SEC_COMMIT,
  1063. hFile );
  1064. NtClose(hFile);
  1065. //
  1066. // Check for error from NtCreateSection.
  1067. //
  1068. if (!NT_SUCCESS(rc))
  1069. {
  1070. // KdPrint(("NLSAPI (BaseSrv): Could NOT Create Section %wZ - %lx.\n", &ObSecName, rc));
  1071. return (rc);
  1072. }
  1073. //
  1074. // Duplicate the new section handle for the client.
  1075. // The client will map a view of the section and fill in the data.
  1076. //
  1077. InitializeObjectAttributes( &ObjA,
  1078. NULL,
  1079. 0,
  1080. NULL,
  1081. NULL );
  1082. rc = NtOpenProcess( &hProcess,
  1083. PROCESS_DUP_HANDLE,
  1084. &ObjA,
  1085. &m->h.ClientId );
  1086. if (!NT_SUCCESS(rc))
  1087. {
  1088. KdPrint(("NLSAPI (BaseSrv): Could NOT Open Process - %lx.\n", rc));
  1089. NtClose(hNewSec);
  1090. return (rc);
  1091. }
  1092. rc = NtDuplicateObject( NtCurrentProcess(),
  1093. hNewSec,
  1094. hProcess,
  1095. &(a->hNewSection),
  1096. 0L,
  1097. 0L,
  1098. DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE );
  1099. //
  1100. // Close the process handle we opened.
  1101. //
  1102. NtClose(hProcess);
  1103. return (rc);
  1104. ReplyStatus; // get rid of unreferenced parameter warning message
  1105. }
  1106. ////////////////////////////////////////////////////////////////////////////
  1107. //
  1108. // GetThreadAuthenticationId
  1109. //
  1110. // Retreives the authentication id of the security context of the
  1111. // currently executing thread.
  1112. //
  1113. // 12-22-98 SamerA Created.
  1114. ////////////////////////////////////////////////////////////////////////////
  1115. NTSTATUS GetThreadAuthenticationId(
  1116. PLUID Luid)
  1117. {
  1118. HANDLE TokenHandle;
  1119. TOKEN_STATISTICS TokenInformation;
  1120. ULONG BytesRequired;
  1121. NTSTATUS NtStatus;
  1122. NtStatus = NtOpenThreadToken( NtCurrentThread(),
  1123. TOKEN_QUERY,
  1124. FALSE,
  1125. &TokenHandle );
  1126. if (!NT_SUCCESS(NtStatus))
  1127. {
  1128. KdPrint(("NLSAPI (BaseSrv) : No thread token in BaseSrvNlsLogon - %lx\n", NtStatus));
  1129. return (NtStatus);
  1130. }
  1131. //
  1132. // Get the LUID.
  1133. //
  1134. NtStatus = NtQueryInformationToken(
  1135. TokenHandle,
  1136. TokenStatistics,
  1137. &TokenInformation,
  1138. sizeof(TokenInformation),
  1139. &BytesRequired );
  1140. if (NT_SUCCESS( NtStatus ))
  1141. {
  1142. RtlCopyLuid(Luid, &TokenInformation.AuthenticationId);
  1143. }
  1144. else
  1145. {
  1146. KdPrint(("NLSAPI (BaseSrv) : Couldn't Query Information for Token %lx. NtStatus = %lx\n", TokenHandle, NtStatus));
  1147. }
  1148. NtClose(TokenHandle);
  1149. return (NtStatus);
  1150. }