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.

1451 lines
42 KiB

  1. /**************************************************************************\
  2. * Module Name: server.c
  3. *
  4. * Server support routines for the CSR stuff.
  5. *
  6. * Copyright (c) 1985 - 1999, Microsoft Corporation
  7. *
  8. * Created: 10-Dec-90
  9. *
  10. * History:
  11. * 10-Dec-90 created by sMeans
  12. *
  13. \**************************************************************************/
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. #include <dbt.h>
  17. #include <ntdddisk.h>
  18. #include "ntuser.h"
  19. #include <regstr.h>
  20. HANDLE hKeyPriority;
  21. UNICODE_STRING PriorityValueName;
  22. IO_STATUS_BLOCK IoStatusRegChange;
  23. ULONG RegChangeBuffer;
  24. HANDLE ghNlsEvent;
  25. BOOL gfLogon;
  26. HANDLE ghPowerRequestEvent;
  27. HANDLE ghMediaRequestEvent;
  28. #define ID_NLS 0
  29. #define ID_POWER 1
  30. #define ID_MEDIACHANGE 2
  31. #define ID_NETDEVCHANGE 3
  32. #define ID_NUM_EVENTS 4
  33. //
  34. // Name of event to pulse to request a device-arrival broadcast,
  35. //
  36. #define SC_BSM_EVENT_NAME L"ScNetDrvMsg"
  37. //
  38. // What the net drive bitmask was when we last broadcast (initially 0)
  39. //
  40. DWORD LastNetDrives;
  41. HANDLE CsrApiPort;
  42. HANDLE CsrQueryApiPort(VOID);
  43. ULONG
  44. SrvExitWindowsEx(
  45. IN OUT PCSR_API_MSG m,
  46. IN OUT PCSR_REPLY_STATUS ReplyStatus);
  47. ULONG
  48. SrvEndTask(
  49. IN OUT PCSR_API_MSG m,
  50. IN OUT PCSR_REPLY_STATUS ReplyStatus);
  51. ULONG
  52. SrvLogon(
  53. IN OUT PCSR_API_MSG m,
  54. IN OUT PCSR_REPLY_STATUS ReplyStatus);
  55. ULONG
  56. SrvRegisterServicesProcess(
  57. IN OUT PCSR_API_MSG m,
  58. IN OUT PCSR_REPLY_STATUS ReplyStatus);
  59. ULONG
  60. SrvActivateDebugger(
  61. IN OUT PCSR_API_MSG m,
  62. IN OUT PCSR_REPLY_STATUS ReplyStatus);
  63. ULONG
  64. SrvGetThreadConsoleDesktop(
  65. IN OUT PCSR_API_MSG m,
  66. IN OUT PCSR_REPLY_STATUS ReplyStatus);
  67. ULONG
  68. SrvDeviceEvent(
  69. IN OUT PCSR_API_MSG m,
  70. IN OUT PCSR_REPLY_STATUS ReplyStatus);
  71. ULONG
  72. SrvRegisterLogonProcess(
  73. IN OUT PCSR_API_MSG m,
  74. IN OUT PCSR_REPLY_STATUS ReplyStatus);
  75. #if DBG
  76. ULONG
  77. SrvWin32HeapFail(
  78. IN OUT PCSR_API_MSG m,
  79. IN OUT PCSR_REPLY_STATUS ReplyStatus);
  80. ULONG
  81. SrvWin32HeapStat(
  82. IN OUT PCSR_API_MSG m,
  83. IN OUT PCSR_REPLY_STATUS ReplyStatus);
  84. #endif
  85. ULONG SrvCreateSystemThreads(
  86. IN OUT PCSR_API_MSG m,
  87. IN OUT PCSR_REPLY_STATUS ReplyStatus);
  88. ULONG SrvRecordShutdownReason(
  89. IN OUT PCSR_API_MSG m,
  90. IN OUT PCSR_REPLY_STATUS ReplyStatus);
  91. CONST PCSR_API_ROUTINE UserServerApiDispatchTable[] = {
  92. SrvExitWindowsEx,
  93. SrvEndTask,
  94. SrvLogon,
  95. SrvRegisterServicesProcess,
  96. SrvActivateDebugger,
  97. SrvGetThreadConsoleDesktop,
  98. SrvDeviceEvent,
  99. SrvRegisterLogonProcess,
  100. SrvCreateSystemThreads,
  101. SrvRecordShutdownReason,
  102. #if DBG
  103. SrvWin32HeapFail,
  104. SrvWin32HeapStat,
  105. #endif
  106. };
  107. BOOLEAN UserServerApiServerValidTable[] = {
  108. FALSE, // ExitWindowsEx
  109. FALSE, // EndTask
  110. FALSE, // Logon
  111. FALSE, // RegisterServicesProcess
  112. FALSE, // ActivateDebugger
  113. TRUE, // GetThreadConsoleDesktop
  114. FALSE, // DeviceEvent
  115. FALSE, // RegisterLogonProcess
  116. FALSE, // CreateSystemThreads
  117. TRUE, // RecordShutdownReason
  118. #if DBG
  119. FALSE, // Win32HeapFail
  120. FALSE, // Win32HeapStat
  121. #endif
  122. };
  123. #if DBG
  124. CONST PSZ UserServerApiNameTable[] = {
  125. "SrvExitWindowsEx",
  126. "SrvEndTask",
  127. "SrvLogon",
  128. "SrvRegisterServicesProcess",
  129. "SrvActivateDebugger",
  130. "SrvGetThreadConsoleDesktop",
  131. "SrvDeviceEvent",
  132. "SrvRegisterLogonProcess",
  133. "SrvCreateSystemThreads",
  134. "SrvRecordShutdownReason"
  135. "SrvWin32HeapFail",
  136. "SrvWin32HeapStat",
  137. };
  138. #endif // DBG
  139. NTSTATUS UserServerDllInitialization(
  140. PCSR_SERVER_DLL psrvdll);
  141. NTSTATUS UserClientConnect(
  142. PCSR_PROCESS Process,
  143. PVOID ConnectionInformation,
  144. PULONG pulConnectionLen);
  145. VOID UserHardError(
  146. PCSR_THREAD pcsrt,
  147. PHARDERROR_MSG pmsg);
  148. NTSTATUS UserClientShutdown(
  149. PCSR_PROCESS Process,
  150. ULONG dwFlags,
  151. BOOLEAN fFirstPass);
  152. VOID StartRegReadRead(
  153. VOID);
  154. VOID RegReadApcProcedure(
  155. PVOID RegReadApcContext,
  156. PIO_STATUS_BLOCK IoStatus);
  157. NTSTATUS NotificationThread(
  158. PVOID);
  159. VOID InitializeConsoleAttributes(
  160. VOID);
  161. NTSTATUS GetThreadConsoleDesktop(
  162. DWORD dwThreadId,
  163. HDESK *phdesk);
  164. NTSTATUS MyRegOpenKey(IN HANDLE hKey, IN LPWSTR lpSubKey, OUT PHANDLE phResult);
  165. typedef BOOL (*PFNPROCESSCREATE)(DWORD, DWORD, ULONG_PTR, DWORD);
  166. BOOL BaseSetProcessCreateNotify(
  167. PFNPROCESSCREATE pfn);
  168. VOID BaseSrvNlsUpdateRegistryCache(
  169. PVOID ApcContext,
  170. PIO_STATUS_BLOCK pIoStatusBlock);
  171. NTSTATUS BaseSrvNlsLogon(
  172. BOOL fLogon);
  173. NTSTATUS WinStationAPIInit(
  174. VOID);
  175. /***************************************************************************\
  176. * UserServerDllInitialization
  177. *
  178. * Called by the CSR stuff to allow a server DLL to initialize itself and
  179. * provide information about the APIs it provides.
  180. *
  181. * Several operations are performed during this initialization:
  182. *
  183. * - The shared heap (client read-only) handle is initialized.
  184. * - The Raw Input Thread (RIT) is launched.
  185. * - GDI is initialized.
  186. *
  187. * History:
  188. * 10-19-92 DarrinM Integrated xxxUserServerDllInitialize into this rtn.
  189. * 11-08-91 patrickh move GDI init here from DLL init routine.
  190. * 12-10-90 sMeans Created.
  191. \***************************************************************************/
  192. NTSTATUS UserServerDllInitialization(
  193. PCSR_SERVER_DLL psrvdll)
  194. {
  195. CLIENT_ID ClientId;
  196. BOOL bAllocated;
  197. NTSTATUS Status;
  198. HANDLE hThreadNotification;
  199. if (RtlGetNtGlobalFlags() & FLG_SHOW_LDR_SNAPS) {
  200. RIPMSG0(RIP_WARNING,
  201. "UserServerDllInitialization: entered");
  202. }
  203. /*
  204. * Initialize a critical section structure that will be used to protect
  205. * all of the User Server's critical sections.
  206. */
  207. Status = RtlInitializeCriticalSection(&gcsUserSrv);
  208. if (!NT_SUCCESS(Status)) {
  209. RIPMSGF1(RIP_WARNING,
  210. "InitializeCriticalSection failed with Status 0x%x",
  211. Status);
  212. return Status;
  213. }
  214. EnterCrit();
  215. /*
  216. * Remember WINSRV.DLL's hmodule so we can grab resources from it later.
  217. */
  218. ghModuleWin = psrvdll->ModuleHandle;
  219. psrvdll->ApiNumberBase = USERSRV_FIRST_API_NUMBER;
  220. psrvdll->MaxApiNumber = UserpMaxApiNumber;
  221. psrvdll->ApiDispatchTable = UserServerApiDispatchTable;
  222. if (ISTS()) {
  223. UserServerApiServerValidTable[0] = TRUE; // for ExitWindowsEx
  224. }
  225. psrvdll->ApiServerValidTable = UserServerApiServerValidTable;
  226. #if DBG
  227. psrvdll->ApiNameTable = UserServerApiNameTable;
  228. #endif
  229. psrvdll->ConnectRoutine = UserClientConnect;
  230. psrvdll->HardErrorRoutine = UserHardError;
  231. psrvdll->ShutdownProcessRoutine = UserClientShutdown;
  232. /*
  233. * Create the events used by shutdown.
  234. */
  235. Status = NtCreateEvent(&gheventCancel, EVENT_ALL_ACCESS, NULL,
  236. NotificationEvent, FALSE);
  237. if (!NT_SUCCESS(Status)) {
  238. RIPMSG1(RIP_WARNING,
  239. "UserServerDllInitialization: NtCreateEvent failed with Status 0x%x",
  240. Status);
  241. goto ExitUserInit;
  242. }
  243. Status = NtCreateEvent(&gheventCancelled, EVENT_ALL_ACCESS, NULL,
  244. NotificationEvent, FALSE);
  245. if (!NT_SUCCESS(Status)) {
  246. RIPMSG1(RIP_WARNING,
  247. "UserServerDllInitialization: NtCreateEvent failed with Status 0x%x",
  248. Status);
  249. goto ExitUserInit;
  250. }
  251. /*
  252. * Create the event used by the power request code.
  253. */
  254. Status = NtCreateEvent(&ghPowerRequestEvent, EVENT_ALL_ACCESS, NULL,
  255. SynchronizationEvent, FALSE);
  256. if (!NT_SUCCESS(Status)) {
  257. RIPMSG1(RIP_WARNING,
  258. "UserServerDllInitialization: NtCreateEvent failed with Status 0x%x",
  259. Status);
  260. goto ExitUserInit;
  261. }
  262. /*
  263. * Create the event used by the media change code.
  264. */
  265. Status = NtCreateEvent(&ghMediaRequestEvent, EVENT_ALL_ACCESS, NULL,
  266. SynchronizationEvent, FALSE);
  267. if (!NT_SUCCESS(Status)) {
  268. RIPMSG1(RIP_WARNING,
  269. "UserServerDllInitialization: NtCreateEvent failed with Status 0x%x",
  270. Status);
  271. goto ExitUserInit;
  272. }
  273. /*
  274. * Create the event used by the nls code.
  275. */
  276. Status = NtCreateEvent(&ghNlsEvent,
  277. EVENT_ALL_ACCESS,
  278. NULL,
  279. SynchronizationEvent,
  280. FALSE);
  281. if (!NT_SUCCESS(Status)) {
  282. RIPMSG1(RIP_WARNING,
  283. "UserServerDllInitialization: NtCreateEvent failed with Status 0x%x",
  284. Status);
  285. goto ExitUserInit;
  286. }
  287. /*
  288. * Tell the base what user address to call when it is creating a process
  289. * (but before the process starts running).
  290. */
  291. BaseSetProcessCreateNotify(NtUserNotifyProcessCreate);
  292. /*
  293. * Load some strings.
  294. */
  295. gpwszaSUCCESS = (PWSTR)RtlLoadStringOrError(ghModuleWin,
  296. STR_SUCCESS, NULL, &bAllocated, FALSE);
  297. gpwszaSYSTEM_INFORMATION = (PWSTR)RtlLoadStringOrError(ghModuleWin,
  298. STR_SYSTEM_INFORMATION, NULL, &bAllocated, FALSE);
  299. gpwszaSYSTEM_WARNING = (PWSTR)RtlLoadStringOrError(ghModuleWin,
  300. STR_SYSTEM_WARNING, NULL, &bAllocated, FALSE);
  301. gpwszaSYSTEM_ERROR = (PWSTR)RtlLoadStringOrError(ghModuleWin,
  302. STR_SYSTEM_ERROR, NULL, &bAllocated, FALSE);
  303. /*
  304. * Initialize USER
  305. */
  306. Status = NtUserInitialize(USERCURRENTVERSION, ghPowerRequestEvent, ghMediaRequestEvent);
  307. if (!NT_SUCCESS(Status)) {
  308. RIPMSG1(RIP_WARNING,
  309. "NtUserInitialize failed with Status 0x%x",
  310. Status);
  311. goto ExitUserInit;
  312. }
  313. if (ISTS()) {
  314. Status = WinStationAPIInit();
  315. if (!NT_SUCCESS(Status)) {
  316. RIPMSG1(RIP_WARNING,
  317. "UserServerDllInitialization: WinStationAPIInit failed with Status 0x%x",
  318. Status);
  319. goto ExitUserInit;
  320. }
  321. }
  322. /*
  323. * Start registry notification thread
  324. */
  325. Status = RtlCreateUserThread(NtCurrentProcess(), NULL, FALSE, 0, 0, 0,
  326. NotificationThread, NULL, &hThreadNotification,
  327. &ClientId);
  328. if (NT_SUCCESS(Status)) {
  329. UserVerify(CsrAddStaticServerThread(hThreadNotification, &ClientId, 0));
  330. } else {
  331. RIPMSG1(RIP_WARNING,
  332. "UserServerDllInitialization: RtlCreateUserThread failed with Status 0x%x",
  333. Status);
  334. }
  335. ExitUserInit:
  336. LeaveCrit();
  337. return Status;
  338. }
  339. /**************************************************************************\
  340. * UserClientConnect
  341. *
  342. * This function is called once for each client process that connects to the
  343. * User server. When the client dynlinks to USER.DLL, USER.DLL's init code
  344. * is executed and calls CsrClientConnectToServer to establish the connection.
  345. * The server portion of ConnectToServer calls out this entrypoint.
  346. *
  347. * UserClientConnect first verifies version numbers to make sure the client
  348. * is compatible with this server and then completes all process-specific
  349. * initialization.
  350. *
  351. * History:
  352. * 02-??-91 SMeans Created.
  353. * 04-02-91 DarrinM Added User intialization code.
  354. \**************************************************************************/
  355. extern WORD gDispatchTableValues;
  356. NTSTATUS UserClientConnect(
  357. PCSR_PROCESS Process,
  358. PVOID ConnectionInformation,
  359. PULONG pulConnectionLen)
  360. {
  361. NTSTATUS Status;
  362. /*
  363. * Pass the api port to the kernel. Do this early so the kernel
  364. * can send a datagram to CSR to activate a debugger.
  365. */
  366. if (CsrApiPort == NULL) {
  367. CsrApiPort = CsrQueryApiPort();
  368. UserAssert(CsrApiPort != NULL);
  369. Status = NtUserSetInformationThread(
  370. NtCurrentThread(),
  371. UserThreadCsrApiPort,
  372. &CsrApiPort,
  373. sizeof(HANDLE));
  374. if (!NT_SUCCESS(Status)) {
  375. return Status;
  376. }
  377. }
  378. UserAssert(*pulConnectionLen == sizeof(USERCONNECT));
  379. if (*pulConnectionLen != sizeof(USERCONNECT)) {
  380. return STATUS_INVALID_PARAMETER;
  381. }
  382. ((PUSERCONNECT)ConnectionInformation)->dwDispatchCount = gDispatchTableValues;
  383. return NtUserProcessConnect(Process->ProcessHandle,
  384. (PUSERCONNECT)ConnectionInformation, *pulConnectionLen);
  385. }
  386. VOID RegReadApcProcedure(
  387. PVOID RegReadApcContext,
  388. PIO_STATUS_BLOCK IoStatus)
  389. {
  390. UNICODE_STRING ValueString;
  391. LONG Status;
  392. BYTE Buf[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD)];
  393. DWORD cbSize;
  394. ULONG l;
  395. UNREFERENCED_PARAMETER(RegReadApcContext);
  396. UNREFERENCED_PARAMETER(IoStatus);
  397. RtlInitUnicodeString(&ValueString, L"Win32PrioritySeparation");
  398. Status = NtQueryValueKey(hKeyPriority,
  399. &ValueString,
  400. KeyValuePartialInformation,
  401. (PKEY_VALUE_PARTIAL_INFORMATION)Buf,
  402. sizeof(Buf),
  403. &cbSize);
  404. if (NT_SUCCESS(Status)) {
  405. l = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)Buf)->Data);
  406. } else {
  407. l = PROCESS_PRIORITY_SEPARATION_MAX; // last resort default
  408. }
  409. NtSetSystemInformation(SystemPrioritySeperation,&l,sizeof(ULONG));
  410. NtNotifyChangeKey(hKeyPriority,
  411. NULL,
  412. (PIO_APC_ROUTINE)RegReadApcProcedure,
  413. NULL,
  414. &IoStatusRegChange,
  415. REG_NOTIFY_CHANGE_LAST_SET,
  416. FALSE,
  417. &RegChangeBuffer,
  418. sizeof(RegChangeBuffer),
  419. TRUE);
  420. }
  421. VOID StartRegReadRead(
  422. VOID)
  423. {
  424. UNICODE_STRING UnicodeString;
  425. OBJECT_ATTRIBUTES OA;
  426. RtlInitUnicodeString(&UnicodeString,
  427. L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\PriorityControl");
  428. InitializeObjectAttributes(&OA, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL);
  429. UserVerify(NT_SUCCESS(NtOpenKey(&hKeyPriority, KEY_READ | KEY_NOTIFY, &OA)));
  430. RegReadApcProcedure(NULL, NULL);
  431. }
  432. /***************************************************************************\
  433. * HandlePowerCallout
  434. *
  435. * This handles properly attaching to a desktop and calling into the kernel
  436. * to handle a power-related event.
  437. *
  438. * History:
  439. * 11/20/2001 JasonSch Created.
  440. \***************************************************************************/
  441. VOID HandlePowerCallout(
  442. VOID)
  443. {
  444. NTSTATUS Status;
  445. USERTHREAD_USEDESKTOPINFO utudi;
  446. /*
  447. * Attach to the desktop before calling into the kernel. This is
  448. * necessary because (at least) if a window gets destroyed when we
  449. * callback in xxxxSendBSMtoDesktop, we will call xxxRedrawWindow,
  450. * which requires the calling thread to be on a desktop if the PWND
  451. * passed in is NULL.
  452. */
  453. utudi.hThread = NULL;
  454. utudi.drdRestore.pdeskRestore = NULL;
  455. Status = NtUserSetInformationThread(NtCurrentThread(),
  456. UserThreadUseActiveDesktop,
  457. &utudi, sizeof(utudi));
  458. if (NT_SUCCESS(Status)) {
  459. NtUserCallNoParam(SFI_XXXUSERPOWERCALLOUTWORKER);
  460. /*
  461. * Now unattach from the desktop.
  462. */
  463. Status = NtUserSetInformationThread(NtCurrentThread(),
  464. UserThreadUseDesktop,
  465. &utudi,
  466. sizeof(utudi));
  467. UserAssert(NT_SUCCESS(Status));
  468. }
  469. }
  470. /***************************************************************************\
  471. * HandleMediaChangeEvent
  472. *
  473. * This routine is responsible for broadcasting the WM_DEVICECHANGE message
  474. * when media arrives or is removed from a CD-ROM device.
  475. *
  476. * History:
  477. * 23-Feb-96 BradG Modified to handle event per CD-ROM device
  478. * 23-April-96 Salimc Some CD-ROM drives notify us that media has
  479. * arrived before the drive has recognized that it had
  480. * new media. The call to DeviceIoctl() will fail in
  481. * this case. To fix this we made the following changes
  482. *
  483. * aDriveState is an array of tri-state global variable
  484. * for each drive.Each variable starts off in an UNKNOWN
  485. * state and on the first event with any drive we do the
  486. * full MAX_TRIES or less CHECK_VERIFY's which then gets
  487. * us into either a INSERTED or EJECTED state. From then
  488. * on we know that each new event is going to be the
  489. * opposite of what we currently have.
  490. *
  491. * UNKNOWN => do upto MAX_TRIES CHECK_VERIFY's with
  492. * delay to get into EJECTED or INSERTED state.
  493. *
  494. * INSERTED => do 1 CHECK_VERIFY to get into
  495. * EJECTED state
  496. *
  497. * EJECTED => do upto MAX_TRIES CHECK_VERIFY's with
  498. * delay to get into INSERTED state
  499. *
  500. \***************************************************************************/
  501. VOID HandleMediaChangeEvent(
  502. VOID)
  503. {
  504. /*
  505. * Local variables
  506. */
  507. DWORD dwRecipients;
  508. BOOL bResult;
  509. NTSTATUS Status;
  510. DEV_BROADCAST_VOLUME dbcvInfo;
  511. USERTHREAD_USEDESKTOPINFO utudi;
  512. ULONG cDrive;
  513. while (cDrive = (ULONG)NtUserCallNoParam(SFI_XXXGETDEVICECHANGEINFO)) {
  514. /*
  515. * Determine if it's an arrival or removal
  516. */
  517. bResult = (cDrive & HMCE_ARRIVAL);
  518. cDrive &= ~HMCE_ARRIVAL;
  519. /*
  520. * Initialize the structures used for BroadcastSystemMessage
  521. */
  522. dbcvInfo.dbcv_size = sizeof(dbcvInfo);
  523. dbcvInfo.dbcv_devicetype = DBT_DEVTYP_VOLUME;
  524. dbcvInfo.dbcv_reserved = 0;
  525. dbcvInfo.dbcv_flags = DBTF_MEDIA;
  526. dbcvInfo.dbcv_unitmask = cDrive;
  527. dwRecipients = BSM_ALLCOMPONENTS | BSM_ALLDESKTOPS;
  528. /*
  529. * Temporarily we must assign this thread to a desktop so we can
  530. * call USER's BroascastSystemMessage() routine. We call the
  531. * private SetThreadDesktopToDefault() to assign ourselves to the
  532. * desktop that is currently receiving input.
  533. */
  534. utudi.hThread = NULL;
  535. utudi.drdRestore.pdeskRestore = NULL;
  536. Status = NtUserSetInformationThread(NtCurrentThread(),
  537. UserThreadUseActiveDesktop,
  538. &utudi, sizeof(utudi));
  539. if (NT_SUCCESS(Status)) {
  540. /*
  541. * Broadcast the message
  542. */
  543. BroadcastSystemMessage(BSF_FORCEIFHUNG | ((bResult) ? BSF_ALLOWSFW : 0),
  544. &dwRecipients,
  545. WM_DEVICECHANGE,
  546. // HACK: need to or 0x8000 in wParam
  547. // because this is a flag to let
  548. // BSM know that lParam is a pointer
  549. // to a data structure.
  550. 0x8000 | ((bResult) ? DBT_DEVICEARRIVAL : DBT_DEVICEREMOVECOMPLETE),
  551. (LPARAM)&dbcvInfo);
  552. /*
  553. * Set our thread's desktop back to NULL. This will decrement
  554. * the desktop's reference count.
  555. */
  556. NtUserSetInformationThread(NtCurrentThread(),
  557. UserThreadUseDesktop,
  558. &utudi,
  559. sizeof(utudi));
  560. }
  561. }
  562. }
  563. DWORD
  564. GetNetworkDrives(
  565. )
  566. /*++
  567. Routine Description:
  568. Returns a drive bitmask similar to GetLogicalDrives, but including
  569. only the network drives.
  570. Arguments:
  571. Return Value:
  572. --*/
  573. {
  574. DWORD Mask = 0;
  575. DWORD DriveNumber;
  576. PROCESS_DEVICEMAP_INFORMATION ProcessDeviceMapInfo;
  577. if (NT_SUCCESS(NtQueryInformationProcess( NtCurrentProcess(),
  578. ProcessDeviceMap,
  579. &ProcessDeviceMapInfo.Query,
  580. sizeof( ProcessDeviceMapInfo.Query ),
  581. NULL
  582. ))) {
  583. // For all the drives from C to Z
  584. for (DriveNumber = 2; DriveNumber < 26; DriveNumber++)
  585. {
  586. if (ProcessDeviceMapInfo.Query.DriveType[DriveNumber] == DOSDEVICE_DRIVE_REMOTE)
  587. {
  588. Mask |= (1 << DriveNumber);
  589. }
  590. }
  591. }
  592. return Mask;
  593. }
  594. VOID
  595. HandleRemoteNetDeviceChangeEvent(
  596. )
  597. /*++
  598. Routine Description:
  599. Arguments:
  600. Return Value:
  601. --*/
  602. {
  603. DWORD NetDrives;
  604. DEV_BROADCAST_VOLUME dbv;
  605. LONG status;
  606. USERTHREAD_USEDESKTOPINFO utudi;
  607. /*
  608. * Temporarily we must assign this thread to a desktop so we can
  609. * call USER's BroascastSystemMessage() routine. We call the
  610. * private SetThreadDesktopToDefault() to assign ourselves to the
  611. * desktop that is currently receiving input.
  612. */
  613. utudi.hThread = NULL;
  614. utudi.drdRestore.pdeskRestore = NULL;
  615. status = NtUserSetInformationThread(NtCurrentThread(),
  616. UserThreadUseActiveDesktop,
  617. &utudi, sizeof(utudi));
  618. if (!NT_SUCCESS(status)) {
  619. return;
  620. }
  621. //
  622. // Keep broadcasting until the set of net drives stops changing
  623. //
  624. for (;;)
  625. {
  626. //
  627. // Get the current net drive bitmask and compare against the net
  628. // drive bitmask when we last broadcast
  629. //
  630. NetDrives = GetNetworkDrives();
  631. if (NetDrives == LastNetDrives)
  632. {
  633. break;
  634. }
  635. //
  636. // Broadcast about deleted volumes
  637. //
  638. dbv.dbcv_size = sizeof(dbv);
  639. dbv.dbcv_devicetype = DBT_DEVTYP_VOLUME;
  640. dbv.dbcv_reserved = 0;
  641. dbv.dbcv_unitmask = LastNetDrives & ~NetDrives;
  642. dbv.dbcv_flags = DBTF_NET;
  643. if (dbv.dbcv_unitmask != 0)
  644. {
  645. DWORD dwRec = BSM_APPLICATIONS | BSM_ALLDESKTOPS;
  646. status = BroadcastSystemMessage(
  647. BSF_FORCEIFHUNG | BSF_NOHANG | BSF_NOTIMEOUTIFNOTHUNG,
  648. &dwRec,
  649. WM_DEVICECHANGE,
  650. (WPARAM) DBT_DEVICEREMOVECOMPLETE,
  651. (LPARAM)(DEV_BROADCAST_HDR*)(&dbv)
  652. );
  653. }
  654. //
  655. // Broadcast about added volumes
  656. //
  657. dbv.dbcv_unitmask = NetDrives & ~LastNetDrives;
  658. if (dbv.dbcv_unitmask != 0)
  659. {
  660. DWORD dwRec = BSM_APPLICATIONS | BSM_ALLDESKTOPS;
  661. status = BroadcastSystemMessage(
  662. BSF_FORCEIFHUNG | BSF_NOHANG | BSF_NOTIMEOUTIFNOTHUNG,
  663. &dwRec,
  664. WM_DEVICECHANGE,
  665. (WPARAM) DBT_DEVICEARRIVAL,
  666. (LPARAM)(DEV_BROADCAST_HDR*)(&dbv)
  667. );
  668. }
  669. //
  670. // Remember the drive set that we last broadcast about
  671. //
  672. LastNetDrives = NetDrives;
  673. //
  674. // Go around the loop again to detect changes that may have occurred
  675. // while we were broadcasting
  676. //
  677. }
  678. /*
  679. * Set our thread's desktop back to NULL. This will decrement
  680. * the desktop's reference count.
  681. */
  682. NtUserSetInformationThread(NtCurrentThread(),
  683. UserThreadUseDesktop,
  684. &utudi,
  685. sizeof(utudi));
  686. return;
  687. }
  688. BOOL
  689. CreateBSMEventSD(
  690. PSECURITY_DESCRIPTOR * SecurityDescriptor
  691. )
  692. /*++
  693. Routine Description:
  694. This function creates a security descriptor for the BSM request event.
  695. It grants EVENT_ALL_ACCESS to local system and EVENT_MODIFY_STATE access
  696. to the rest of the world. This prevents principals other than local
  697. system from waiting for the event.
  698. Arguments:
  699. SecurityDescriptor - Receives a pointer to the new security descriptor.
  700. Should be freed with LocalFree.
  701. Return Value:
  702. TRUE - success
  703. FALSE - failure, use GetLastError
  704. --*/
  705. {
  706. NTSTATUS Status;
  707. ULONG AclLength;
  708. PACL EventDacl;
  709. PSID WorldSid = NULL;
  710. PSID SystemSid = NULL;
  711. SID_IDENTIFIER_AUTHORITY NtSidAuthority = SECURITY_NT_AUTHORITY;
  712. SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY;
  713. BOOL retval = TRUE;
  714. *SecurityDescriptor = NULL;
  715. Status = RtlAllocateAndInitializeSid( &NtSidAuthority,
  716. 1,
  717. SECURITY_LOCAL_SYSTEM_RID,
  718. 0, 0, 0, 0, 0, 0, 0,
  719. &SystemSid );
  720. if (!NT_SUCCESS(Status)) {
  721. retval = FALSE;
  722. goto Cleanup;
  723. }
  724. Status = RtlAllocateAndInitializeSid( &WorldSidAuthority,
  725. 1,
  726. SECURITY_WORLD_RID,
  727. 0, 0, 0, 0, 0, 0, 0,
  728. &WorldSid );
  729. if (!NT_SUCCESS(Status)) {
  730. retval = FALSE;
  731. goto Cleanup;
  732. }
  733. //
  734. // Allocate a buffer to contain the SD followed by the DACL
  735. // Note, the well-known SIDs are expected to have been created
  736. // by this time
  737. //
  738. AclLength = (ULONG)sizeof(ACL) +
  739. (2*((ULONG)sizeof(ACCESS_ALLOWED_ACE))) +
  740. RtlLengthSid( SystemSid ) +
  741. RtlLengthSid( WorldSid ) +
  742. 8; // 8 is for good measure
  743. *SecurityDescriptor = (PSECURITY_DESCRIPTOR)
  744. LocalAlloc( 0, SECURITY_DESCRIPTOR_MIN_LENGTH + AclLength );
  745. if (*SecurityDescriptor == NULL) {
  746. retval = FALSE;
  747. goto Cleanup;
  748. }
  749. EventDacl = (PACL) ((BYTE*)(*SecurityDescriptor) + SECURITY_DESCRIPTOR_MIN_LENGTH);
  750. //
  751. // Set up a default ACL
  752. //
  753. // Public: WORLD:EVENT_MODIFY_STATE, SYSTEM:all
  754. Status = RtlCreateAcl( EventDacl, AclLength, ACL_REVISION2);
  755. if (!NT_SUCCESS(Status)) {
  756. retval = FALSE;
  757. goto Cleanup;
  758. }
  759. //
  760. // WORLD access
  761. //
  762. Status = RtlAddAccessAllowedAce (
  763. EventDacl,
  764. ACL_REVISION2,
  765. EVENT_MODIFY_STATE,
  766. WorldSid
  767. );
  768. if (!NT_SUCCESS(Status)) {
  769. retval = FALSE;
  770. goto Cleanup;
  771. }
  772. //
  773. // SYSTEM access
  774. //
  775. Status = RtlAddAccessAllowedAce (
  776. EventDacl,
  777. ACL_REVISION2,
  778. EVENT_ALL_ACCESS,
  779. SystemSid
  780. );
  781. if (!NT_SUCCESS(Status)) {
  782. retval = FALSE;
  783. goto Cleanup;
  784. }
  785. //
  786. // Now initialize security descriptors
  787. // that export this protection
  788. //
  789. Status = RtlCreateSecurityDescriptor(
  790. *SecurityDescriptor,
  791. SECURITY_DESCRIPTOR_REVISION1
  792. );
  793. if (!NT_SUCCESS(Status)) {
  794. retval = FALSE;
  795. goto Cleanup;
  796. }
  797. Status = RtlSetDaclSecurityDescriptor(
  798. *SecurityDescriptor,
  799. TRUE, // DaclPresent
  800. EventDacl,
  801. FALSE // DaclDefaulted
  802. );
  803. if (!NT_SUCCESS(Status)) {
  804. retval = FALSE;
  805. goto Cleanup;
  806. }
  807. Cleanup:
  808. if (WorldSid) {
  809. RtlFreeSid(WorldSid);
  810. }
  811. if (SystemSid) {
  812. RtlFreeSid(SystemSid);
  813. }
  814. if ((retval == FALSE) && (*SecurityDescriptor != NULL)) {
  815. LocalFree(*SecurityDescriptor);
  816. *SecurityDescriptor = NULL;
  817. }
  818. return retval;
  819. }
  820. NTSTATUS NotificationThread(
  821. PVOID ThreadParameter)
  822. {
  823. KPRIORITY Priority;
  824. NTSTATUS Status;
  825. HANDLE hEvent[ID_NUM_EVENTS];
  826. WCHAR szObjectStr[MAX_SESSION_PATH];
  827. OBJECT_ATTRIBUTES Attributes;
  828. UNICODE_STRING UnicodeString;
  829. PSECURITY_DESCRIPTOR pSD = NULL;
  830. ULONG NumEvents = ID_NUM_EVENTS;
  831. UNREFERENCED_PARAMETER(ThreadParameter);
  832. Priority = LOW_PRIORITY + 3;
  833. Status = NtSetInformationThread(GetCurrentThread(),
  834. ThreadPriority,
  835. &Priority,
  836. sizeof(KPRIORITY));
  837. UserAssert(NT_SUCCESS(Status));
  838. UserAssert(ghNlsEvent && ghPowerRequestEvent && ghMediaRequestEvent);
  839. /*
  840. * Setup the NLS event.
  841. */
  842. hEvent[ID_NLS] = ghNlsEvent;
  843. /*
  844. * Setup the power request event.
  845. */
  846. hEvent[ID_POWER] = ghPowerRequestEvent;
  847. /*
  848. * Setup the MediaChangeEvent.
  849. */
  850. hEvent[ID_MEDIACHANGE] = ghMediaRequestEvent;
  851. /*
  852. * Setup the NetDeviceChange Event (only on remote sessions).
  853. */
  854. if (gSessionId != 0) {
  855. swprintf(szObjectStr,
  856. L"%ws\\%ld\\BaseNamedObjects\\%ws",
  857. SESSION_ROOT,
  858. gSessionId,
  859. SC_BSM_EVENT_NAME);
  860. RtlInitUnicodeString(&UnicodeString, szObjectStr);
  861. if (CreateBSMEventSD(&pSD)) {
  862. InitializeObjectAttributes(&Attributes,
  863. &UnicodeString,
  864. OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
  865. NULL,
  866. pSD);
  867. if (!NT_SUCCESS(NtCreateEvent(&hEvent[ID_NETDEVCHANGE], EVENT_ALL_ACCESS, &Attributes, SynchronizationEvent, FALSE))) {
  868. NumEvents--;
  869. }
  870. LocalFree(pSD);
  871. } else {
  872. NumEvents--;
  873. }
  874. } else {
  875. NumEvents--;
  876. }
  877. StartRegReadRead();
  878. /*
  879. * Sit and wait forever.
  880. */
  881. while (TRUE) {
  882. Status = NtWaitForMultipleObjects(NumEvents,
  883. hEvent,
  884. WaitAny,
  885. TRUE,
  886. NULL);
  887. if (Status == ID_NLS + WAIT_OBJECT_0) {
  888. /*
  889. * Handle the NLS event.
  890. */
  891. if (gfLogon) {
  892. gfLogon = FALSE;
  893. BaseSrvNlsUpdateRegistryCache(NULL, NULL);
  894. }
  895. } else if (Status == ID_POWER + WAIT_OBJECT_0) {
  896. /*
  897. * Handle the power request event.
  898. */
  899. HandlePowerCallout();
  900. } else if (Status == ID_MEDIACHANGE + WAIT_OBJECT_0) {
  901. /*
  902. * Handle the media change event.
  903. */
  904. HandleMediaChangeEvent();
  905. NtResetEvent(hEvent[ID_MEDIACHANGE], NULL);
  906. } else if (Status == ID_NETDEVCHANGE + WAIT_OBJECT_0) {
  907. /*
  908. * Handle the NetDevice change event for remote sessions.
  909. */
  910. HandleRemoteNetDeviceChangeEvent();
  911. }
  912. }
  913. UserExitWorkerThread(STATUS_SUCCESS);
  914. return STATUS_SUCCESS;
  915. }
  916. UINT GetRegIntFromID(
  917. HKEY hKey,
  918. int KeyID,
  919. UINT nDefault)
  920. {
  921. LPWSTR lpszValue;
  922. BOOL fAllocated;
  923. UNICODE_STRING Value;
  924. DWORD cbSize;
  925. BYTE Buf[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 20 * sizeof(WCHAR)];
  926. NTSTATUS Status;
  927. UINT ReturnValue;
  928. lpszValue = RtlLoadStringOrError(ghModuleWin,
  929. KeyID,
  930. NULL,
  931. &fAllocated,
  932. FALSE);
  933. RtlInitUnicodeString(&Value, lpszValue);
  934. Status = NtQueryValueKey(hKey,
  935. &Value,
  936. KeyValuePartialInformation,
  937. (PKEY_VALUE_PARTIAL_INFORMATION)Buf,
  938. sizeof(Buf),
  939. &cbSize);
  940. if (NT_SUCCESS(Status)) {
  941. /*
  942. * Convert string to int.
  943. */
  944. RtlInitUnicodeString(&Value, (LPWSTR)((PKEY_VALUE_PARTIAL_INFORMATION)Buf)->Data);
  945. RtlUnicodeStringToInteger(&Value, 10, &ReturnValue);
  946. } else {
  947. ReturnValue = nDefault;
  948. }
  949. LocalFree(lpszValue);
  950. return ReturnValue;
  951. }
  952. VOID GetTimeouts(
  953. VOID)
  954. {
  955. HANDLE hCurrentUserKey;
  956. HANDLE hKey;
  957. NTSTATUS Status;
  958. Status = RtlOpenCurrentUser(MAXIMUM_ALLOWED, &hCurrentUserKey);
  959. if (NT_SUCCESS(Status)) {
  960. Status = MyRegOpenKey(hCurrentUserKey,
  961. L"Control Panel\\Desktop",
  962. &hKey);
  963. if (NT_SUCCESS(Status)) {
  964. gCmsHungAppTimeout = GetRegIntFromID(
  965. hKey,
  966. STR_CMSHUNGAPPTIMEOUT,
  967. CMSHUNGAPPTIMEOUT);
  968. gCmsWaitToKillTimeout = GetRegIntFromID(
  969. hKey,
  970. STR_CMSWAITTOKILLTIMEOUT,
  971. CMSWAITTOKILLTIMEOUT);
  972. /*
  973. * Need to protect ourselves from users mucking about the registry.
  974. */
  975. if (gCmsHungAppTimeout == 0) {
  976. gCmsHungAppTimeout = CMSHUNGAPPTIMEOUT;
  977. }
  978. gdwHungToKillCount = gCmsWaitToKillTimeout / gCmsHungAppTimeout;
  979. gfAutoEndTask = GetRegIntFromID(
  980. hKey,
  981. STR_AUTOENDTASK,
  982. gfAutoEndTask);
  983. NtClose(hKey);
  984. }
  985. NtClose(hCurrentUserKey);
  986. }
  987. Status = MyRegOpenKey(NULL,
  988. L"\\Registry\\Machine\\System\\CurrentControlSet\\Control",
  989. &hKey);
  990. if (NT_SUCCESS(Status)) {
  991. gdwServicesWaitToKillTimeout = GetRegIntFromID(
  992. hKey,
  993. STR_WAITTOKILLSERVICETIMEOUT,
  994. gCmsWaitToKillTimeout);
  995. gdwProcessTerminateTimeout = GetRegIntFromID(
  996. hKey,
  997. STR_PROCESSTERMINATETIMEOUT,
  998. PROCESSTERMINATETIMEOUT);
  999. if (gdwProcessTerminateTimeout < CMSHUNGAPPTIMEOUT) {
  1000. gdwProcessTerminateTimeout = CMSHUNGAPPTIMEOUT;
  1001. }
  1002. NtClose(hKey);
  1003. }
  1004. }
  1005. ULONG
  1006. SrvLogon(
  1007. IN OUT PCSR_API_MSG m,
  1008. IN OUT PCSR_REPLY_STATUS ReplyStatus)
  1009. {
  1010. PLOGONMSG a = (PLOGONMSG)&m->u.ApiMessageData;
  1011. NTSTATUS Status;
  1012. UNREFERENCED_PARAMETER(ReplyStatus);
  1013. if (!CsrImpersonateClient(NULL)) {
  1014. return STATUS_UNSUCCESSFUL;
  1015. }
  1016. if (a->fLogon) {
  1017. /*
  1018. * Flush the MultiLingual UI (MUI) alternate resource modules from
  1019. * within NTDLL, so that the new user logging-on gets his chance to
  1020. * load his own.
  1021. */
  1022. LdrFlushAlternateResourceModules();
  1023. /*
  1024. * Take care of NLS cache for LogON.
  1025. */
  1026. BaseSrvNlsLogon(TRUE);
  1027. /*
  1028. * Set the cleanup event so that the RIT can handle the NLS
  1029. * registry notification.
  1030. */
  1031. gfLogon = TRUE;
  1032. Status = NtSetEvent(ghNlsEvent, NULL);
  1033. ASSERT(NT_SUCCESS(Status));
  1034. } else {
  1035. /*
  1036. * Take care of NLS cache for LogOFF.
  1037. */
  1038. BaseSrvNlsLogon(FALSE);
  1039. }
  1040. /*
  1041. * Get timeout values from registry.
  1042. */
  1043. GetTimeouts();
  1044. CsrRevertToSelf();
  1045. /*
  1046. * Initialize console attributes.
  1047. */
  1048. InitializeConsoleAttributes();
  1049. return STATUS_SUCCESS;
  1050. }
  1051. ULONG
  1052. SrvRegisterLogonProcess(
  1053. IN OUT PCSR_API_MSG m,
  1054. IN OUT PCSR_REPLY_STATUS ReplyStatus)
  1055. {
  1056. NTSTATUS Status;
  1057. UNREFERENCED_PARAMETER(ReplyStatus);
  1058. /*
  1059. * Fail if this is not the first call.
  1060. */
  1061. EnterCrit();
  1062. if (gIdLogon == 0) {
  1063. gIdLogon = *(DWORD*)m->u.ApiMessageData;
  1064. Status = STATUS_SUCCESS;
  1065. } else {
  1066. Status = STATUS_UNSUCCESSFUL;
  1067. }
  1068. LeaveCrit();
  1069. return Status;
  1070. }
  1071. #if DBG
  1072. ULONG
  1073. SrvWin32HeapFail(
  1074. IN OUT PCSR_API_MSG m,
  1075. IN OUT PCSR_REPLY_STATUS ReplyStatus)
  1076. {
  1077. PWIN32HEAPFAILMSG a = (PWIN32HEAPFAILMSG)&m->u.ApiMessageData;
  1078. UNREFERENCED_PARAMETER(ReplyStatus);
  1079. Win32HeapFailAllocations(a->bFail);
  1080. return STATUS_SUCCESS;
  1081. }
  1082. ULONG
  1083. SrvWin32HeapStat(
  1084. IN OUT PCSR_API_MSG m,
  1085. IN OUT PCSR_REPLY_STATUS ReplyStatus)
  1086. {
  1087. extern DWORD Win32HeapStat(PDBGHEAPSTAT phs, DWORD dwLen, BOOL bNeedTagShift);
  1088. PWIN32HEAPSTATMSG a = (PWIN32HEAPSTATMSG)&m->u.ApiMessageData;
  1089. UNREFERENCED_PARAMETER(ReplyStatus);
  1090. if (!CsrValidateMessageBuffer(m, &a->phs, a->dwLen, sizeof(BYTE))) {
  1091. return STATUS_INVALID_PARAMETER;
  1092. }
  1093. a->dwMaxTag = Win32HeapStat(a->phs, a->dwLen, TRUE);
  1094. return STATUS_SUCCESS;
  1095. }
  1096. #endif
  1097. ULONG
  1098. SrvGetThreadConsoleDesktop(
  1099. IN OUT PCSR_API_MSG m,
  1100. IN OUT PCSR_REPLY_STATUS ReplyStatus)
  1101. {
  1102. PGETTHREADCONSOLEDESKTOPMSG a = (PGETTHREADCONSOLEDESKTOPMSG)&m->u.ApiMessageData;
  1103. UNREFERENCED_PARAMETER(ReplyStatus);
  1104. return GetThreadConsoleDesktop(a->dwThreadId, &a->hdeskConsole);
  1105. }
  1106. /***************************************************************************\
  1107. * FindWindowFromThread
  1108. *
  1109. * This is a callback function passed to EnumThreadWindows by to find a top
  1110. * level window owned by a given thread. Ideally, we want to find a top level
  1111. * owner.
  1112. *
  1113. * 07/18/96 GerardoB Created
  1114. \***************************************************************************/
  1115. BOOL CALLBACK FindWindowFromThread(
  1116. HWND hwnd,
  1117. LPARAM lParam)
  1118. {
  1119. BOOL fTopLevelOwner;
  1120. #ifdef FE_IME
  1121. if (IsImeWindow(hwnd)) {
  1122. return TRUE;
  1123. }
  1124. #endif
  1125. fTopLevelOwner = (GetWindow(hwnd, GW_OWNER) == NULL);
  1126. if (*((HWND *)lParam) == NULL || fTopLevelOwner) {
  1127. *((HWND *)lParam) = hwnd;
  1128. }
  1129. return !fTopLevelOwner;
  1130. }
  1131. #if DBG
  1132. DWORD GetRipComponent(
  1133. VOID)
  1134. {
  1135. return RIP_USERSRV;
  1136. }
  1137. #endif
  1138. /***************************************************************************\
  1139. * StartCreateSystemThreads
  1140. *
  1141. * Simply calls xxxCreateSystemThreads which will calls to the right
  1142. * thread routine (depending on uThreadID).
  1143. *
  1144. * History:
  1145. * 15-Mar-00 MHamid Created.
  1146. \***************************************************************************/
  1147. VOID StartCreateSystemThreads(
  1148. PVOID pUnused)
  1149. {
  1150. PCSR_THREAD pt = CsrConnectToUser();
  1151. UNREFERENCED_PARAMETER(pUnused);
  1152. NtUserCallOneParam(FALSE, SFI_XXXCREATESYSTEMTHREADS);
  1153. if (pt) {
  1154. CsrDereferenceThread(pt);
  1155. }
  1156. UserExitWorkerThread(STATUS_SUCCESS);
  1157. }
  1158. /***************************************************************************\
  1159. * SrvCreateSystemThreads
  1160. *
  1161. * Just creates a thread (at StartCreateSystemThreads) and return.
  1162. *
  1163. * History:
  1164. * 15-Mar-00 MHamid Created.
  1165. \***************************************************************************/
  1166. ULONG SrvCreateSystemThreads(
  1167. IN OUT PCSR_API_MSG m,
  1168. IN OUT PCSR_REPLY_STATUS ReplyStatus)
  1169. {
  1170. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  1171. HANDLE UniqueProcessId;
  1172. HANDLE hProcess;
  1173. BOOL bRemoteThread;
  1174. CLIENT_ID ClientId;
  1175. PCREATESYSTEMTHREADSMSG pCreateSystemThreads = (PCREATESYSTEMTHREADSMSG)&m->u.ApiMessageData;
  1176. UNREFERENCED_PARAMETER(ReplyStatus);
  1177. if ((bRemoteThread = pCreateSystemThreads->bRemoteThread)) {
  1178. LPTHREAD_START_ROUTINE ThreadStart = NULL;
  1179. PCSR_PROCESS Process;
  1180. HANDLE huser32 = GetModuleHandle(TEXT("user32.dll"));
  1181. if (huser32) {
  1182. ThreadStart = (LPTHREAD_START_ROUTINE)GetProcAddress(huser32, "CreateSystemThreads");
  1183. }
  1184. if (ThreadStart) {
  1185. UniqueProcessId = (HANDLE)NtUserCallNoParam(SFI_GETREMOTEPROCESSID);
  1186. Status = CsrLockProcessByClientId(UniqueProcessId, &Process);
  1187. if (!NT_SUCCESS(Status)) {
  1188. RIPMSG1(RIP_WARNING,
  1189. "SrvCreateSystemThreads: CsrLockProcessByClientId failed for remote thread with Status 0x%x", Status);
  1190. NtUserCallOneParam(TRUE, SFI_HANDLESYSTEMTHREADCREATIONFAILURE);
  1191. return Status;
  1192. }
  1193. hProcess = Process->ProcessHandle;
  1194. Status = RtlCreateUserThread(hProcess, NULL, FALSE, 0, 0, 0x4000, ThreadStart, NULL, NULL, &ClientId);
  1195. CsrUnlockProcess(Process);
  1196. }
  1197. if (!NT_SUCCESS(Status)) {
  1198. RIPMSG1(RIP_WARNING,
  1199. "SrvCreateSystemThreads: Failed for remote thread with Status 0x%x", Status);
  1200. NtUserCallOneParam(TRUE, SFI_HANDLESYSTEMTHREADCREATIONFAILURE);
  1201. }
  1202. } else {
  1203. Status = CsrExecServerThread((PUSER_THREAD_START_ROUTINE)StartCreateSystemThreads, 0);
  1204. if (!NT_SUCCESS(Status)) {
  1205. RIPMSG1(RIP_WARNING,
  1206. "SrvCreateSystemThreads: RtlCreateUserThread failed with Status 0x%x", Status);
  1207. NtUserCallOneParam(FALSE, SFI_HANDLESYSTEMTHREADCREATIONFAILURE);
  1208. }
  1209. }
  1210. return Status;
  1211. }