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.

3004 lines
92 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. srvinit.c
  5. Abstract:
  6. This is the main initialization file for the Windows 32-bit Base API
  7. Server DLL.
  8. Author:
  9. Steve Wood (stevewo) 10-Oct-1990
  10. Revision History:
  11. --*/
  12. #include "basesrv.h"
  13. //
  14. // needed for definitions of structures when broadcasting a message to all
  15. // the windows that have the caller's LUID
  16. //
  17. #include <dbt.h>
  18. //
  19. // TS broadcast support
  20. //
  21. #include <winsta.h>
  22. #define NT_DRIVE_LETTER_PATH_LENGTH 8 // "\??\X:<NULL>" = 7 chars
  23. // Protection mode for named objects
  24. ULONG ProtectionMode = 0;
  25. UNICODE_STRING BaseSrvCSDString;
  26. ULONG BaseSrvCSDNumber;
  27. UNICODE_STRING BaseSrvKernel32DllPath;
  28. UNICODE_STRING BaseSrvSxsDllPath;
  29. UNICODE_STRING UnexpandedSystemRootString = RTL_CONSTANT_STRING(L"%SystemRoot%");
  30. RTL_QUERY_REGISTRY_TABLE BaseServerRegistryConfigurationTable[] = {
  31. {NULL, RTL_QUERY_REGISTRY_DIRECT,
  32. L"CSDVersion", &BaseSrvCSDString,
  33. REG_NONE, NULL, 0},
  34. {NULL, 0,
  35. NULL, NULL,
  36. REG_NONE, NULL, 0}
  37. };
  38. RTL_QUERY_REGISTRY_TABLE BaseServerRegistryConfigurationTable1[] = {
  39. {NULL, RTL_QUERY_REGISTRY_DIRECT,
  40. L"CSDVersion", &BaseSrvCSDNumber,
  41. REG_NONE, NULL, 0},
  42. {NULL, 0,
  43. NULL, NULL,
  44. REG_NONE, NULL, 0}
  45. };
  46. PCSR_API_ROUTINE BaseServerApiDispatchTable[ BasepMaxApiNumber+1 ] = {
  47. BaseSrvCreateProcess,
  48. BaseSrvCreateThread,
  49. BaseSrvGetTempFile,
  50. BaseSrvExitProcess,
  51. BaseSrvDebugProcess,
  52. BaseSrvCheckVDM,
  53. BaseSrvUpdateVDMEntry,
  54. BaseSrvGetNextVDMCommand,
  55. BaseSrvExitVDM,
  56. BaseSrvIsFirstVDM,
  57. BaseSrvGetVDMExitCode,
  58. BaseSrvSetReenterCount,
  59. BaseSrvSetProcessShutdownParam,
  60. BaseSrvGetProcessShutdownParam,
  61. BaseSrvNlsSetUserInfo,
  62. BaseSrvNlsSetMultipleUserInfo,
  63. BaseSrvNlsCreateSection,
  64. BaseSrvSetVDMCurDirs,
  65. BaseSrvGetVDMCurDirs,
  66. BaseSrvBatNotification,
  67. BaseSrvRegisterWowExec,
  68. BaseSrvSoundSentryNotification,
  69. BaseSrvRefreshIniFileMapping,
  70. BaseSrvDefineDosDevice,
  71. BaseSrvSetTermsrvAppInstallMode,
  72. BaseSrvNlsUpdateCacheCount,
  73. BaseSrvSetTermsrvClientTimeZone,
  74. BaseSrvSxsCreateActivationContext,
  75. BaseSrvDebugProcessStop,
  76. BaseSrvRegisterThread,
  77. BaseSrvNlsGetUserInfo, // BaseSrvNlsGetUserInfo
  78. NULL
  79. };
  80. BOOLEAN BaseServerApiServerValidTable[ BasepMaxApiNumber+1 ] = {
  81. TRUE, // SrvCreateProcess,
  82. TRUE, // SrvCreateThread,
  83. TRUE, // SrvGetTempFile,
  84. FALSE, // SrvExitProcess,
  85. FALSE, // SrvDebugProcess,
  86. TRUE, // SrvCheckVDM,
  87. TRUE, // SrvUpdateVDMEntry
  88. TRUE, // SrvGetNextVDMCommand
  89. TRUE, // SrvExitVDM
  90. TRUE, // SrvIsFirstVDM
  91. TRUE, // SrvGetVDMExitCode
  92. TRUE, // SrvSetReenterCount
  93. TRUE, // SrvSetProcessShutdownParam
  94. TRUE, // SrvGetProcessShutdownParam
  95. TRUE, // SrvNlsSetUserInfo
  96. TRUE, // SrvNlsSetMultipleUserInfo
  97. TRUE, // SrvNlsCreateSection
  98. TRUE, // SrvSetVDMCurDirs
  99. TRUE, // SrvGetVDMCurDirs
  100. TRUE, // SrvBatNotification
  101. TRUE, // SrvRegisterWowExec
  102. TRUE, // SrvSoundSentryNotification
  103. TRUE, // SrvRefreshIniFileMapping
  104. TRUE, // SrvDefineDosDevice
  105. TRUE, // SrvSetTermsrvAppInstallMode
  106. TRUE, // SrvNlsUpdateCacheCount,
  107. TRUE, // SrvSetTermsrvClientTimeZone
  108. TRUE, // SrvSxsCreateActivationContext
  109. TRUE, // SrvDebugProcessStop
  110. TRUE, // SrvRegisterThread,
  111. TRUE, // BaseSrvNlsGetUserInfo
  112. FALSE
  113. };
  114. #if DBG
  115. PSZ BaseServerApiNameTable[ BasepMaxApiNumber+1 ] = {
  116. "BaseCreateProcess",
  117. "BaseCreateThread",
  118. "BaseGetTempFile",
  119. "BaseExitProcess",
  120. "BaseDebugProcess",
  121. "BaseCheckVDM",
  122. "BaseUpdateVDMEntry",
  123. "BaseGetNextVDMCommand",
  124. "BaseExitVDM",
  125. "BaseIsFirstVDM",
  126. "BaseGetVDMExitCode",
  127. "BaseSetReenterCount",
  128. "BaseSetProcessShutdownParam",
  129. "BaseGetProcessShutdownParam",
  130. "BaseNlsSetUserInfo",
  131. "BaseNlsSetMultipleUserInfo",
  132. "BaseNlsCreateSection",
  133. "BaseSetVDMCurDirs",
  134. "BaseGetVDMCurDirs",
  135. "BaseBatNotification",
  136. "BaseRegisterWowExec",
  137. "BaseSoundSentryNotification",
  138. "BaseSrvRefreshIniFileMapping"
  139. "BaseDefineDosDevice",
  140. "BaseSrvSetTermsrvAppInstallMode",
  141. "BaseSrvNlsUpdateCacheCount",
  142. "BaseSrvSetTermsrvClientTimeZone",
  143. "BaseSrvSxsCreateActivationContext",
  144. "BaseSrvDebugProcessStop",
  145. "BaseRegisterThread",
  146. "BaseNlsGetUserInfo",
  147. NULL
  148. };
  149. #endif // DBG
  150. HANDLE BaseSrvNamedObjectDirectory;
  151. HANDLE BaseSrvRestrictedObjectDirectory;
  152. RTL_CRITICAL_SECTION BaseSrvDosDeviceCritSec;
  153. BOOLEAN BaseSrvFirstClient = TRUE;
  154. #if defined(_WIN64)
  155. SYSTEM_BASIC_INFORMATION SysInfo;
  156. #endif
  157. //
  158. // With LUID Device Maps,
  159. // Use BroadCastSystemMessageEx to broadcast the message to all the windows
  160. // with the LUID
  161. // Function pointer to BroadCastSystemMessageEx
  162. //
  163. long (WINAPI *PBROADCASTSYSTEMMESSAGEEXW)( DWORD, LPDWORD, UINT, WPARAM, LPARAM, PBSMINFO ) = NULL;
  164. //
  165. // Data structures and functions used for broadcast drive letter
  166. // change to application and the desktop with the caller's LUID
  167. //
  168. typedef struct _DDD_BSM_REQUEST *PDDD_BSM_REQUEST;
  169. typedef struct _DDD_BSM_REQUEST {
  170. PDDD_BSM_REQUEST pNextRequest;
  171. LUID Luid;
  172. DWORD iDrive;
  173. BOOLEAN DeleteRequest;
  174. } DDD_BSM_REQUEST, *PDDD_BSM_REQUEST;
  175. PDDD_BSM_REQUEST BSM_Request_Queue = NULL;
  176. PDDD_BSM_REQUEST BSM_Request_Queue_End = NULL;
  177. RTL_CRITICAL_SECTION BaseSrvDDDBSMCritSec;
  178. LONG BaseSrvpBSMThreadCount = 0;
  179. #define BaseSrvpBSMThreadMax 1
  180. #define PREALLOCATE_EVENT_MASK 0x80000000
  181. //
  182. // TS broadcast support
  183. //
  184. #define DEFAULT_BROADCAST_TIME_OUT 5
  185. typedef LONG (*FP_WINSTABROADCASTSYSTEMMESSAGE)(HANDLE hServer,
  186. BOOL sendToAllWinstations,
  187. ULONG sessionID,
  188. ULONG timeOut,
  189. DWORD dwFlags,
  190. DWORD *lpdwRecipients,
  191. ULONG uiMessage,
  192. WPARAM wParam,
  193. LPARAM lParam,
  194. LONG *pResponse);
  195. NTSTATUS
  196. SendWinStationBSM (
  197. DWORD dwFlags,
  198. LPDWORD lpdwRecipients,
  199. UINT uiMessage,
  200. WPARAM wParam,
  201. LPARAM lParam
  202. );
  203. //
  204. // END: TS broadcast support
  205. //
  206. NTSTATUS
  207. AddBSMRequest(
  208. IN DWORD iDrive,
  209. IN BOOLEAN DeleteRequest,
  210. IN PLUID pLuid
  211. );
  212. NTSTATUS
  213. CreateBSMThread();
  214. NTSTATUS
  215. BaseSrvBSMThread(
  216. PVOID pJunk
  217. );
  218. BOOLEAN
  219. CheckForGlobalSymLink (
  220. PUNICODE_STRING pDeviceName
  221. );
  222. //
  223. // END: broadcast drive letter change
  224. //
  225. WORD
  226. ConvertUnicodeToWord( PWSTR s );
  227. NTSTATUS
  228. CreateBaseAcls( PACL *Dacl, PACL *RestrictedDacl );
  229. NTSTATUS
  230. IsGlobalSymbolicLink(
  231. IN HANDLE hSymLink,
  232. OUT PBOOLEAN pbGlobalSymLink);
  233. NTSTATUS
  234. GetCallerLuid (
  235. OUT PLUID pLuid);
  236. NTSTATUS
  237. BroadcastDriveLetterChange(
  238. IN DWORD iDrive,
  239. IN BOOLEAN DeleteRequest,
  240. IN PLUID pLuid);
  241. WORD
  242. ConvertUnicodeToWord( PWSTR s )
  243. {
  244. NTSTATUS Status;
  245. ULONG Result;
  246. UNICODE_STRING UnicodeString;
  247. while (*s && *s <= L' ') {
  248. s += 1;
  249. }
  250. RtlInitUnicodeString( &UnicodeString, s );
  251. Status = RtlUnicodeStringToInteger( &UnicodeString,
  252. 10,
  253. &Result
  254. );
  255. if (!NT_SUCCESS( Status )) {
  256. Result = 0;
  257. }
  258. return (WORD)Result;
  259. }
  260. #if defined(WX86) || defined(_AXP64_)
  261. PKEY_VALUE_PARTIAL_INFORMATION
  262. Wx86QueryValueKey(
  263. HANDLE KeyHandle,
  264. PWCHAR ValueName
  265. )
  266. {
  267. NTSTATUS Status;
  268. ULONG ResultLength;
  269. UNICODE_STRING UnicodeString;
  270. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation, RetKeyValueInfo;
  271. BYTE ValueBuffer[MAX_PATH*sizeof(WCHAR) + sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
  272. KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
  273. RtlInitUnicodeString( &UnicodeString, ValueName);
  274. Status = NtQueryValueKey(KeyHandle,
  275. &UnicodeString,
  276. KeyValuePartialInformation,
  277. KeyValueInformation,
  278. sizeof( ValueBuffer ),
  279. &ResultLength
  280. );
  281. if (NT_SUCCESS(Status)) {
  282. RetKeyValueInfo = RtlAllocateHeap(RtlProcessHeap(), 0, ResultLength);
  283. if (RetKeyValueInfo) {
  284. RtlMoveMemory(RetKeyValueInfo,
  285. KeyValueInformation,
  286. ResultLength
  287. );
  288. }
  289. }
  290. else if (Status == STATUS_BUFFER_OVERFLOW) {
  291. RetKeyValueInfo = RtlAllocateHeap(RtlProcessHeap(), 0, ResultLength);
  292. if (RetKeyValueInfo) {
  293. Status = NtQueryValueKey(KeyHandle,
  294. &UnicodeString,
  295. KeyValuePartialInformation,
  296. RetKeyValueInfo,
  297. ResultLength,
  298. &ResultLength
  299. );
  300. if (!NT_SUCCESS(Status)) {
  301. RtlFreeHeap(RtlProcessHeap(), 0, RetKeyValueInfo);
  302. RetKeyValueInfo = NULL;
  303. }
  304. }
  305. }
  306. else {
  307. RetKeyValueInfo = NULL;
  308. }
  309. return RetKeyValueInfo;
  310. }
  311. /*
  312. * Initializes the volatile registry entries for Wx86.
  313. * \Registry\Machine\HARDWARE\DESCRIPTION\System\Wx86FloatingPointProcessor
  314. */
  315. void
  316. SetupWx86KeyMapping(void)
  317. {
  318. NTSTATUS Status;
  319. ULONG Processors, ProcessorCount;
  320. HANDLE KeyHandle, ParentKeyHandle;
  321. PKEY_VALUE_PARTIAL_INFORMATION Identifier;
  322. PKEY_VALUE_PARTIAL_INFORMATION ConfigurationData;
  323. PKEY_VALUE_PARTIAL_INFORMATION ComponentInformation;
  324. UNICODE_STRING UnicodeString;
  325. UNICODE_STRING ClassUnicode;
  326. OBJECT_ATTRIBUTES Obja;
  327. WCHAR wcProcessor[64];
  328. //
  329. // If the Wx86\\KeyRemapping\\FloatingPointProcessor does not exist
  330. // don't create the Wx86FloatingPointProcessor. So that x86 apps
  331. // will think there isn't any fpu.
  332. //
  333. RtlInitUnicodeString(&UnicodeString,
  334. L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Wx86\\KeyRemapping\\FloatingPointProcessor"
  335. );
  336. InitializeObjectAttributes(&Obja,
  337. &UnicodeString,
  338. OBJ_CASE_INSENSITIVE,
  339. NULL,
  340. NULL
  341. );
  342. Status = NtOpenKey(&KeyHandle, KEY_READ | KEY_WRITE, &Obja);
  343. if (!NT_SUCCESS(Status)) {
  344. return;
  345. }
  346. NtClose(KeyHandle);
  347. //
  348. // Create Wx86FloatingPointProcessor key
  349. //
  350. RtlInitUnicodeString(&ClassUnicode, L"Processor");
  351. RtlInitUnicodeString(
  352. &UnicodeString,
  353. L"\\Registry\\Machine\\Hardware\\Description\\System\\Wx86FloatingPointProcessor"
  354. );
  355. InitializeObjectAttributes(&Obja,
  356. &UnicodeString,
  357. OBJ_CASE_INSENSITIVE,
  358. NULL,
  359. NULL
  360. );
  361. Status = NtCreateKey(&ParentKeyHandle,
  362. KEY_READ | KEY_WRITE | KEY_CREATE_SUB_KEY,
  363. &Obja,
  364. 0, // TitleIndex ?
  365. &ClassUnicode,
  366. REG_OPTION_VOLATILE,
  367. NULL
  368. );
  369. if (!NT_SUCCESS(Status)) {
  370. return;
  371. }
  372. RtlInitUnicodeString(&UnicodeString,
  373. L"\\Registry\\Machine\\Hardware\\Description\\System\\CentralProcessor\\0"
  374. );
  375. InitializeObjectAttributes(&Obja,
  376. &UnicodeString,
  377. OBJ_CASE_INSENSITIVE,
  378. NULL,
  379. NULL
  380. );
  381. Status = NtOpenKey(&KeyHandle, KEY_READ, &Obja);
  382. if (!NT_SUCCESS(Status)) {
  383. NtClose(ParentKeyHandle);
  384. return;
  385. }
  386. Identifier = Wx86QueryValueKey(KeyHandle, L"Identifier");
  387. ConfigurationData = Wx86QueryValueKey(KeyHandle, L"Configuration Data");
  388. ComponentInformation = Wx86QueryValueKey(KeyHandle, L"Component Information");
  389. NtClose(KeyHandle);
  390. KeyHandle = NULL;
  391. #if defined(_WIN64)
  392. Processors = SysInfo.NumberOfProcessors;
  393. #else
  394. Processors = BaseSrvpStaticServerData->SysInfo.NumberOfProcessors;
  395. #endif
  396. ProcessorCount = 0;
  397. while (Processors--) {
  398. swprintf(wcProcessor, L"%d", ProcessorCount++);
  399. RtlInitUnicodeString(&UnicodeString, wcProcessor);
  400. InitializeObjectAttributes(&Obja,
  401. &UnicodeString,
  402. OBJ_CASE_INSENSITIVE,
  403. ParentKeyHandle,
  404. NULL
  405. );
  406. Status = NtCreateKey(&KeyHandle,
  407. KEY_READ | KEY_WRITE,
  408. &Obja,
  409. 0,
  410. NULL,
  411. REG_OPTION_VOLATILE,
  412. NULL
  413. );
  414. if (!NT_SUCCESS(Status)) {
  415. KeyHandle = NULL;
  416. goto SWMCleanup;
  417. }
  418. if (ComponentInformation) {
  419. RtlInitUnicodeString(&UnicodeString, L"Component Information");
  420. Status = NtSetValueKey(KeyHandle,
  421. &UnicodeString,
  422. 0,
  423. ComponentInformation->Type,
  424. ComponentInformation->Data,
  425. ComponentInformation->DataLength
  426. );
  427. if (!NT_SUCCESS(Status)) {
  428. goto SWMCleanup;
  429. }
  430. }
  431. if (ConfigurationData) {
  432. RtlInitUnicodeString(&UnicodeString, L"Configuration Data");
  433. Status = NtSetValueKey(KeyHandle,
  434. &UnicodeString,
  435. 0,
  436. ConfigurationData->Type,
  437. ConfigurationData->Data,
  438. ConfigurationData->DataLength
  439. );
  440. if (!NT_SUCCESS(Status)) {
  441. goto SWMCleanup;
  442. }
  443. }
  444. if (Identifier) {
  445. RtlInitUnicodeString(&UnicodeString, L"Identifier");
  446. Status = NtSetValueKey(KeyHandle,
  447. &UnicodeString,
  448. 0,
  449. Identifier->Type,
  450. Identifier->Data,
  451. Identifier->DataLength
  452. );
  453. if (!NT_SUCCESS(Status)) {
  454. goto SWMCleanup;
  455. }
  456. }
  457. NtClose(KeyHandle);
  458. KeyHandle = NULL;
  459. }
  460. SWMCleanup:
  461. if (ConfigurationData) {
  462. RtlFreeHeap( RtlProcessHeap(), 0, ConfigurationData);
  463. }
  464. if (ComponentInformation) {
  465. RtlFreeHeap( RtlProcessHeap(), 0, ComponentInformation);
  466. }
  467. if (Identifier) {
  468. RtlFreeHeap( RtlProcessHeap(), 0, Identifier);
  469. }
  470. if (ParentKeyHandle) {
  471. NtClose(ParentKeyHandle);
  472. }
  473. if (KeyHandle) {
  474. NtClose(KeyHandle);
  475. }
  476. return;
  477. }
  478. #endif
  479. NTSTATUS
  480. ServerDllInitialization(
  481. PCSR_SERVER_DLL LoadedServerDll
  482. )
  483. {
  484. NTSTATUS Status;
  485. UNICODE_STRING UnicodeString;
  486. OBJECT_ATTRIBUTES Obja;
  487. PSECURITY_DESCRIPTOR PrimarySecurityDescriptor;
  488. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
  489. ULONG ResultLength;
  490. PVOID p;
  491. WCHAR ValueBuffer[ 400 ];
  492. UNICODE_STRING NameString, ValueString;
  493. HANDLE KeyHandle;
  494. PWSTR s, s1;
  495. PACL Dacl, RestrictedDacl;
  496. WCHAR szObjectDirectory[MAX_SESSION_PATH];
  497. HANDLE SymbolicLinkHandle;
  498. UNICODE_STRING LinkTarget;
  499. ULONG attributes = OBJ_CASE_INSENSITIVE | OBJ_OPENIF;
  500. ULONG LUIDDeviceMapsEnabled;
  501. //
  502. // Id of the Terminal Server Session to which this CSRSS belongs.
  503. // SessionID == 0 is always console session (Standard NT).
  504. //
  505. SessionId = NtCurrentPeb()->SessionId;
  506. //
  507. // Object directories are only permanent for the console session
  508. //
  509. if (SessionId == 0) {
  510. attributes |= OBJ_PERMANENT;
  511. }
  512. BaseSrvHeap = RtlProcessHeap();
  513. BaseSrvTag = RtlCreateTagHeap( BaseSrvHeap,
  514. 0,
  515. L"BASESRV!",
  516. L"TMP\0"
  517. L"VDM\0"
  518. L"SXS\0"
  519. );
  520. BaseSrvSharedHeap = LoadedServerDll->SharedStaticServerData;
  521. BaseSrvSharedTag = RtlCreateTagHeap( BaseSrvSharedHeap,
  522. 0,
  523. L"BASESHR!",
  524. L"INIT\0"
  525. L"INI\0"
  526. );
  527. LoadedServerDll->ApiNumberBase = BASESRV_FIRST_API_NUMBER;
  528. LoadedServerDll->MaxApiNumber = BasepMaxApiNumber;
  529. LoadedServerDll->ApiDispatchTable = BaseServerApiDispatchTable;
  530. LoadedServerDll->ApiServerValidTable = BaseServerApiServerValidTable;
  531. #if DBG
  532. LoadedServerDll->ApiNameTable = BaseServerApiNameTable;
  533. #else
  534. LoadedServerDll->ApiNameTable = NULL;
  535. #endif
  536. LoadedServerDll->PerProcessDataLength = 0;
  537. LoadedServerDll->ConnectRoutine = BaseClientConnectRoutine;
  538. LoadedServerDll->DisconnectRoutine = BaseClientDisconnectRoutine;
  539. Status = RtlInitializeCriticalSection (&BaseSrvDosDeviceCritSec);
  540. if (!NT_SUCCESS (Status)) {
  541. return Status;
  542. }
  543. ValueString.Buffer = ValueBuffer;
  544. ValueString.MaximumLength = sizeof( ValueBuffer );
  545. Status = RtlExpandEnvironmentStrings_U( NULL,
  546. &UnexpandedSystemRootString,
  547. &ValueString,
  548. NULL
  549. );
  550. //
  551. // RtlCreateUnicodeString includes a terminal nul.
  552. // It makes a heap allocated copy.
  553. // These strings are never freed.
  554. //
  555. ASSERT( NT_SUCCESS( Status ) );
  556. ValueBuffer[ ValueString.Length / sizeof( WCHAR ) ] = UNICODE_NULL;
  557. if (!RtlCreateUnicodeString( &BaseSrvWindowsDirectory, ValueBuffer ))
  558. goto OutOfMemory;
  559. wcscat(ValueBuffer, L"\\System32" );
  560. if (!RtlCreateUnicodeString( &BaseSrvWindowsSystemDirectory, ValueBuffer ))
  561. goto OutOfMemory;
  562. wcscat(ValueBuffer, L"\\kernel32.dll" );
  563. if (!RtlCreateUnicodeString( &BaseSrvKernel32DllPath, ValueBuffer ))
  564. goto OutOfMemory;
  565. wcscpy(ValueBuffer, BaseSrvWindowsSystemDirectory.Buffer);
  566. wcscat(ValueBuffer, L"\\sxs.dll");
  567. if (!RtlCreateUnicodeString( &BaseSrvSxsDllPath, ValueBuffer ))
  568. goto OutOfMemory;
  569. #ifdef WX86
  570. wcscpy(ValueBuffer, BaseSrvWindowsDirectory.Buffer);
  571. wcscat(ValueBuffer, L"\\Sys32x86" );
  572. if (!RtlCreateUnicodeString( &BaseSrvWindowsSys32x86Directory, ValueBuffer))
  573. goto OutOfMemory;
  574. #endif
  575. //
  576. // need to synch this w/ user's desktop concept
  577. //
  578. if (SessionId == 0) {
  579. //
  580. // Console Session
  581. //
  582. wcscpy(szObjectDirectory,L"\\BaseNamedObjects" );
  583. } else {
  584. swprintf(szObjectDirectory,L"%ws\\%ld\\BaseNamedObjects",
  585. SESSION_ROOT,SessionId);
  586. }
  587. RtlInitUnicodeString(&UnicodeString,szObjectDirectory);
  588. //
  589. // initialize base static server data
  590. //
  591. BaseSrvpStaticServerData = RtlAllocateHeap( BaseSrvSharedHeap,
  592. MAKE_SHARED_TAG( INIT_TAG ),
  593. sizeof( BASE_STATIC_SERVER_DATA )
  594. );
  595. if ( !BaseSrvpStaticServerData ) {
  596. return STATUS_NO_MEMORY;
  597. }
  598. LoadedServerDll->SharedStaticServerData = (PVOID)BaseSrvpStaticServerData;
  599. BaseSrvpStaticServerData->TermsrvClientTimeZoneId=TIME_ZONE_ID_INVALID;
  600. Status = NtQuerySystemInformation(
  601. SystemTimeOfDayInformation,
  602. (PVOID)&BaseSrvpStaticServerData->TimeOfDay,
  603. sizeof(BaseSrvpStaticServerData->TimeOfDay),
  604. NULL
  605. );
  606. if ( !NT_SUCCESS( Status ) ) {
  607. return Status;
  608. }
  609. //
  610. // windows directory
  611. //
  612. BaseSrvpStaticServerData->WindowsDirectory = BaseSrvWindowsDirectory;
  613. p = RtlAllocateHeap( BaseSrvSharedHeap,
  614. MAKE_SHARED_TAG( INIT_TAG ),
  615. BaseSrvWindowsDirectory.MaximumLength
  616. );
  617. if ( !p ) {
  618. return STATUS_NO_MEMORY;
  619. }
  620. RtlMoveMemory(p,BaseSrvpStaticServerData->WindowsDirectory.Buffer,BaseSrvWindowsDirectory.MaximumLength);
  621. BaseSrvpStaticServerData->WindowsDirectory.Buffer = p;
  622. //
  623. // windows system directory
  624. //
  625. BaseSrvpStaticServerData->WindowsSystemDirectory = BaseSrvWindowsSystemDirectory;
  626. p = RtlAllocateHeap( BaseSrvSharedHeap,
  627. MAKE_SHARED_TAG( INIT_TAG ),
  628. BaseSrvWindowsSystemDirectory.MaximumLength
  629. );
  630. if ( !p ) {
  631. return STATUS_NO_MEMORY;
  632. }
  633. RtlMoveMemory(p,BaseSrvpStaticServerData->WindowsSystemDirectory.Buffer,BaseSrvWindowsSystemDirectory.MaximumLength);
  634. BaseSrvpStaticServerData->WindowsSystemDirectory.Buffer = p;
  635. #ifdef WX86
  636. //
  637. // wx86 system directory
  638. //
  639. BaseSrvpStaticServerData->WindowsSys32x86Directory = BaseSrvWindowsSys32x86Directory;
  640. p = RtlAllocateHeap( BaseSrvSharedHeap,
  641. MAKE_SHARED_TAG( INIT_TAG ),
  642. BaseSrvWindowsSys32x86Directory.MaximumLength
  643. );
  644. if ( !p ) {
  645. return STATUS_NO_MEMORY;
  646. }
  647. RtlMoveMemory(p,BaseSrvpStaticServerData->WindowsSys32x86Directory.Buffer,BaseSrvWindowsSys32x86Directory.MaximumLength);
  648. BaseSrvpStaticServerData->WindowsSys32x86Directory.Buffer = p;
  649. #else
  650. BaseSrvpStaticServerData->WindowsSys32x86Directory.Buffer = NULL;
  651. BaseSrvpStaticServerData->WindowsSys32x86Directory.Length = 0;
  652. BaseSrvpStaticServerData->WindowsSys32x86Directory.MaximumLength = 0;
  653. #endif
  654. //
  655. // named object directory
  656. //
  657. BaseSrvpStaticServerData->NamedObjectDirectory = UnicodeString;
  658. BaseSrvpStaticServerData->NamedObjectDirectory.MaximumLength = UnicodeString.Length+(USHORT)sizeof(UNICODE_NULL);
  659. p = RtlAllocateHeap( BaseSrvSharedHeap,
  660. MAKE_SHARED_TAG( INIT_TAG ),
  661. UnicodeString.Length + sizeof( UNICODE_NULL )
  662. );
  663. if ( !p ) {
  664. return STATUS_NO_MEMORY;
  665. }
  666. RtlMoveMemory(p,BaseSrvpStaticServerData->NamedObjectDirectory.Buffer,BaseSrvpStaticServerData->NamedObjectDirectory.MaximumLength);
  667. BaseSrvpStaticServerData->NamedObjectDirectory.Buffer = p;
  668. //
  669. // Terminal Server: App installation mode is intially turned off
  670. //
  671. BaseSrvpStaticServerData->fTermsrvAppInstallMode = FALSE;
  672. BaseSrvCSDString.Buffer = &ValueBuffer[ 300 ];
  673. BaseSrvCSDString.Length = 0;
  674. BaseSrvCSDString.MaximumLength = 100 * sizeof( WCHAR );
  675. Status = RtlQueryRegistryValues( RTL_REGISTRY_WINDOWS_NT,
  676. L"",
  677. BaseServerRegistryConfigurationTable1,
  678. NULL,
  679. NULL
  680. );
  681. if (NT_SUCCESS( Status )) {
  682. BaseSrvpStaticServerData->CSDNumber = (USHORT)(BaseSrvCSDNumber & 0xFFFF);
  683. BaseSrvpStaticServerData->RCNumber = (USHORT)(BaseSrvCSDNumber >> 16);
  684. }
  685. else {
  686. BaseSrvpStaticServerData->CSDNumber = 0;
  687. BaseSrvpStaticServerData->RCNumber = 0;
  688. }
  689. Status = RtlQueryRegistryValues( RTL_REGISTRY_WINDOWS_NT,
  690. L"",
  691. BaseServerRegistryConfigurationTable,
  692. NULL,
  693. NULL
  694. );
  695. if (NT_SUCCESS( Status )) {
  696. wcsncpy( BaseSrvpStaticServerData->CSDVersion,
  697. BaseSrvCSDString.Buffer,
  698. BaseSrvCSDString.Length
  699. );
  700. BaseSrvpStaticServerData->CSDVersion[ BaseSrvCSDString.Length ] = UNICODE_NULL;
  701. }
  702. else {
  703. BaseSrvpStaticServerData->CSDVersion[ 0 ] = UNICODE_NULL;
  704. }
  705. #if defined(_WIN64)
  706. Status = NtQuerySystemInformation( SystemBasicInformation,
  707. (PVOID)&SysInfo,
  708. sizeof(SYSTEM_BASIC_INFORMATION),
  709. NULL
  710. );
  711. #else
  712. Status = NtQuerySystemInformation( SystemBasicInformation,
  713. (PVOID)&BaseSrvpStaticServerData->SysInfo,
  714. sizeof( BaseSrvpStaticServerData->SysInfo ),
  715. NULL
  716. );
  717. #endif
  718. if (!NT_SUCCESS( Status )) {
  719. return( Status );
  720. }
  721. Status = BaseSrvInitializeIniFileMappings( BaseSrvpStaticServerData );
  722. if ( !NT_SUCCESS(Status) ){
  723. return Status;
  724. }
  725. BaseSrvpStaticServerData->DefaultSeparateVDM = FALSE;
  726. RtlInitUnicodeString( &NameString, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\WOW" );
  727. InitializeObjectAttributes( &Obja,
  728. &NameString,
  729. OBJ_CASE_INSENSITIVE,
  730. NULL,
  731. NULL );
  732. Status = NtOpenKey( &KeyHandle,
  733. KEY_READ,
  734. &Obja
  735. );
  736. if (NT_SUCCESS(Status)) {
  737. RtlInitUnicodeString( &NameString, L"DefaultSeparateVDM" );
  738. KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
  739. Status = NtQueryValueKey( KeyHandle,
  740. &NameString,
  741. KeyValuePartialInformation,
  742. KeyValueInformation,
  743. sizeof( ValueBuffer ),
  744. &ResultLength
  745. );
  746. if (NT_SUCCESS(Status)) {
  747. if (KeyValueInformation->Type == REG_DWORD) {
  748. BaseSrvpStaticServerData->DefaultSeparateVDM = *(PULONG)KeyValueInformation->Data != 0;
  749. }
  750. else
  751. if (KeyValueInformation->Type == REG_SZ) {
  752. if (!_wcsicmp( (PWSTR)KeyValueInformation->Data, L"yes" ) ||
  753. !_wcsicmp( (PWSTR)KeyValueInformation->Data, L"1" )) {
  754. BaseSrvpStaticServerData->DefaultSeparateVDM = TRUE;
  755. }
  756. }
  757. }
  758. NtClose( KeyHandle );
  759. }
  760. BaseSrvpStaticServerData->ForceDos = FALSE;
  761. RtlInitUnicodeString( &NameString, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\WOW" );
  762. InitializeObjectAttributes( &Obja,
  763. &NameString,
  764. OBJ_CASE_INSENSITIVE,
  765. NULL,
  766. NULL );
  767. Status = NtOpenKey( &KeyHandle,
  768. KEY_READ,
  769. &Obja
  770. );
  771. if (NT_SUCCESS(Status)) {
  772. RtlInitUnicodeString( &NameString, L"ForceDos" );
  773. KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
  774. Status = NtQueryValueKey( KeyHandle,
  775. &NameString,
  776. KeyValuePartialInformation,
  777. KeyValueInformation,
  778. sizeof( ValueBuffer ),
  779. &ResultLength
  780. );
  781. if (NT_SUCCESS(Status)) {
  782. if (KeyValueInformation->Type == REG_DWORD) {
  783. BaseSrvpStaticServerData->ForceDos = *(PULONG)KeyValueInformation->Data != 0;
  784. }
  785. else
  786. if (KeyValueInformation->Type == REG_SZ) {
  787. if (!_wcsicmp( (PWSTR)KeyValueInformation->Data, L"yes" ) ||
  788. !_wcsicmp( (PWSTR)KeyValueInformation->Data, L"1" )) {
  789. BaseSrvpStaticServerData->ForceDos = TRUE;
  790. }
  791. }
  792. }
  793. NtClose( KeyHandle );
  794. }
  795. #if defined(WX86) || defined(_AXP64_)
  796. SetupWx86KeyMapping();
  797. #endif
  798. //
  799. // Following code is direct from Jimk. Why is there a 1k constant
  800. //
  801. PrimarySecurityDescriptor = RtlAllocateHeap( BaseSrvHeap, MAKE_TAG( TMP_TAG ), 1024 );
  802. if ( !PrimarySecurityDescriptor ) {
  803. return STATUS_NO_MEMORY;
  804. }
  805. Status = RtlCreateSecurityDescriptor (
  806. PrimarySecurityDescriptor,
  807. SECURITY_DESCRIPTOR_REVISION1
  808. );
  809. if ( !NT_SUCCESS(Status) ){
  810. return Status;
  811. }
  812. //
  813. // Create an ACL that allows full access to System and partial access to world
  814. //
  815. Status = CreateBaseAcls( &Dacl, &RestrictedDacl );
  816. if ( !NT_SUCCESS(Status) ){
  817. return Status;
  818. }
  819. Status = RtlSetDaclSecurityDescriptor (
  820. PrimarySecurityDescriptor,
  821. TRUE, //DaclPresent,
  822. Dacl, //Dacl
  823. FALSE //DaclDefaulted OPTIONAL
  824. );
  825. if ( !NT_SUCCESS(Status) ){
  826. return Status;
  827. }
  828. InitializeObjectAttributes( &Obja,
  829. &UnicodeString,
  830. attributes,
  831. NULL,
  832. PrimarySecurityDescriptor
  833. );
  834. Status = NtCreateDirectoryObject( &BaseSrvNamedObjectDirectory,
  835. DIRECTORY_ALL_ACCESS,
  836. &Obja
  837. );
  838. if ( !NT_SUCCESS(Status) ){
  839. return Status;
  840. }
  841. //
  842. // Check if LUID device maps are enabled
  843. //
  844. Status = NtQueryInformationProcess( NtCurrentProcess(),
  845. ProcessLUIDDeviceMapsEnabled,
  846. &LUIDDeviceMapsEnabled,
  847. sizeof(LUIDDeviceMapsEnabled),
  848. NULL
  849. );
  850. if (NT_SUCCESS(Status)) {
  851. BaseSrvpStaticServerData->LUIDDeviceMapsEnabled = (LUIDDeviceMapsEnabled != 0);
  852. }
  853. else {
  854. BaseSrvpStaticServerData->LUIDDeviceMapsEnabled = FALSE;
  855. }
  856. //
  857. // If LUID device maps are enabled,
  858. // then initialize the critical section for broadcasting a system message
  859. // about a drive letter change
  860. //
  861. if( BaseSrvpStaticServerData->LUIDDeviceMapsEnabled == TRUE ) {
  862. Status = RtlInitializeCriticalSectionAndSpinCount( &BaseSrvDDDBSMCritSec,
  863. PREALLOCATE_EVENT_MASK );
  864. if (!NT_SUCCESS (Status)) {
  865. return Status;
  866. }
  867. }
  868. //
  869. // Create a symbolic link Global pointing to the Global BaseNamedObjects directory
  870. // This symbolic link will be used by proccesses that want to e.g. access a global
  871. // event instead of the session specific. This will be done by prepending
  872. // "Global\" to the object name.
  873. //
  874. RtlInitUnicodeString( &UnicodeString, GLOBAL_SYM_LINK );
  875. RtlInitUnicodeString( &LinkTarget, L"\\BaseNamedObjects" );
  876. InitializeObjectAttributes( &Obja,
  877. &UnicodeString,
  878. attributes,
  879. (HANDLE)BaseSrvNamedObjectDirectory,
  880. PrimarySecurityDescriptor );
  881. Status = NtCreateSymbolicLinkObject( &SymbolicLinkHandle,
  882. SYMBOLIC_LINK_ALL_ACCESS,
  883. &Obja,
  884. &LinkTarget );
  885. if (NT_SUCCESS( Status ) && (SessionId == 0)) {
  886. NtClose( SymbolicLinkHandle );
  887. }
  888. //
  889. // Create a symbolic link Local pointing to the Current Sessions BaseNamedObjects directory
  890. // This symbolic link will be used for backward compatibility with Hydra 4
  891. // naming conventions
  892. RtlInitUnicodeString( &UnicodeString, LOCAL_SYM_LINK );
  893. RtlInitUnicodeString( &LinkTarget, szObjectDirectory );
  894. InitializeObjectAttributes( &Obja,
  895. &UnicodeString,
  896. attributes,
  897. (HANDLE)BaseSrvNamedObjectDirectory,
  898. PrimarySecurityDescriptor );
  899. Status = NtCreateSymbolicLinkObject( &SymbolicLinkHandle,
  900. SYMBOLIC_LINK_ALL_ACCESS,
  901. &Obja,
  902. &LinkTarget );
  903. if (NT_SUCCESS( Status ) && (SessionId == 0)) {
  904. NtClose( SymbolicLinkHandle );
  905. }
  906. //
  907. // Create a symbolic link Session pointing
  908. // to the \Sessions\BNOLINKS directory
  909. // This symbolic link will be used by proccesses that want to e.g. access a
  910. // event in another session. This will be done by using the following
  911. // naming convention : Session\\<sessionid>\\ObjectName
  912. //
  913. RtlInitUnicodeString( &UnicodeString, SESSION_SYM_LINK );
  914. RtlInitUnicodeString( &LinkTarget, L"\\Sessions\\BNOLINKS" );
  915. InitializeObjectAttributes( &Obja,
  916. &UnicodeString,
  917. attributes,
  918. (HANDLE)BaseSrvNamedObjectDirectory,
  919. PrimarySecurityDescriptor );
  920. Status = NtCreateSymbolicLinkObject( &SymbolicLinkHandle,
  921. SYMBOLIC_LINK_ALL_ACCESS,
  922. &Obja,
  923. &LinkTarget );
  924. if (NT_SUCCESS( Status ) && (SessionId == 0)) {
  925. NtClose( SymbolicLinkHandle );
  926. }
  927. RtlInitUnicodeString( &UnicodeString, L"Restricted" );
  928. Status = RtlSetDaclSecurityDescriptor (
  929. PrimarySecurityDescriptor,
  930. TRUE, //DaclPresent,
  931. RestrictedDacl, //Dacl
  932. FALSE //DaclDefaulted OPTIONAL
  933. );
  934. if ( !NT_SUCCESS(Status) ){
  935. return Status;
  936. }
  937. InitializeObjectAttributes( &Obja,
  938. &UnicodeString,
  939. attributes,
  940. BaseSrvNamedObjectDirectory,
  941. PrimarySecurityDescriptor
  942. );
  943. Status = NtCreateDirectoryObject( &BaseSrvRestrictedObjectDirectory,
  944. DIRECTORY_ALL_ACCESS,
  945. &Obja
  946. );
  947. if ( !NT_SUCCESS(Status) ){
  948. return Status;
  949. }
  950. //
  951. // Initialize the Sxs support
  952. //
  953. Status = BaseSrvSxsInit(BaseSrvpStaticServerData);
  954. if (!NT_SUCCESS(Status)) {
  955. return Status;
  956. }
  957. RtlFreeHeap( BaseSrvHeap, 0, Dacl );
  958. RtlFreeHeap( BaseSrvHeap, 0, RestrictedDacl );
  959. RtlFreeHeap( BaseSrvHeap, 0,PrimarySecurityDescriptor );
  960. BaseSrvVDMInit();
  961. //
  962. // Initialize the shared heap for the NLS information.
  963. //
  964. BaseSrvNLSInit(BaseSrvpStaticServerData);
  965. Status = STATUS_SUCCESS;
  966. goto Exit;
  967. OutOfMemory:
  968. Status = STATUS_NO_MEMORY;
  969. goto Exit;
  970. Exit:
  971. return( Status );
  972. }
  973. NTSTATUS
  974. BaseClientConnectRoutine(
  975. IN PCSR_PROCESS Process,
  976. IN OUT PVOID ConnectionInfo,
  977. IN OUT PULONG ConnectionInfoLength
  978. )
  979. {
  980. if (*ConnectionInfoLength != sizeof(HANDLE)) {
  981. return STATUS_INVALID_PARAMETER;
  982. }
  983. return ( BaseSrvNlsConnect( Process,
  984. ConnectionInfo,
  985. ConnectionInfoLength ) );
  986. }
  987. VOID
  988. BaseClientDisconnectRoutine(
  989. IN PCSR_PROCESS Process
  990. )
  991. {
  992. BaseSrvCleanupVDMResources (Process);
  993. }
  994. ULONG
  995. BaseSrvDefineDosDevice(
  996. IN OUT PCSR_API_MSG m,
  997. IN OUT PCSR_REPLY_STATUS ReplyStatus
  998. )
  999. {
  1000. NTSTATUS Status;
  1001. PBASE_DEFINEDOSDEVICE_MSG a = (PBASE_DEFINEDOSDEVICE_MSG)&m->u.ApiMessageData;
  1002. UNICODE_STRING LinkName;
  1003. UNICODE_STRING LinkValue;
  1004. HANDLE LinkHandle;
  1005. OBJECT_ATTRIBUTES ObjectAttributes;
  1006. PWSTR Buffer, s, Src, Dst, pchValue;
  1007. ULONG cchBuffer, cch;
  1008. ULONG cchName, cchValue, cchSrc, cchSrcStr, cchDst;
  1009. BOOLEAN QueryNeeded, MatchFound, RevertToSelfNeeded, DeleteRequest;
  1010. ULONG ReturnedLength;
  1011. SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY;
  1012. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  1013. PSID RestrictedSid;
  1014. PSID WorldSid;
  1015. SECURITY_DESCRIPTOR SecurityDescriptor;
  1016. CHAR Acl[256]; // 256 is more than big enough
  1017. ULONG AclLength=256;
  1018. ACCESS_MASK WorldAccess;
  1019. ULONG lastIndex;
  1020. DWORD iDrive;
  1021. LUID callerLuid;
  1022. BOOLEAN bsmForLuid = FALSE;
  1023. BOOLEAN haveLuid = FALSE;
  1024. BOOLEAN bGlobalSymLink = FALSE;
  1025. if (!CsrValidateMessageBuffer(m, &a->DeviceName.Buffer, a->DeviceName.Length, sizeof(BYTE)) ||
  1026. (a->DeviceName.Length&(sizeof (WCHAR) - 1))) {
  1027. return STATUS_INVALID_PARAMETER;
  1028. }
  1029. if (a->TargetPath.Length == 0) {
  1030. cchBuffer = 0;
  1031. }
  1032. else {
  1033. cchBuffer = sizeof (WCHAR);
  1034. }
  1035. if (!CsrValidateMessageBuffer(m, &a->TargetPath.Buffer, (a->TargetPath.Length + cchBuffer), sizeof(BYTE)) ||
  1036. (a->TargetPath.Length&(sizeof (WCHAR) - 1))) {
  1037. return STATUS_INVALID_PARAMETER;
  1038. }
  1039. cchBuffer = 4096;
  1040. Buffer = RtlAllocateHeap( BaseSrvHeap,
  1041. MAKE_TAG( TMP_TAG ),
  1042. cchBuffer * sizeof( WCHAR )
  1043. );
  1044. if (Buffer == NULL) {
  1045. return (ULONG)STATUS_NO_MEMORY;
  1046. }
  1047. Status = RtlEnterCriticalSection( &BaseSrvDosDeviceCritSec );
  1048. if (!NT_SUCCESS( Status )) {
  1049. RtlFreeHeap( BaseSrvHeap, 0, Buffer );
  1050. return (ULONG)Status;
  1051. }
  1052. if (a->Flags & DDD_REMOVE_DEFINITION) {
  1053. DeleteRequest = TRUE;
  1054. }
  1055. else {
  1056. DeleteRequest = FALSE;
  1057. }
  1058. LinkHandle = NULL;
  1059. try {
  1060. //
  1061. // Determine if need to broadcast the change to the system, otherwise
  1062. // the client portion of DefineDosDevice will broadcast the change
  1063. // if needed.
  1064. //
  1065. // Broadcast to the system when all the conditions are met:
  1066. // - LUID device maps are enabled
  1067. // - Successfully completed operations of this BaseSrvDefineDosDevice
  1068. // - caller did not specify the DDD_NO_BROADCAST_SYSTEM flag
  1069. // - symbolic link's name is the "<drive letter>:" format
  1070. //
  1071. // Broadcasting this change from the server because
  1072. // we need to broadcast as Local_System in order to broadcast this
  1073. // message to all desktops that have windows with this LUID.
  1074. // Effectively, we are broadcasting to all the windows with this LUID.
  1075. //
  1076. if ((BaseSrvpStaticServerData->LUIDDeviceMapsEnabled == TRUE) &&
  1077. (!(a->Flags & DDD_NO_BROADCAST_SYSTEM)) &&
  1078. ((a->DeviceName).Buffer != NULL) &&
  1079. ((a->DeviceName).Length == (2 * sizeof( WCHAR ))) &&
  1080. ((a->DeviceName).Buffer[ 1 ] == L':')) {
  1081. WCHAR DriveLetter = a->DeviceName.Buffer[ 0 ];
  1082. if ( ((DriveLetter - L'a') < 26) &&
  1083. ((DriveLetter - L'a') >= 0) ) {
  1084. DriveLetter = RtlUpcaseUnicodeChar( DriveLetter );
  1085. }
  1086. iDrive = DriveLetter - L'A';
  1087. if (iDrive < 26) {
  1088. bsmForLuid = TRUE;
  1089. }
  1090. }
  1091. if ((a->Flags & DDD_LUID_BROADCAST_DRIVE) &&
  1092. (bsmForLuid == FALSE)) {
  1093. Status = STATUS_INVALID_PARAMETER;
  1094. leave;
  1095. }
  1096. //
  1097. // Each user LUID has a DeviceMap, so we put the link in that directory,
  1098. // instead of in the global \??.
  1099. //
  1100. // We get the LUID device map by impersonating the user
  1101. // and requesting \??\ in the beginning of the symbolic link name
  1102. // Then, the Object Manager will get the correct device map
  1103. // for this user (based on LUID)
  1104. //
  1105. s = Buffer;
  1106. cch = cchBuffer;
  1107. cchName = _snwprintf( s,
  1108. cch,
  1109. L"\\??\\%wZ",
  1110. &a->DeviceName
  1111. );
  1112. s += cchName + 1;
  1113. cch -= (cchName + 1);
  1114. RtlInitUnicodeString( &LinkName, Buffer );
  1115. InitializeObjectAttributes( &ObjectAttributes,
  1116. &LinkName,
  1117. OBJ_CASE_INSENSITIVE,
  1118. (HANDLE) NULL,
  1119. (PSECURITY_DESCRIPTOR)NULL
  1120. );
  1121. QueryNeeded = TRUE;
  1122. RevertToSelfNeeded = CsrImpersonateClient( NULL ); // This stacks client contexts
  1123. if( RevertToSelfNeeded == FALSE ) {
  1124. Status = STATUS_BAD_IMPERSONATION_LEVEL;
  1125. leave;
  1126. }
  1127. if (bsmForLuid == TRUE) {
  1128. Status = GetCallerLuid( &(callerLuid) );
  1129. if (NT_SUCCESS( Status )) {
  1130. //
  1131. // obtained the caller's LUID
  1132. //
  1133. haveLuid = TRUE;
  1134. }
  1135. }
  1136. Status = NtOpenSymbolicLinkObject( &LinkHandle,
  1137. SYMBOLIC_LINK_QUERY | DELETE,
  1138. &ObjectAttributes
  1139. );
  1140. if (RevertToSelfNeeded) {
  1141. CsrRevertToSelf(); // This unstacks client contexts
  1142. }
  1143. //
  1144. // With LUID device maps Enabled and DDD_LUID_BROADCAST_DRIVE,
  1145. // we capture all the information need to perform the broadcast:
  1146. // Drive Letter, action, and the caller's LUID.
  1147. // if the user had specified a delete action,
  1148. // then the drive letter should not exist (status ==
  1149. // STATUS_OBJECT_NAME_NOT_FOUND)
  1150. // else the drive letter should exist (status == STATUS_SUCCESS)
  1151. //
  1152. // if DDD_LUID_BROADCAST_DRIVE is set, we always leave this 'try'
  1153. // block because the 'finally' block will perform the broadcast
  1154. // when (Status == STATUS_SUCCESS).
  1155. //
  1156. if (a->Flags & DDD_LUID_BROADCAST_DRIVE) {
  1157. if (!NT_SUCCESS( Status )) {
  1158. LinkHandle = NULL;
  1159. }
  1160. if (DeleteRequest && (Status == STATUS_OBJECT_NAME_NOT_FOUND)) {
  1161. Status = STATUS_SUCCESS;
  1162. }
  1163. leave;
  1164. }
  1165. if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
  1166. LinkHandle = NULL;
  1167. if (DeleteRequest) {
  1168. if (a->TargetPath.Length == 0) {
  1169. Status = STATUS_SUCCESS;
  1170. }
  1171. leave;
  1172. }
  1173. QueryNeeded = FALSE;
  1174. Status = STATUS_SUCCESS;
  1175. }
  1176. else {
  1177. if (!NT_SUCCESS( Status )) {
  1178. LinkHandle = NULL;
  1179. leave;
  1180. }
  1181. else {
  1182. //
  1183. // Symbolic link already exists
  1184. //
  1185. // With device maps per LUID, we must determine that the
  1186. // symlink does not exist in the global device map because
  1187. // DefineDosDevice allow the caller to perform the
  1188. // mapping operations on a symlink (push/pop/delete)
  1189. // mapping for a particular symlink.
  1190. //
  1191. // The mapping capability is supported by writing
  1192. // all mappings (target(s) of a symlink) into the symlink's
  1193. // value, where the mappings names are separate by a NULL
  1194. // char. The symlink's list of mappings is terminated by
  1195. // two NULL characters.
  1196. //
  1197. // The first mapping, first target name in the symlink's
  1198. // value, is the current (top) mapping for the system because
  1199. // the system only reads the symlink's value up to the
  1200. // first NULL char.
  1201. //
  1202. // The mapping code works by opening the existing symlink,
  1203. // reading the symlink's entire value (name of the target(s)),
  1204. // destroy the old symlink, manipulate the symlink's value
  1205. // for the mapping operation, and finally create a
  1206. // brand-new symlink with the new symlink's value.
  1207. //
  1208. // If we don't check that the symlink exists in the global
  1209. // device map, we might delete a global symlink and
  1210. // and recreate the symlink in a user's LUID device map.
  1211. // Thus, the new symlink will no longer reside in the global
  1212. // map, i.e. other users cannot access the symlink.
  1213. //
  1214. if( BaseSrvpStaticServerData->LUIDDeviceMapsEnabled == TRUE ) {
  1215. Status = IsGlobalSymbolicLink( LinkHandle,
  1216. &bGlobalSymLink
  1217. );
  1218. if( !NT_SUCCESS( Status )) {
  1219. leave;
  1220. }
  1221. if( bGlobalSymLink == TRUE ) {
  1222. s = Buffer;
  1223. cch = cchBuffer;
  1224. cchName = _snwprintf( s,
  1225. cch,
  1226. L"\\GLOBAL??\\%wZ",
  1227. &a->DeviceName
  1228. );
  1229. s += cchName + 1;
  1230. cch -= (cchName + 1);
  1231. LinkName.Length = (USHORT)(cchName * sizeof( WCHAR ));
  1232. LinkName.MaximumLength = (USHORT)(LinkName.Length + sizeof(UNICODE_NULL));
  1233. }
  1234. }
  1235. }
  1236. }
  1237. if (a->TargetPath.Length != 0) {
  1238. Src = a->TargetPath.Buffer;
  1239. Src[a->TargetPath.Length/sizeof (Src[0])] = L'\0';
  1240. cchValue = wcslen( Src );
  1241. if ((cchValue + 1) >= cch) {
  1242. Status = STATUS_TOO_MANY_NAMES;
  1243. leave;
  1244. }
  1245. RtlMoveMemory( s, Src, (cchValue + 1) * sizeof( WCHAR ) );
  1246. pchValue = s;
  1247. s += cchValue + 1;
  1248. cch -= (cchValue + 1);
  1249. }
  1250. else {
  1251. pchValue = NULL;
  1252. cchValue = 0;
  1253. }
  1254. if (QueryNeeded) {
  1255. LinkValue.Length = 0;
  1256. LinkValue.MaximumLength = (USHORT)(cch * sizeof( WCHAR ));
  1257. LinkValue.Buffer = s;
  1258. ReturnedLength = 0;
  1259. Status = NtQuerySymbolicLinkObject( LinkHandle,
  1260. &LinkValue,
  1261. &ReturnedLength
  1262. );
  1263. if (ReturnedLength == (ULONG)LinkValue.MaximumLength) {
  1264. Status = STATUS_BUFFER_OVERFLOW;
  1265. }
  1266. if (!NT_SUCCESS( Status )) {
  1267. leave;
  1268. }
  1269. lastIndex = ReturnedLength / sizeof( WCHAR );
  1270. //
  1271. // check if the returned string already has the extra NULL at the end
  1272. //
  1273. if( (lastIndex >= 2) &&
  1274. (s[ lastIndex - 2 ] == UNICODE_NULL) &&
  1275. (s[ lastIndex - 1 ] == UNICODE_NULL) ) {
  1276. LinkValue.MaximumLength = (USHORT)ReturnedLength;
  1277. }
  1278. else {
  1279. //
  1280. // add the extra NULL for the DeleteRequest search later
  1281. //
  1282. s[ lastIndex ] = UNICODE_NULL;
  1283. LinkValue.MaximumLength = (USHORT)(ReturnedLength + sizeof( UNICODE_NULL ));
  1284. }
  1285. }
  1286. else {
  1287. if (DeleteRequest) {
  1288. RtlInitUnicodeString( &LinkValue, NULL );
  1289. }
  1290. else {
  1291. RtlInitUnicodeString( &LinkValue, s - (cchValue + 1) );
  1292. }
  1293. }
  1294. if (LinkHandle != NULL) {
  1295. Status = NtMakeTemporaryObject( LinkHandle );
  1296. NtClose( LinkHandle );
  1297. LinkHandle = NULL;
  1298. }
  1299. if (!NT_SUCCESS( Status )) {
  1300. leave;
  1301. }
  1302. if (DeleteRequest) {
  1303. Src = Dst = LinkValue.Buffer;
  1304. cchSrc = LinkValue.MaximumLength / sizeof( WCHAR );
  1305. cchDst = 0;
  1306. MatchFound = FALSE;
  1307. while (*Src) {
  1308. cchSrcStr = 0;
  1309. s = Src;
  1310. while (*Src++) {
  1311. cchSrcStr++;
  1312. }
  1313. if ( (!MatchFound) &&
  1314. ( (a->Flags & DDD_EXACT_MATCH_ON_REMOVE &&
  1315. cchValue == cchSrcStr &&
  1316. !_wcsicmp( s, pchValue )
  1317. ) ||
  1318. ( !(a->Flags & DDD_EXACT_MATCH_ON_REMOVE) &&
  1319. (cchValue == 0 || !_wcsnicmp( s, pchValue, cchValue ))
  1320. )
  1321. )
  1322. ) {
  1323. MatchFound = TRUE;
  1324. }
  1325. else {
  1326. if (s != Dst) {
  1327. RtlMoveMemory( Dst, s, (cchSrcStr + 1) * sizeof( WCHAR ) );
  1328. }
  1329. Dst += cchSrcStr + 1;
  1330. }
  1331. }
  1332. *Dst++ = UNICODE_NULL;
  1333. LinkValue.Length = wcslen( LinkValue.Buffer ) * sizeof( UNICODE_NULL );
  1334. if (LinkValue.Length != 0) {
  1335. LinkValue.MaximumLength = (USHORT)((PCHAR)Dst - (PCHAR)LinkValue.Buffer);
  1336. }
  1337. }
  1338. else
  1339. if (QueryNeeded) {
  1340. LinkValue.Buffer -= (cchValue + 1);
  1341. LinkValue.Length = (USHORT)(cchValue * sizeof( WCHAR ));
  1342. LinkValue.MaximumLength += LinkValue.Length + sizeof( UNICODE_NULL );
  1343. }
  1344. //
  1345. // Create a new value for the link.
  1346. //
  1347. if (LinkValue.Length != 0) {
  1348. //
  1349. // Create the new symbolic link object with a security descriptor
  1350. // that grants world SYMBOLIC_LINK_QUERY access.
  1351. //
  1352. Status = RtlAllocateAndInitializeSid( &WorldSidAuthority,
  1353. 1,
  1354. SECURITY_WORLD_RID,
  1355. 0, 0, 0, 0, 0, 0, 0,
  1356. &WorldSid
  1357. );
  1358. if (!NT_SUCCESS( Status )) {
  1359. leave;
  1360. }
  1361. Status = RtlAllocateAndInitializeSid( &NtAuthority,
  1362. 1,
  1363. SECURITY_RESTRICTED_CODE_RID,
  1364. 0, 0, 0, 0, 0, 0, 0,
  1365. &RestrictedSid
  1366. );
  1367. if (!NT_SUCCESS( Status )) {
  1368. RtlFreeSid( WorldSid );
  1369. leave;
  1370. }
  1371. Status = RtlCreateSecurityDescriptor( &SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION );
  1372. ASSERT(NT_SUCCESS(Status));
  1373. Status = RtlCreateAcl( (PACL)Acl,
  1374. AclLength,
  1375. ACL_REVISION2
  1376. );
  1377. ASSERT(NT_SUCCESS(Status));
  1378. if( (SessionId != 0) && (ProtectionMode & 0x00000003) ) {
  1379. // Do not allow world cross session delete in WTS
  1380. WorldAccess = SYMBOLIC_LINK_QUERY;
  1381. }
  1382. else {
  1383. WorldAccess = SYMBOLIC_LINK_QUERY | DELETE;
  1384. }
  1385. Status = RtlAddAccessAllowedAce( (PACL)Acl,
  1386. ACL_REVISION2,
  1387. WorldAccess,
  1388. WorldSid
  1389. );
  1390. ASSERT(NT_SUCCESS(Status));
  1391. Status = RtlAddAccessAllowedAce( (PACL)Acl,
  1392. ACL_REVISION2,
  1393. WorldAccess,
  1394. RestrictedSid
  1395. );
  1396. ASSERT(NT_SUCCESS(Status));
  1397. //
  1398. // Sids have been copied into the ACL
  1399. //
  1400. RtlFreeSid( WorldSid );
  1401. RtlFreeSid( RestrictedSid );
  1402. Status = RtlSetDaclSecurityDescriptor ( &SecurityDescriptor,
  1403. TRUE,
  1404. (PACL)Acl,
  1405. TRUE // Don't over-ride inherited protection
  1406. );
  1407. ASSERT(NT_SUCCESS(Status));
  1408. ObjectAttributes.SecurityDescriptor = &SecurityDescriptor;
  1409. //
  1410. // Since we impersonate the user to create in the
  1411. // correct directory, we cannot request the creation
  1412. // of a permanent object. By default, only Local_System
  1413. // can request creation of a permanant object.
  1414. //
  1415. // However, we use a new API, NtMakePermanentObject that
  1416. // only Local_System can call to make the object
  1417. // permanant after creation
  1418. //
  1419. if ( BaseSrvpStaticServerData->LUIDDeviceMapsEnabled == TRUE ) {
  1420. if ( bGlobalSymLink == FALSE ) {
  1421. //
  1422. // Do not impersonate if global symbolic link is being
  1423. // created, because administrators do not have permission
  1424. // to create in the global device map if we impersonate
  1425. //
  1426. // Administrators have inherited permissions on the
  1427. // existing global symbolic links, so we may recreate
  1428. // the existing global link that we opened and destroyed.
  1429. //
  1430. // We had impersonated the caller when opening the symbolic
  1431. // link, so we know that the caller has permissions for the
  1432. // link that we are creating.
  1433. //
  1434. //
  1435. // Impersonate Client when creating the Symbolic Link
  1436. // This impersonation is needed to ensure that the symlink
  1437. // is created in the correct directory
  1438. //
  1439. RevertToSelfNeeded = CsrImpersonateClient( NULL ); // This stacks client contexts
  1440. if( RevertToSelfNeeded == FALSE ) {
  1441. Status = STATUS_BAD_IMPERSONATION_LEVEL;
  1442. leave;
  1443. }
  1444. }
  1445. //
  1446. // if a global symlink is being create, don't impersonate &
  1447. // don't use the old style of using the OBJ_PERMANENT flag
  1448. // directly
  1449. //
  1450. }
  1451. else {
  1452. //
  1453. // Old style, disabled when separate dev maps are enabled
  1454. //
  1455. ObjectAttributes.Attributes |= OBJ_PERMANENT;
  1456. }
  1457. Status = NtCreateSymbolicLinkObject( &LinkHandle,
  1458. SYMBOLIC_LINK_ALL_ACCESS,
  1459. &ObjectAttributes,
  1460. &LinkValue
  1461. );
  1462. if ((BaseSrvpStaticServerData->LUIDDeviceMapsEnabled == TRUE) &&
  1463. (bGlobalSymLink == FALSE)) {
  1464. if (RevertToSelfNeeded) {
  1465. CsrRevertToSelf(); // This unstacks client contexts
  1466. }
  1467. }
  1468. if (NT_SUCCESS( Status )) {
  1469. if ( BaseSrvpStaticServerData->LUIDDeviceMapsEnabled == TRUE ) {
  1470. //
  1471. // add the OBJ_PERMANENT attribute to the object
  1472. // so that the object remains in the namespace
  1473. // of the system
  1474. //
  1475. Status = NtMakePermanentObject( LinkHandle );
  1476. }
  1477. NtClose( LinkHandle );
  1478. if (DeleteRequest && !MatchFound) {
  1479. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  1480. }
  1481. }
  1482. LinkHandle = NULL;
  1483. }
  1484. }
  1485. finally {
  1486. if (LinkHandle != NULL) {
  1487. NtClose( LinkHandle );
  1488. }
  1489. RtlFreeHeap( BaseSrvHeap, 0, Buffer );
  1490. //
  1491. // Determine if need to broadcast change to the system, otherwise
  1492. // the client portion of DefineDosDevice will broadcast the change
  1493. // if needed.
  1494. //
  1495. // Broadcast to the system when all the conditions are met:
  1496. // - LUID device maps are enabled
  1497. // - Successfully completed operations of this BaseSrvDefineDosDevice
  1498. // - caller did not specify the DDD_NO_BROADCAST_SYSTEM flag
  1499. // - symbolic link's name is the "<drive letter>:" format
  1500. //
  1501. // Can also broadcast when DDD_LUID_BROADCAST_DRIVE is set,
  1502. // and drive exists (when not a DeleteRequest) or
  1503. // drive does not exist (when a DeleteRequest)
  1504. //
  1505. // Broadcasting this change from the server because
  1506. // we need to broadcast as Local_System in order to broadcast this
  1507. // message to all desktops that have windows with this LUID.
  1508. // Effectively, we are broadcasting to all the windows with this LUID.
  1509. //
  1510. if ((bsmForLuid == TRUE) &&
  1511. (Status == STATUS_SUCCESS) &&
  1512. (haveLuid == TRUE)) {
  1513. LUID SystemLuid = SYSTEM_LUID;
  1514. if (bGlobalSymLink == TRUE) {
  1515. RtlCopyLuid( &callerLuid, &SystemLuid);
  1516. }
  1517. AddBSMRequest( iDrive,
  1518. DeleteRequest,
  1519. &callerLuid );
  1520. //
  1521. // If the user has removed a drive letter from his LUID DosDevices
  1522. // and now sees a global drive letter, then generate a broadcast
  1523. // about the arrival of the drive letter to the user's view.
  1524. //
  1525. if ((DeleteRequest == TRUE) &&
  1526. (!RtlEqualLuid( &callerLuid, &SystemLuid )) &&
  1527. CheckForGlobalSymLink( &(a->DeviceName) )) {
  1528. AddBSMRequest( iDrive,
  1529. FALSE,
  1530. &callerLuid );
  1531. }
  1532. }
  1533. RtlLeaveCriticalSection( &BaseSrvDosDeviceCritSec );
  1534. }
  1535. return (ULONG)Status;
  1536. ReplyStatus; // get rid of unreferenced parameter warning message
  1537. }
  1538. NTSTATUS
  1539. CreateBaseAcls(
  1540. PACL *Dacl,
  1541. PACL *RestrictedDacl
  1542. )
  1543. /*++
  1544. Routine Description:
  1545. Creates the ACL for the BaseNamedObjects directory.
  1546. Arguments:
  1547. Dacl - Supplies a pointer to a PDACL that will be filled in with
  1548. the resultant ACL (allocated out of the process heap). The caller
  1549. is responsible for freeing this memory.
  1550. Return Value:
  1551. STATUS_NO_MEMORY or Success
  1552. --*/
  1553. {
  1554. PSID LocalSystemSid;
  1555. PSID WorldSid;
  1556. PSID RestrictedSid;
  1557. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  1558. SID_IDENTIFIER_AUTHORITY WorldAuthority = SECURITY_WORLD_SID_AUTHORITY;
  1559. NTSTATUS Status;
  1560. ACCESS_MASK WorldAccess;
  1561. ACCESS_MASK SystemAccess;
  1562. ACCESS_MASK RestrictedAccess;
  1563. ULONG AclLength;
  1564. // Get the Protection mode from Session Manager\ProtectionMode
  1565. HANDLE KeyHandle;
  1566. ULONG ResultLength;
  1567. WCHAR ValueBuffer[ 32 ];
  1568. UNICODE_STRING NameString;
  1569. OBJECT_ATTRIBUTES ObjectAttributes;
  1570. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
  1571. RtlInitUnicodeString( &NameString, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager" );
  1572. InitializeObjectAttributes(
  1573. &ObjectAttributes,
  1574. &NameString,
  1575. OBJ_CASE_INSENSITIVE,
  1576. NULL,
  1577. NULL
  1578. );
  1579. Status = NtOpenKey(
  1580. &KeyHandle,
  1581. KEY_READ,
  1582. &ObjectAttributes
  1583. );
  1584. if (NT_SUCCESS(Status)) {
  1585. RtlInitUnicodeString( &NameString, L"ProtectionMode" );
  1586. KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
  1587. Status = NtQueryValueKey(
  1588. KeyHandle,
  1589. &NameString,
  1590. KeyValuePartialInformation,
  1591. KeyValueInformation,
  1592. sizeof( ValueBuffer ),
  1593. &ResultLength
  1594. );
  1595. if (NT_SUCCESS(Status)) {
  1596. if (KeyValueInformation->Type == REG_DWORD &&
  1597. *(PULONG)KeyValueInformation->Data) {
  1598. ProtectionMode = *(PULONG)KeyValueInformation->Data;
  1599. }
  1600. }
  1601. NtClose( KeyHandle );
  1602. }
  1603. Status = RtlAllocateAndInitializeSid(
  1604. &NtAuthority,
  1605. 1,
  1606. SECURITY_LOCAL_SYSTEM_RID,
  1607. 0, 0, 0, 0, 0, 0, 0,
  1608. &LocalSystemSid
  1609. );
  1610. if (!NT_SUCCESS( Status )) {
  1611. return( Status );
  1612. }
  1613. Status = RtlAllocateAndInitializeSid(
  1614. &WorldAuthority,
  1615. 1,
  1616. SECURITY_WORLD_RID,
  1617. 0, 0, 0, 0, 0, 0, 0,
  1618. &WorldSid
  1619. );
  1620. if (!NT_SUCCESS( Status )) {
  1621. return( Status );
  1622. }
  1623. Status = RtlAllocateAndInitializeSid(
  1624. &NtAuthority,
  1625. 1,
  1626. SECURITY_RESTRICTED_CODE_RID,
  1627. 0, 0, 0, 0, 0, 0, 0,
  1628. &RestrictedSid
  1629. );
  1630. if (!NT_SUCCESS( Status )) {
  1631. return( Status );
  1632. }
  1633. WorldAccess = DIRECTORY_ALL_ACCESS & ~(WRITE_OWNER | WRITE_DAC | DELETE );
  1634. RestrictedAccess = DIRECTORY_TRAVERSE;
  1635. SystemAccess = DIRECTORY_ALL_ACCESS;
  1636. AclLength = sizeof( ACL ) +
  1637. 3 * sizeof( ACCESS_ALLOWED_ACE ) +
  1638. RtlLengthSid( LocalSystemSid ) +
  1639. RtlLengthSid( RestrictedSid ) +
  1640. RtlLengthSid( WorldSid );
  1641. *Dacl = RtlAllocateHeap( BaseSrvHeap, MAKE_TAG( TMP_TAG ), AclLength );
  1642. if (*Dacl == NULL) {
  1643. return( STATUS_NO_MEMORY );
  1644. }
  1645. Status = RtlCreateAcl (*Dacl, AclLength, ACL_REVISION2 );
  1646. if (!NT_SUCCESS( Status )) {
  1647. return( Status );
  1648. }
  1649. Status = RtlAddAccessAllowedAce ( *Dacl, ACL_REVISION2, WorldAccess, WorldSid );
  1650. if (NT_SUCCESS( Status )) {
  1651. Status = RtlAddAccessAllowedAce ( *Dacl, ACL_REVISION2, SystemAccess, LocalSystemSid );
  1652. }
  1653. if (NT_SUCCESS( Status )) {
  1654. Status = RtlAddAccessAllowedAce ( *Dacl, ACL_REVISION2, RestrictedAccess, RestrictedSid );
  1655. }
  1656. // now create the DACL for restricted use
  1657. if( (SessionId != 0) && (ProtectionMode & 0x00000003) ) {
  1658. // Terminal server does not allow world create in other sessions
  1659. RestrictedAccess = DIRECTORY_ALL_ACCESS & ~(WRITE_OWNER | WRITE_DAC | DELETE | DIRECTORY_CREATE_OBJECT | DIRECTORY_CREATE_SUBDIRECTORY);
  1660. }
  1661. else {
  1662. RestrictedAccess = DIRECTORY_ALL_ACCESS & ~(WRITE_OWNER | WRITE_DAC | DELETE );
  1663. }
  1664. AclLength = sizeof( ACL ) +
  1665. 3 * sizeof( ACCESS_ALLOWED_ACE ) +
  1666. RtlLengthSid( LocalSystemSid ) +
  1667. RtlLengthSid( RestrictedSid ) +
  1668. RtlLengthSid( WorldSid );
  1669. *RestrictedDacl = RtlAllocateHeap( BaseSrvHeap, MAKE_TAG( TMP_TAG ), AclLength );
  1670. if (*RestrictedDacl == NULL) {
  1671. return( STATUS_NO_MEMORY );
  1672. }
  1673. Status = RtlCreateAcl (*RestrictedDacl, AclLength, ACL_REVISION2 );
  1674. if (!NT_SUCCESS( Status )) {
  1675. return( Status );
  1676. }
  1677. Status = RtlAddAccessAllowedAce ( *RestrictedDacl, ACL_REVISION2, WorldAccess, WorldSid );
  1678. if (NT_SUCCESS( Status )) {
  1679. Status = RtlAddAccessAllowedAce ( *RestrictedDacl, ACL_REVISION2, SystemAccess, LocalSystemSid );
  1680. }
  1681. if (NT_SUCCESS( Status )) {
  1682. Status = RtlAddAccessAllowedAce ( *RestrictedDacl, ACL_REVISION2, RestrictedAccess, RestrictedSid );
  1683. }
  1684. //
  1685. // These have been copied in, free them.
  1686. //
  1687. RtlFreeHeap( BaseSrvHeap, 0, LocalSystemSid );
  1688. RtlFreeHeap( BaseSrvHeap, 0, RestrictedSid );
  1689. RtlFreeHeap( BaseSrvHeap, 0, WorldSid );
  1690. return( Status );
  1691. }
  1692. ULONG
  1693. BaseSrvSetTermsrvClientTimeZone(
  1694. IN PCSR_API_MSG m,
  1695. IN OUT PCSR_REPLY_STATUS ReplyStatus
  1696. )
  1697. /*++
  1698. Routine Description:
  1699. Sets BaseSrvpStaticServerData->tziTermsrvClientTimeZone
  1700. according to received information
  1701. Arguments:
  1702. IN PCSR_API_MSG m - part of timezone information.
  1703. we have to cut it ito two pieces because of
  1704. message size restrictions (100 bytes).
  1705. IN OUT PCSR_REPLY_STATUS ReplyStatus - not used.
  1706. Return Value:
  1707. always STATUS_SUCCESS
  1708. --*/
  1709. {
  1710. PBASE_SET_TERMSRVCLIENTTIMEZONE b = (PBASE_SET_TERMSRVCLIENTTIMEZONE)&m->u.ApiMessageData;
  1711. if(b->fFirstChunk) {
  1712. BaseSrvpStaticServerData->tziTermsrvClientTimeZone.Bias=b->Bias;
  1713. RtlMoveMemory(&(BaseSrvpStaticServerData->tziTermsrvClientTimeZone.StandardName),
  1714. &(b->Name),sizeof(b->Name));
  1715. BaseSrvpStaticServerData->tziTermsrvClientTimeZone.StandardDate=b->Date;
  1716. BaseSrvpStaticServerData->tziTermsrvClientTimeZone.StandardBias=b->Bias1;
  1717. //only half of data received
  1718. //see comment below
  1719. BaseSrvpStaticServerData->TermsrvClientTimeZoneId=TIME_ZONE_ID_INVALID;
  1720. } else {
  1721. RtlMoveMemory(&(BaseSrvpStaticServerData->tziTermsrvClientTimeZone.DaylightName),
  1722. &b->Name,sizeof(b->Name));
  1723. BaseSrvpStaticServerData->tziTermsrvClientTimeZone.DaylightDate=b->Date;
  1724. BaseSrvpStaticServerData->tziTermsrvClientTimeZone.DaylightBias=b->Bias1;
  1725. BaseSrvpStaticServerData->ktTermsrvClientBias=b->RealBias;
  1726. //Set TimeZoneId only if last chunk of data received
  1727. //it indicates whether we have correct information in
  1728. //global data or not.
  1729. BaseSrvpStaticServerData->TermsrvClientTimeZoneId=b->TimeZoneId;
  1730. }
  1731. return( STATUS_SUCCESS );
  1732. }
  1733. NTSTATUS
  1734. IsGlobalSymbolicLink(
  1735. IN HANDLE hSymLink,
  1736. OUT PBOOLEAN pbGlobalSymLink)
  1737. /*++
  1738. Routine Description:
  1739. Check if the Symbolic Link exists in the global device map
  1740. Arguments:
  1741. hSymLink [IN] - handle to the symbolic link for verification
  1742. pbGlobalSymLink [OUT] - result of "Is symbolic link global?"
  1743. TRUE - symbolic link is global
  1744. FALSE - symbolic link is not global
  1745. Return Value:
  1746. NTSTATUS code
  1747. STATUS_SUCCESS - operations successful, did not encounter any errors,
  1748. the result in pbGlobalSymlink is only valid for this
  1749. status code
  1750. STATUS_INVALID_PARAMETER - pbGlobalSymLink or hSymLink is NULL
  1751. STATUS_NO_MEMORY - could not allocate memory to read the symbolic link's
  1752. name
  1753. STATUS_INFO_LENGTH_MISMATCH - did not allocate enough memory for the
  1754. symbolic link's name
  1755. STATUS_UNSUCCESSFUL - an unexpected error encountered
  1756. --*/
  1757. {
  1758. UNICODE_STRING ObjectName;
  1759. UNICODE_STRING GlobalDeviceMapPrefix;
  1760. PWSTR NameBuffer = NULL;
  1761. ULONG ReturnedLength;
  1762. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  1763. if( ( pbGlobalSymLink == NULL ) || ( hSymLink == NULL ) ) {
  1764. return( STATUS_INVALID_PARAMETER );
  1765. }
  1766. try {
  1767. ObjectName.Length = 0;
  1768. ObjectName.MaximumLength = 0;
  1769. ObjectName.Buffer = NULL;
  1770. ReturnedLength = 0;
  1771. //
  1772. // Determine the length of the symbolic link's name
  1773. //
  1774. Status = NtQueryObject( hSymLink,
  1775. ObjectNameInformation,
  1776. (PVOID) &ObjectName,
  1777. 0,
  1778. &ReturnedLength
  1779. );
  1780. if( !NT_SUCCESS( Status ) && (Status != STATUS_INFO_LENGTH_MISMATCH) ) {
  1781. leave;
  1782. }
  1783. //
  1784. // allocate memory for the symbolic link's name
  1785. //
  1786. NameBuffer = RtlAllocateHeap( BaseSrvHeap,
  1787. MAKE_TAG( TMP_TAG ),
  1788. ReturnedLength
  1789. );
  1790. if( NameBuffer == NULL ) {
  1791. Status = STATUS_NO_MEMORY;
  1792. leave;
  1793. }
  1794. //
  1795. // get the full name of the symbolic link
  1796. //
  1797. Status = NtQueryObject( hSymLink,
  1798. ObjectNameInformation,
  1799. NameBuffer,
  1800. ReturnedLength,
  1801. &ReturnedLength
  1802. );
  1803. if( !NT_SUCCESS( Status )) {
  1804. leave;
  1805. }
  1806. RtlInitUnicodeString ( &GlobalDeviceMapPrefix, L"\\GLOBAL??\\" );
  1807. //
  1808. // Check if the symlink exists in the global device map
  1809. //
  1810. *pbGlobalSymLink = RtlPrefixUnicodeString( &GlobalDeviceMapPrefix,
  1811. (PUNICODE_STRING)NameBuffer,
  1812. FALSE);
  1813. Status = STATUS_SUCCESS;
  1814. }
  1815. finally {
  1816. if( NameBuffer != NULL ) {
  1817. RtlFreeHeap( BaseSrvHeap, 0, NameBuffer );
  1818. NameBuffer = NULL;
  1819. }
  1820. }
  1821. return ( Status );
  1822. }
  1823. NTSTATUS
  1824. GetCallerLuid (
  1825. PLUID pLuid
  1826. )
  1827. /*++
  1828. Routine Description:
  1829. Retrieves the caller's LUID from the effective access_token
  1830. The effective access_token will be the thread's token if
  1831. impersonating, else the process' token
  1832. Arguments:
  1833. pLuid [IN] - pointer to a buffer to hold the LUID
  1834. Return Value:
  1835. STATUS_SUCCESS - operations successful, did not encounter any errors
  1836. STATUS_INVALID_PARAMETER - pLuid is NULL
  1837. STATUS_NO_TOKEN - could not find a token for the user
  1838. appropriate NTSTATUS code - an unexpected error encountered
  1839. --*/
  1840. {
  1841. TOKEN_STATISTICS TokenStats;
  1842. HANDLE hToken = NULL;
  1843. DWORD dwLength = 0;
  1844. NTSTATUS Status;
  1845. if( (pLuid == NULL) || (sizeof(*pLuid) != sizeof(LUID)) ) {
  1846. return( STATUS_INVALID_PARAMETER );
  1847. }
  1848. //
  1849. // Get the access token
  1850. // Try to get the impersonation token, else the primary token
  1851. //
  1852. Status = NtOpenThreadToken( NtCurrentThread(), TOKEN_READ, FALSE, &hToken );
  1853. if( Status == STATUS_NO_TOKEN ) {
  1854. Status = NtOpenProcessToken( NtCurrentProcess(), TOKEN_READ, &hToken );
  1855. }
  1856. if( NT_SUCCESS(Status) ) {
  1857. //
  1858. // Query the LUID for the user.
  1859. //
  1860. Status = NtQueryInformationToken( hToken,
  1861. TokenStatistics,
  1862. &TokenStats,
  1863. sizeof(TokenStats),
  1864. &dwLength );
  1865. if( NT_SUCCESS(Status) ) {
  1866. RtlCopyLuid( pLuid, &(TokenStats.AuthenticationId) );
  1867. }
  1868. }
  1869. if( hToken != NULL ) {
  1870. NtClose( hToken );
  1871. }
  1872. return( Status );
  1873. }
  1874. NTSTATUS
  1875. BroadcastDriveLetterChange(
  1876. IN DWORD iDrive,
  1877. IN BOOLEAN DeleteRequest,
  1878. IN PLUID pLuid
  1879. )
  1880. /*++
  1881. Routine Description:
  1882. broadcasting the drive letter change to all the windows with this LUID
  1883. Use BroadcastSystemMessageExW and the flags BSF_LUID & BSM_ALLDESKTOPS
  1884. to send the message
  1885. To broadcast with the BSM_ALLDESKTOPS flag, we need to call
  1886. BroadcastSystemMessageExW as Local_System. So this function should be
  1887. called as Local_System.
  1888. Arguments:
  1889. iDrive [IN] - drive letter that is changing, in the form of a number
  1890. relative to 'A', used to create a bit mask
  1891. DeleteRequest [IN] - denotes whether this change is a delete
  1892. TRUE - drive letter was deleted
  1893. FALSE - drive letter was added
  1894. pLuid [IN] - caller's LUID
  1895. Return Value:
  1896. STATUS_SUCCESS - operations successful, did not encounter any errors,
  1897. appropriate NTSTATUS code
  1898. --*/
  1899. {
  1900. BSMINFO bsmInfo;
  1901. DEV_BROADCAST_VOLUME dbv;
  1902. DWORD bsmFlags;
  1903. DWORD dwRec;
  1904. UNICODE_STRING DllName_U;
  1905. STRING bsmName;
  1906. HANDLE hUser32DllModule;
  1907. LUID SystemLuid = SYSTEM_LUID;
  1908. NTSTATUS Status = STATUS_SUCCESS;
  1909. if( pLuid == NULL ) {
  1910. return( STATUS_INVALID_PARAMETER );
  1911. }
  1912. bsmInfo.cbSize = sizeof(bsmInfo);
  1913. bsmInfo.hdesk = NULL;
  1914. bsmInfo.hwnd = NULL;
  1915. RtlCopyLuid(&(bsmInfo.luid), pLuid);
  1916. dbv.dbcv_size = sizeof( dbv );
  1917. dbv.dbcv_devicetype = DBT_DEVTYP_VOLUME;
  1918. dbv.dbcv_reserved = 0;
  1919. dbv.dbcv_unitmask = (1 << iDrive);
  1920. dbv.dbcv_flags = DBTF_NET;
  1921. bsmFlags = BSF_FORCEIFHUNG |
  1922. BSF_NOHANG |
  1923. BSF_NOTIMEOUTIFNOTHUNG;
  1924. //
  1925. // If the LUID is not Local_System, then broadcast only for the LUID
  1926. //
  1927. if (!RtlEqualLuid( &(bsmInfo.luid), &SystemLuid )) {
  1928. bsmFlags |= BSF_LUID;
  1929. }
  1930. dwRec = BSM_APPLICATIONS | BSM_ALLDESKTOPS;
  1931. hUser32DllModule = NULL;
  1932. if( PBROADCASTSYSTEMMESSAGEEXW == NULL ) {
  1933. RtlInitUnicodeString( &DllName_U, L"user32" );
  1934. Status = LdrGetDllHandle(
  1935. UNICODE_NULL,
  1936. NULL,
  1937. &DllName_U,
  1938. (PVOID *)&hUser32DllModule
  1939. );
  1940. if( hUser32DllModule != NULL && NT_SUCCESS( Status ) ) {
  1941. //
  1942. // get the address of the BroadcastSystemMessageExW function
  1943. //
  1944. RtlInitString( &bsmName, "CsrBroadcastSystemMessageExW" );
  1945. Status = LdrGetProcedureAddress(
  1946. hUser32DllModule,
  1947. &bsmName,
  1948. 0L,
  1949. (PVOID *)&PBROADCASTSYSTEMMESSAGEEXW
  1950. );
  1951. if( !NT_SUCCESS( Status ) ) {
  1952. PBROADCASTSYSTEMMESSAGEEXW = NULL;
  1953. }
  1954. }
  1955. }
  1956. if( PBROADCASTSYSTEMMESSAGEEXW != NULL ) {
  1957. //
  1958. // Since this thread is a csrss thread, the thread is not a
  1959. // GUI thread and does not have a desktop associated with it.
  1960. // Must set the thread's desktop to the active desktop in
  1961. // order to call BroadcastSystemMessageExW
  1962. //
  1963. Status = (PBROADCASTSYSTEMMESSAGEEXW)(
  1964. bsmFlags,
  1965. &dwRec,
  1966. WM_DEVICECHANGE,
  1967. (WPARAM)((DeleteRequest == TRUE) ?
  1968. DBT_DEVICEREMOVECOMPLETE :
  1969. DBT_DEVICEARRIVAL
  1970. ),
  1971. (LPARAM)(DEV_BROADCAST_HDR *)&dbv,
  1972. (PBSMINFO)&(bsmInfo)
  1973. );
  1974. }
  1975. //
  1976. // Send to all the TS CSRSS servers
  1977. //
  1978. if( !(bsmFlags & BSF_LUID) ) {
  1979. Status = SendWinStationBSM(
  1980. bsmFlags,
  1981. &dwRec,
  1982. WM_DEVICECHANGE,
  1983. (WPARAM)((DeleteRequest == TRUE) ?
  1984. DBT_DEVICEREMOVECOMPLETE :
  1985. DBT_DEVICEARRIVAL
  1986. ),
  1987. (LPARAM)(DEV_BROADCAST_HDR *)&dbv);
  1988. }
  1989. return( Status );
  1990. }
  1991. NTSTATUS
  1992. AddBSMRequest(
  1993. IN DWORD iDrive,
  1994. IN BOOLEAN DeleteRequest,
  1995. IN PLUID pLuid)
  1996. /*++
  1997. Routine Description:
  1998. Add a request for Broadcasting a System Message about a change with
  1999. a drive letter.
  2000. Must be running as Local_System and LUID device maps must be enabled.
  2001. Places the request item in the BSM_Request_Queue.
  2002. This mechanism allows the broadcast to occur asynchronously, otherwise
  2003. we encounter waiting issues with explorer.exe, in which the user sees
  2004. the shell hang for 20 seconds.
  2005. Arguments:
  2006. iDrive [IN] - drive letter that is changing, in the form of a number
  2007. relative to 'A', used to create a bit mask
  2008. DeleteRequest [IN] - denotes whether this change is a delete
  2009. TRUE - drive letter was deleted
  2010. FALSE - drive letter was added
  2011. pLuid [IN] - caller's LUID
  2012. Return Value:
  2013. STATUS_SUCCESS - operations successful, did not encounter any errors,
  2014. STATUS_INVALID_PARAMETER - pLuid is a null pointer
  2015. STATUS_ACCESS_DENIED - LUID device maps are disabled or the caller
  2016. is not running as Local_System
  2017. STATUS_NO_MEMORY - could not allocate memory for the DDD_BSM_REQUEST
  2018. data structure
  2019. appropriate NTSTATUS code
  2020. --*/
  2021. {
  2022. PDDD_BSM_REQUEST pRequest;
  2023. LUID CallerLuid;
  2024. LUID SystemLuid = SYSTEM_LUID;
  2025. BOOLEAN FirstRequest;
  2026. NTSTATUS Status;
  2027. if( pLuid == NULL ) {
  2028. return( STATUS_INVALID_PARAMETER );
  2029. }
  2030. //
  2031. // LUID device maps must be enabled
  2032. //
  2033. if( BaseSrvpStaticServerData->LUIDDeviceMapsEnabled == FALSE ) {
  2034. return( STATUS_ACCESS_DENIED );
  2035. }
  2036. Status = GetCallerLuid(&CallerLuid);
  2037. if( !NT_SUCCESS(Status) ) {
  2038. return Status;
  2039. }
  2040. //
  2041. // The caller must be Local_System
  2042. //
  2043. if( !RtlEqualLuid(&SystemLuid, &CallerLuid) ) {
  2044. return( STATUS_ACCESS_DENIED );
  2045. }
  2046. pRequest = RtlAllocateHeap( BaseSrvHeap,
  2047. MAKE_TAG( TMP_TAG ),
  2048. sizeof( DDD_BSM_REQUEST ));
  2049. if( pRequest == NULL ) {
  2050. return( STATUS_NO_MEMORY );
  2051. }
  2052. pRequest->iDrive = iDrive;
  2053. pRequest->DeleteRequest = DeleteRequest;
  2054. RtlCopyLuid( &(pRequest->Luid), pLuid );
  2055. pRequest->pNextRequest = NULL;
  2056. Status = RtlEnterCriticalSection( &BaseSrvDDDBSMCritSec );
  2057. if( !NT_SUCCESS(Status) ) {
  2058. RtlFreeHeap( BaseSrvHeap, 0, pRequest );
  2059. return( Status );
  2060. }
  2061. //
  2062. // Check if we are adding a request to an empty queue
  2063. //
  2064. FirstRequest = ( BSM_Request_Queue == NULL );
  2065. //
  2066. // add the work item to the end of the queue
  2067. //
  2068. if( BSM_Request_Queue_End != NULL ) {
  2069. BSM_Request_Queue_End->pNextRequest = pRequest;
  2070. }
  2071. else {
  2072. BSM_Request_Queue = pRequest;
  2073. }
  2074. BSM_Request_Queue_End = pRequest;
  2075. //
  2076. // if we added a request to an empty queue,
  2077. // then create a new thread to process the request
  2078. //
  2079. // BaseSrvDDDBSMCritSec guards BaseSrvpBSMThreadCount
  2080. //
  2081. if( (FirstRequest == TRUE) ||
  2082. (BaseSrvpBSMThreadCount < BaseSrvpBSMThreadMax) ) {
  2083. RtlLeaveCriticalSection( &BaseSrvDDDBSMCritSec );
  2084. Status = CreateBSMThread();
  2085. if( NT_SUCCESS(Status) ) {
  2086. Status = RtlEnterCriticalSection( &BaseSrvDDDBSMCritSec );
  2087. if( NT_SUCCESS(Status) ) {
  2088. BaseSrvpBSMThreadCount++;
  2089. RtlLeaveCriticalSection( &BaseSrvDDDBSMCritSec );
  2090. }
  2091. }
  2092. }
  2093. else {
  2094. RtlLeaveCriticalSection( &BaseSrvDDDBSMCritSec );
  2095. }
  2096. return( Status );
  2097. }
  2098. NTSTATUS
  2099. CreateBSMThread()
  2100. /*++
  2101. Routine Description:
  2102. Creates a dynamic csr thread
  2103. This thread will be use to asynchronously broadcast a drive letter
  2104. change message to the LUID's applications
  2105. The caller must be Local_System and LUID device maps must be
  2106. enabled.
  2107. Arguments:
  2108. None
  2109. Return Value:
  2110. STATUS_SUCCESS - operations successful, did not encounter any errors,
  2111. STATUS_ACCESS_DENIED - caller is not running as Local_System or
  2112. LUID device maps are not enabled
  2113. appropriate NTSTATUS code
  2114. --*/
  2115. {
  2116. HANDLE hThread = NULL;
  2117. NTSTATUS Status;
  2118. //
  2119. // Luid device maps must be enabled
  2120. //
  2121. if( BaseSrvpStaticServerData->LUIDDeviceMapsEnabled == FALSE ) {
  2122. return( STATUS_ACCESS_DENIED );
  2123. }
  2124. //
  2125. // Create a thread to asynchronously broadcast a drive letter change
  2126. //
  2127. Status = RtlCreateUserThread(
  2128. NtCurrentProcess(),
  2129. NULL,
  2130. FALSE, // create the new thread as ready
  2131. 0,
  2132. 0,
  2133. 0,
  2134. BaseSrvBSMThread,
  2135. NULL,
  2136. &hThread,
  2137. NULL
  2138. );
  2139. if( NT_SUCCESS(Status) && hThread ) {
  2140. NtClose(hThread);
  2141. }
  2142. return Status;
  2143. }
  2144. NTSTATUS
  2145. BaseSrvBSMThread(
  2146. PVOID pJunk
  2147. )
  2148. /*++
  2149. Routine Description:
  2150. Remove a work item from the BSM_Request_Queue and broadcast a message
  2151. about drive letter change.
  2152. The caller must be Local_System and LUID device maps must be
  2153. enabled.
  2154. Arguments:
  2155. pJunk - not used, RtlCreateUserThread needs a PVOID parameter
  2156. Return Value:
  2157. STATUS_SUCCESS - operations successful, did not encounter any errors,
  2158. STATUS_ACCESS_DENIED - caller is not running as Local_System or
  2159. LUID device maps are not enabled
  2160. appropriate NTSTATUS code
  2161. --*/
  2162. {
  2163. PDDD_BSM_REQUEST pRequest;
  2164. NTSTATUS Status, St;
  2165. DWORD Error;
  2166. UNREFERENCED_PARAMETER(pJunk);
  2167. //
  2168. // LUID device maps must be enabled
  2169. //
  2170. if( BaseSrvpStaticServerData->LUIDDeviceMapsEnabled == FALSE ) {
  2171. Status = STATUS_ACCESS_DENIED;
  2172. goto ExitCleanup;
  2173. }
  2174. //
  2175. // Enter the critical section that protects the BSM_Request_Queue
  2176. //
  2177. Status = RtlEnterCriticalSection( &BaseSrvDDDBSMCritSec );
  2178. if( !NT_SUCCESS(Status) ) {
  2179. goto ExitCleanup;
  2180. }
  2181. while( BSM_Request_Queue != NULL ) {
  2182. pRequest = BSM_Request_Queue;
  2183. if( pRequest != NULL ) {
  2184. //
  2185. // Remove the request from the front of BSM_Request_Queue
  2186. //
  2187. if( BSM_Request_Queue != NULL ) {
  2188. BSM_Request_Queue = BSM_Request_Queue->pNextRequest;
  2189. }
  2190. //
  2191. // if the queue is empty,
  2192. // then make sure that the queue's end pointer is NULL
  2193. //
  2194. if( BSM_Request_Queue == NULL ) {
  2195. BSM_Request_Queue_End = NULL;
  2196. }
  2197. RtlLeaveCriticalSection( &BaseSrvDDDBSMCritSec );
  2198. //
  2199. // Broadcasting can take a long time
  2200. // so broadcast outside of the critical section
  2201. //
  2202. Status = BroadcastDriveLetterChange( pRequest->iDrive,
  2203. pRequest->DeleteRequest,
  2204. &(pRequest->Luid) );
  2205. //
  2206. // free the work item's memory
  2207. //
  2208. pRequest->pNextRequest = NULL;
  2209. RtlFreeHeap( BaseSrvHeap, 0, pRequest );
  2210. //
  2211. // Enter the critical section that protects the BSM_Request_Queue
  2212. //
  2213. Status = RtlEnterCriticalSection( &BaseSrvDDDBSMCritSec );
  2214. if( !NT_SUCCESS(Status) ) {
  2215. goto ExitCleanup;
  2216. }
  2217. }
  2218. }
  2219. ExitCleanup:
  2220. St = Status;
  2221. if( !NT_SUCCESS(Status) ) {
  2222. St = RtlEnterCriticalSection( &BaseSrvDDDBSMCritSec );
  2223. }
  2224. if( BaseSrvpBSMThreadCount > 0 ) {
  2225. BaseSrvpBSMThreadCount--;
  2226. }
  2227. if( NT_SUCCESS(St) ) {
  2228. RtlLeaveCriticalSection( &BaseSrvDDDBSMCritSec );
  2229. }
  2230. //
  2231. // Since this thread was created with RtlCreateUserThread,
  2232. // we must clean up the thread manually
  2233. // Set the variable for User Stack cleanup and terminate the thread
  2234. // Note: This thread should not be holding a critical section when
  2235. // terminating the thread
  2236. //
  2237. NtCurrentTeb ()->FreeStackOnTermination = TRUE;
  2238. NtTerminateThread( NtCurrentThread(), Status );
  2239. return( Status );
  2240. }
  2241. BOOLEAN
  2242. CheckForGlobalSymLink (
  2243. PUNICODE_STRING pDeviceName
  2244. )
  2245. /*++
  2246. Routine Description:
  2247. Checks if the user sees a drive letter symbolic link that exists in the
  2248. global DosDevices
  2249. Arguments:
  2250. pDeviceName - contains the drive letter name in an UNICODE_STRING
  2251. Return Value:
  2252. TRUE - operations successful && the drive letter does exist in the
  2253. global DosDevices
  2254. FALSE - error encountered or drive letter does not exist in the
  2255. global DosDevices
  2256. --*/
  2257. {
  2258. WCHAR DeviceName[NT_DRIVE_LETTER_PATH_LENGTH];
  2259. UNICODE_STRING LinkName;
  2260. OBJECT_ATTRIBUTES ObjectAttributes;
  2261. HANDLE LinkHandle;
  2262. BOOLEAN RevertToSelfNeeded, bGlobalSymbolicLink;
  2263. NTSTATUS Status;
  2264. if ( pDeviceName == NULL ) {
  2265. return FALSE;
  2266. }
  2267. _snwprintf( DeviceName,
  2268. NT_DRIVE_LETTER_PATH_LENGTH,
  2269. L"\\??\\%wZ",
  2270. pDeviceName
  2271. );
  2272. RtlInitUnicodeString( &LinkName, DeviceName );
  2273. InitializeObjectAttributes( &ObjectAttributes,
  2274. &LinkName,
  2275. OBJ_CASE_INSENSITIVE,
  2276. (HANDLE) NULL,
  2277. (PSECURITY_DESCRIPTOR)NULL
  2278. );
  2279. //
  2280. // Impersonating the user to make sure that there is not a LUID DosDevices
  2281. // drive letter masking the global DosDevices drive letter
  2282. //
  2283. RevertToSelfNeeded = CsrImpersonateClient( NULL ); // This stacks client contexts
  2284. if( RevertToSelfNeeded == FALSE ) {
  2285. Status = STATUS_BAD_IMPERSONATION_LEVEL;
  2286. return FALSE;
  2287. }
  2288. Status = NtOpenSymbolicLinkObject( &LinkHandle,
  2289. SYMBOLIC_LINK_QUERY,
  2290. &ObjectAttributes
  2291. );
  2292. if (RevertToSelfNeeded) {
  2293. CsrRevertToSelf(); // This unstacks client contexts
  2294. }
  2295. if (!NT_SUCCESS(Status)) {
  2296. return FALSE;
  2297. }
  2298. Status = IsGlobalSymbolicLink( LinkHandle,
  2299. &bGlobalSymbolicLink
  2300. );
  2301. NtClose( LinkHandle );
  2302. if (!NT_SUCCESS(Status)) {
  2303. return FALSE;
  2304. }
  2305. return (bGlobalSymbolicLink);
  2306. }
  2307. NTSTATUS
  2308. SendWinStationBSM (
  2309. DWORD dwFlags,
  2310. LPDWORD lpdwRecipients,
  2311. UINT uiMessage,
  2312. WPARAM wParam,
  2313. LPARAM lParam
  2314. )
  2315. {
  2316. FP_WINSTABROADCASTSYSTEMMESSAGE fpWinStationBroadcastSystemMessage = NULL;
  2317. UNICODE_STRING DllName_U;
  2318. STRING bsmName;
  2319. HANDLE hWinStaDllModule = NULL;
  2320. LONG result = 0;
  2321. NTSTATUS Status;
  2322. //
  2323. // Load the base library that contains the user message dispatch routines
  2324. // for Terminal Services.
  2325. //
  2326. RtlInitUnicodeString( &DllName_U, L"WINSTA.DLL" );
  2327. Status = LdrLoadDll(
  2328. NULL,
  2329. NULL,
  2330. &DllName_U,
  2331. (PVOID *)&hWinStaDllModule
  2332. );
  2333. if(!NT_SUCCESS( Status )) {
  2334. return Status;
  2335. }
  2336. //
  2337. // get the address of the WinStationBroadcastSystemMessage function
  2338. //
  2339. RtlInitString( &bsmName, "WinStationBroadcastSystemMessage" );
  2340. Status = LdrGetProcedureAddress(
  2341. hWinStaDllModule,
  2342. &bsmName,
  2343. 0L,
  2344. (PVOID *)&fpWinStationBroadcastSystemMessage
  2345. );
  2346. if( !NT_SUCCESS( Status ) ) {
  2347. fpWinStationBroadcastSystemMessage = NULL;
  2348. }
  2349. if( fpWinStationBroadcastSystemMessage != NULL ) {
  2350. fpWinStationBroadcastSystemMessage(SERVERNAME_CURRENT,
  2351. TRUE,
  2352. 0,
  2353. DEFAULT_BROADCAST_TIME_OUT,
  2354. dwFlags,
  2355. lpdwRecipients,
  2356. uiMessage,
  2357. wParam,
  2358. lParam,
  2359. &result);
  2360. }
  2361. if(hWinStaDllModule != NULL) {
  2362. LdrUnloadDll(hWinStaDllModule);
  2363. hWinStaDllModule = NULL;
  2364. }
  2365. return( Status );
  2366. }
  2367. ULONG BaseSrvKernel32DelayLoadComplete = FALSE; // keep ULONG for atomicity
  2368. HANDLE BaseSrvKernel32DllHandle = NULL;
  2369. PGET_NLS_SECTION_NAME pGetNlsSectionName = NULL;
  2370. PGET_DEFAULT_SORTKEY_SIZE pGetDefaultSortkeySize = NULL;
  2371. PGET_LINGUIST_LANG_SIZE pGetLinguistLangSize = NULL;
  2372. PVALIDATE_LOCALE pValidateLocale = NULL;
  2373. PVALIDATE_LCTYPE pValidateLCType = NULL;
  2374. POPEN_DATA_FILE pOpenDataFile = NULL;
  2375. PNLS_CONVERT_INTEGER_TO_STRING pNlsConvertIntegerToString = NULL;
  2376. PGET_USER_DEFAULT_LANG_ID pGetUserDefaultLangID = NULL;
  2377. PGET_CP_FILE_NAME_FROM_REGISTRY pGetCPFileNameFromRegistry = NULL;
  2378. PCREATE_NLS_SECURITY_DESCRIPTOR pCreateNlsSecurityDescriptor = NULL;
  2379. const static struct KERNEL32_DELAY_LOAD_FUNCTION {
  2380. ANSI_STRING Name;
  2381. PVOID* Code;
  2382. } BaseSrvKernel32DelayLoadFunctions[] = {
  2383. { RTL_CONSTANT_STRING("OpenDataFile"), (PVOID*)(&pOpenDataFile) },
  2384. { RTL_CONSTANT_STRING("GetDefaultSortkeySize"), (PVOID*)(&pGetDefaultSortkeySize) },
  2385. { RTL_CONSTANT_STRING("GetLinguistLangSize"), (PVOID*)(&pGetLinguistLangSize) },
  2386. { RTL_CONSTANT_STRING("NlsConvertIntegerToString"), (PVOID*)(&pNlsConvertIntegerToString) },
  2387. { RTL_CONSTANT_STRING("ValidateLCType"), (PVOID*)(&pValidateLCType) },
  2388. { RTL_CONSTANT_STRING("ValidateLocale"), (PVOID*)(&pValidateLocale) },
  2389. { RTL_CONSTANT_STRING("GetNlsSectionName"), (PVOID*)(&pGetNlsSectionName) },
  2390. { RTL_CONSTANT_STRING("GetUserDefaultLangID"), (PVOID*)(&pGetUserDefaultLangID) },
  2391. { RTL_CONSTANT_STRING("GetCPFileNameFromRegistry"), (PVOID*)(&pGetCPFileNameFromRegistry) },
  2392. { RTL_CONSTANT_STRING("CreateNlsSecurityDescriptor"),(PVOID*)(&pCreateNlsSecurityDescriptor)}
  2393. };
  2394. NTSTATUS
  2395. BaseSrvDelayLoadKernel32(
  2396. VOID
  2397. )
  2398. {
  2399. NTSTATUS Status = STATUS_SUCCESS;
  2400. HANDLE LocalKernel32DllHandle = BaseSrvKernel32DllHandle;
  2401. int i = 0;
  2402. ASSERT(BaseSrvKernel32DllPath.Buffer != NULL && BaseSrvKernel32DllPath.Length != 0);
  2403. if (BaseSrvKernel32DelayLoadComplete)
  2404. return STATUS_SUCCESS;
  2405. //
  2406. // The structure here is somewhat inverted.
  2407. // Usually you load the library, then loop over functions.
  2408. // We loop over functions, only loading the library when we find a NULL one.
  2409. //
  2410. // I (a-JayK) don't remember why we do this, but it was deliberate.
  2411. //
  2412. for (i = 0 ; i != RTL_NUMBER_OF(BaseSrvKernel32DelayLoadFunctions) ; ++i) {
  2413. //
  2414. // Due to races, we cannot skip out of the loop upon finding any non NULLs.
  2415. //
  2416. if (*BaseSrvKernel32DelayLoadFunctions[i].Code == NULL) {
  2417. if (LocalKernel32DllHandle == NULL) {
  2418. //
  2419. // We depend on the loader lock for thread safety.
  2420. // In a race we might refcount kernel32.dll more than once.
  2421. // This is ok, because we do not ever unload kernel32.dll.
  2422. //
  2423. Status = LdrLoadDll(NULL, NULL, &BaseSrvKernel32DllPath, &BaseSrvKernel32DllHandle);
  2424. ASSERTMSG("Rerun with ShowSnaps to debug.", NT_SUCCESS(Status));
  2425. ASSERTMSG("Rerun with ShowSnaps to debug.", BaseSrvKernel32DllHandle != NULL);
  2426. if (!NT_SUCCESS(Status))
  2427. goto Exit;
  2428. LocalKernel32DllHandle = BaseSrvKernel32DllHandle;
  2429. }
  2430. Status =
  2431. LdrGetProcedureAddress(
  2432. BaseSrvKernel32DllHandle,
  2433. &BaseSrvKernel32DelayLoadFunctions[i].Name,
  2434. 0,
  2435. BaseSrvKernel32DelayLoadFunctions[i].Code
  2436. );
  2437. ASSERTMSG("Rerun with ShowSnaps to debug.", NT_SUCCESS(Status));
  2438. ASSERTMSG("Rerun with ShowSnaps to debug.", *BaseSrvKernel32DelayLoadFunctions[i].Code != NULL);
  2439. if (!NT_SUCCESS(Status))
  2440. goto Exit;
  2441. }
  2442. }
  2443. BaseSrvKernel32DelayLoadComplete = TRUE;
  2444. Exit:
  2445. return Status;
  2446. }