Leaked source code of windows server 2003
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.

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