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

2038 lines
65 KiB

  1. /*************************************************************************
  2. *
  3. * wstlpc.c
  4. *
  5. * WinStation LPC Initialization and dispatch functions for NT ICA Server
  6. *
  7. * Copyright Microsoft Corporation, 1998
  8. *
  9. *
  10. *************************************************************************/
  11. /*
  12. * Includes
  13. */
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. #include <rpc.h>
  17. #include "icaevent.h"
  18. /*
  19. * August 19, 1996 JohnR:
  20. *
  21. * The ICASRV and WinStation API's have been now reorganized.
  22. *
  23. * The main visible API's that client applications such as winadmin,
  24. * winquery, and system components such as the spooler see are now
  25. * based on RPC.
  26. *
  27. * Internally where ICASRV communicates with WinStations, the reverse
  28. * LPC is used. This is because the client of these API's is
  29. * the WIN32K.SYS kernel mode module. Non-system mode callers of
  30. * the LPC API's are no longer allowed, and must use RPC.
  31. */
  32. typedef NTSTATUS (*PWINSTATION_API) (
  33. IN PLPC_CLIENT_CONTEXT pContext,
  34. IN OUT PWINSTATION_APIMSG ApiMsg
  35. );
  36. /*
  37. * entry for the list that keeps track of currently active LPC contexts
  38. */
  39. typedef struct _TERMSRVLPCCONTEXT {
  40. LIST_ENTRY Links;
  41. PVOID pContext;
  42. } TERMSRVLPCCONTEXT, *PTERMSRVLPCCONTEXT;
  43. LIST_ENTRY gTermsrvLpcListHead;
  44. /*
  45. * External Functions
  46. */
  47. NTSTATUS SendWinStationCommand( PWINSTATION, PWINSTATION_APIMSG, ULONG );
  48. /*
  49. * Internal Functions
  50. */
  51. VOID InsertLpcContext(PVOID pContext);
  52. VOID RemoveLpcContext(PVOID pContext);
  53. BOOL GetSessionIdFromLpcContext(PLPC_CLIENT_CONTEXT pContext, PULONG pSessionId);
  54. NTSTATUS WinStationLpcThread( IN PVOID ThreadParameter );
  55. NTSTATUS WinStationLpcHandleConnectionRequest( PPORT_MESSAGE );
  56. VOID WinStationLpcClientHasTerminated( PLPC_CLIENT_CONTEXT );
  57. NTSTATUS WinStationInternalCreate( PLPC_CLIENT_CONTEXT, PWINSTATION_APIMSG );
  58. NTSTATUS WinStationInternalReset( PLPC_CLIENT_CONTEXT, PWINSTATION_APIMSG );
  59. NTSTATUS WinStationInternalDisconnect( PLPC_CLIENT_CONTEXT, PWINSTATION_APIMSG );
  60. NTSTATUS WinStationWCharLog( PLPC_CLIENT_CONTEXT pContext, PWINSTATION_APIMSG pMsg );
  61. NTSTATUS WinStationGetSMCommand( PLPC_CLIENT_CONTEXT, PWINSTATION_APIMSG );
  62. NTSTATUS WinStationBrokenConnection( PLPC_CLIENT_CONTEXT, PWINSTATION_APIMSG );
  63. NTSTATUS WinStationIcaReplyMessage( PLPC_CLIENT_CONTEXT, PWINSTATION_APIMSG );
  64. NTSTATUS WinStationIcaShadowHotkey( PLPC_CLIENT_CONTEXT, PWINSTATION_APIMSG );
  65. NTSTATUS WinStationWindowInvalid( PLPC_CLIENT_CONTEXT pContext,PWINSTATION_APIMSG pMsg );
  66. /*
  67. * External functions we call out to do the actual WinStation control
  68. */
  69. NTSTATUS WinStationDisconnectWorker( ULONG, BOOLEAN, BOOLEAN );
  70. NTSTATUS WinStationDoDisconnect( PWINSTATION, PRECONNECT_INFO, BOOLEAN );
  71. NTSTATUS WinStationExceptionFilter( PWSTR, PEXCEPTION_POINTERS );
  72. NTSTATUS QueueWinStationCreate( PWINSTATIONNAME );
  73. PSECURITY_DESCRIPTOR BuildSystemOnlySecurityDescriptor();
  74. /*
  75. * Local variables
  76. */
  77. ULONG MinApiThreads;
  78. ULONG MaxApiThreads;
  79. ULONG NumApiThreads;
  80. ULONG WaitingApiThreads;
  81. RTL_CRITICAL_SECTION ApiThreadLock;
  82. HANDLE SsWinStationLpcPort;
  83. BOOLEAN ShutdownInProgress;
  84. ULONG MessageId = 1;
  85. /*
  86. * ICASRV WinStation LPC Dispatch Table
  87. *
  88. * If this table is changed, the table below must be modified too.
  89. */
  90. PWINSTATION_API WinStationLpcDispatch[SMWinStationMaxApiNumber] = {
  91. WinStationInternalCreate, // for ICASRV internal use only
  92. WinStationInternalReset, // for ICASRV internal use only
  93. WinStationInternalDisconnect, // for ICASRV internal use only
  94. WinStationWCharLog, // for ICASRV internal use only
  95. WinStationGetSMCommand,
  96. WinStationBrokenConnection,
  97. WinStationIcaReplyMessage,
  98. WinStationIcaShadowHotkey,
  99. NULL, // WinStationDoConnect, // needed for connect and reconnect (I.E. InitMouse)
  100. NULL, // WinStationDoDisconnect, // needed for disconnect (I.E. disable screen)
  101. NULL, // WinStationDoReconnect // Reconnect
  102. NULL, // WinStationExitWindows, // Logoff
  103. NULL, // WinStationTerminate, // Terminate process (less gentle than logoff?)
  104. NULL, // WinStationNtSecurity, // CTL-ALT-DEL screen
  105. NULL, // WinStationDoMessage, // Message box
  106. NULL, // WinStationDoBreakPoint // WinStation breakpoint
  107. NULL, // WinStationThinwireStats // Get thinwire stats
  108. NULL, // WinStationShadowSetup,
  109. NULL, // WinStationShadowStart,
  110. NULL, // WinStationShadowStop,
  111. NULL, // WinStationShadowCleanup,
  112. NULL, // WinStationPassthruEnable,
  113. NULL, // WinStationPassthruDisable,
  114. NULL, // WinStationSetTimeZone, // Set Time Zone
  115. NULL, // WinStationInitialProgram,
  116. NULL, // WinStationNtsdDebug,
  117. NULL, // WinStationBroadcastSystemMessage // For PNP: This is the counter part to BroadcastSystemMessage on console
  118. NULL, // WinStationSendWindowMessage // General Window's SendMessage() API
  119. NULL, // SMWinStationNotify
  120. WinStationWindowInvalid
  121. };
  122. #if DBG
  123. PSZ WinStationLpcName[SMWinStationMaxApiNumber] = {
  124. "WinStationInternalCreate",
  125. "WinStationInternalReset",
  126. "WinStationInternalDisconnect",
  127. "WinStationWCharLog",
  128. "WinStationGetSMCommand",
  129. "WinStationBrokenConnection",
  130. "WinStationIcaReplyMessage",
  131. "WinStationShadowHotkey",
  132. "WinStationDoConnect",
  133. "WinStationDoDisconnect",
  134. "WinStationDoReconnect",
  135. "WinStationExitWindows",
  136. "WinStationTerminate",
  137. "WinStationNtSecurity",
  138. "WinStationDoMessage",
  139. "WinStationDoBreakPoint",
  140. "WinStationThinwireStats",
  141. "WinStationShadowSetup",
  142. "WinStationShadowStart",
  143. "WinStationShadowStop",
  144. "WinStationShadowCleanup",
  145. "WinStationPassthruEnable",
  146. "WinStationPassthruDisable",
  147. "WinStationSetTimeZone",
  148. "WinStationInitialProgram",
  149. "WinStationNtsdDebug",
  150. "WinStationBroadcastSystemMessage",
  151. "WinStationSendWindowMessage",
  152. "SMWinStationNotify",
  153. "WinStationWindowInvalid"
  154. };
  155. PSZ WinStationStateName[] = {
  156. "Active",
  157. "Connected",
  158. "ConnectQuery",
  159. "VirtualIO",
  160. "Disconnected",
  161. "Idle",
  162. "Off",
  163. "Reset",
  164. "Down",
  165. "Init",
  166. };
  167. #endif // DBG
  168. /*****************************************************************************
  169. *
  170. * WinStationInitLPC
  171. *
  172. * Create the Session manager WinStation API LPC port and Thread
  173. *
  174. * ENTRY:
  175. * No Parameters
  176. *
  177. * EXIT:
  178. * STATUS_SUCCESS - no error
  179. *
  180. ****************************************************************************/
  181. NTSTATUS
  182. WinStationInitLPC()
  183. {
  184. ULONG i;
  185. NTSTATUS st;
  186. ANSI_STRING Name;
  187. UNICODE_STRING UnicodeName;
  188. OBJECT_ATTRIBUTES ObjA;
  189. ULONG Length;
  190. SYSTEM_BASIC_INFORMATION SysInfo;
  191. PSECURITY_DESCRIPTOR SecurityDescriptor;
  192. TRACE((hTrace,TC_ICASRV,TT_API1,"TERMSRV: WinSta: Init WinStation LPC Channels\n"));
  193. /*
  194. * Initialize PC context LIst
  195. */
  196. InitializeListHead(&gTermsrvLpcListHead);
  197. /*
  198. * create a security descriptor that allows only SYSTEM access
  199. */
  200. SecurityDescriptor = BuildSystemOnlySecurityDescriptor();
  201. if (!SecurityDescriptor)
  202. {
  203. return STATUS_NO_MEMORY;
  204. }
  205. /*
  206. * Create the port for the WIN32 CSRSS's to connect to.
  207. */
  208. RtlInitAnsiString( &Name, "\\SmSsWinStationApiPort" );
  209. st = RtlAnsiStringToUnicodeString( &UnicodeName, &Name, TRUE);
  210. if (!NT_SUCCESS(st))
  211. {
  212. MemFree( SecurityDescriptor );
  213. return st;
  214. }
  215. InitializeObjectAttributes( &ObjA, &UnicodeName, 0, NULL,
  216. SecurityDescriptor );
  217. TRACE((hTrace,TC_ICASRV,TT_API1,"TERMSRV: Creating SsApiPort\n"));
  218. ASSERT( sizeof(WINSTATION_APIMSG) <= PORT_MAXIMUM_MESSAGE_LENGTH );
  219. st = NtCreatePort( &SsWinStationLpcPort,
  220. &ObjA,
  221. sizeof(WINSTATIONAPI_CONNECT_INFO),
  222. sizeof(WINSTATION_APIMSG),
  223. sizeof(WINSTATION_APIMSG) * 32 );
  224. RtlFreeUnicodeString(&UnicodeName);
  225. /*
  226. * Clean up security stuff
  227. */
  228. MemFree( SecurityDescriptor );
  229. if (!NT_SUCCESS(st))
  230. {
  231. return st;
  232. }
  233. /*
  234. * Determine min/max number of API threads we will support
  235. */
  236. if (g_bPersonalTS) {
  237. MinApiThreads = 1;
  238. MaxApiThreads = 100;
  239. }
  240. else {
  241. MinApiThreads = 3;
  242. st = NtQuerySystemInformation( SystemBasicInformation,
  243. &SysInfo, sizeof(SysInfo), &Length );
  244. if ( NT_SUCCESS( st ) )
  245. MaxApiThreads = 100; // (3 + SysInfo.NumberOfProcessors * 2);
  246. else {
  247. DBGPRINT(( "TERMSRV: NtQuerySystemInfo failed, rc=0x%x\n", st ));
  248. MaxApiThreads = 100;
  249. }
  250. }
  251. NumApiThreads = 0;
  252. WaitingApiThreads = 0;
  253. st = RtlInitializeCriticalSection( &ApiThreadLock );
  254. if(!(NT_SUCCESS(st))) {
  255. return(st);
  256. }
  257. /*
  258. * Create Initial Set of Server Threads
  259. */
  260. TRACE((hTrace,TC_ICASRV,TT_API1,"TERMSRV: Creating WinStation LPC Server Threads\n"));
  261. for ( i = 0; i < MinApiThreads; i++ ) {
  262. DWORD ThreadId;
  263. HANDLE Handle;
  264. Handle = CreateThread( NULL,
  265. 0,
  266. (LPTHREAD_START_ROUTINE)WinStationLpcThread,
  267. NULL,
  268. THREAD_SET_INFORMATION,
  269. &ThreadId );
  270. if ( !Handle ) {
  271. return( STATUS_TOO_MANY_THREADS );
  272. } else {
  273. NtClose( Handle );
  274. }
  275. }
  276. RtlEnterCriticalSection( &ApiThreadLock );
  277. NumApiThreads += MinApiThreads;
  278. RtlLeaveCriticalSection( &ApiThreadLock );
  279. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: Done Creating Service API Service Threads\n" ));
  280. return STATUS_SUCCESS;
  281. }
  282. /*****************************************************************************
  283. *
  284. * WinStationLpcThread
  285. *
  286. * Main service thread for internal Winstation LPC connections.
  287. *
  288. * ENTRY:
  289. * ThreadParameter (input)
  290. * Not used standard NT ThreadCreate() parameter
  291. *
  292. * EXIT:
  293. * Should never exit
  294. *
  295. ****************************************************************************/
  296. NTSTATUS
  297. WinStationLpcThread( IN PVOID ThreadParameter )
  298. {
  299. WINSTATION_APIMSG ApiMsg;
  300. PWINSTATION_APIMSG ReplyMsg;
  301. PLPC_CLIENT_CONTEXT pContext;
  302. NTSTATUS Status;
  303. HANDLE Handle;
  304. ReplyMsg = NULL;
  305. /*
  306. * Loop forever processing API requests
  307. */
  308. for ( ; ; ) {
  309. /*
  310. * If there are more than the minimum number of API threads active,
  311. * and at least 1 waiting thread, then this thread will terminate.
  312. * But first, any pending reply message must be sent.
  313. */
  314. RtlEnterCriticalSection( &ApiThreadLock );
  315. #ifdef notdef
  316. if ( NumApiThreads > MinApiThreads && WaitingApiThreads ) {
  317. NumApiThreads--;
  318. RtlLeaveCriticalSection( &ApiThreadLock );
  319. if ( ReplyMsg ) {
  320. (VOID) NtReplyPort( SsWinStationLpcPort,
  321. (PPORT_MESSAGE) ReplyMsg );
  322. }
  323. break;
  324. }
  325. #endif
  326. /*
  327. * Increment the number of waiting threads and wait for an LPC request
  328. */
  329. WaitingApiThreads++;
  330. RtlLeaveCriticalSection( &ApiThreadLock );
  331. Status = NtReplyWaitReceivePort( SsWinStationLpcPort,
  332. (PVOID *) &pContext,
  333. (PPORT_MESSAGE) ReplyMsg,
  334. (PPORT_MESSAGE) &ApiMsg );
  335. RtlEnterCriticalSection( &ApiThreadLock );
  336. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStation LPC Service Thread got a message\n" ));
  337. /*
  338. * If there are no more waiting threads,
  339. * then create a new API thread to process requests.
  340. */
  341. if ( --WaitingApiThreads == 0 && NumApiThreads < MaxApiThreads ) {
  342. DWORD ThreadId;
  343. NumApiThreads++;
  344. RtlLeaveCriticalSection( &ApiThreadLock );
  345. Handle = CreateThread( NULL,
  346. 0,
  347. (LPTHREAD_START_ROUTINE)WinStationLpcThread,
  348. NULL,
  349. THREAD_SET_INFORMATION,
  350. &ThreadId );
  351. if ( !Handle ) {
  352. RtlEnterCriticalSection( &ApiThreadLock );
  353. NumApiThreads--;
  354. RtlLeaveCriticalSection( &ApiThreadLock );
  355. } else {
  356. NtClose( Handle );
  357. }
  358. } else {
  359. RtlLeaveCriticalSection( &ApiThreadLock );
  360. }
  361. if ( !NT_SUCCESS(Status) ) {
  362. ReplyMsg = NULL;
  363. continue;
  364. }
  365. try {
  366. /*
  367. * Process connection request from a new client
  368. */
  369. if ( ApiMsg.h.u2.s2.Type == LPC_CONNECTION_REQUEST ) {
  370. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStation LPC Service Thread got connection message\n" ));
  371. // CONNECT_INFO is in ApiMsg from NtReplyWaitReceivePort() when
  372. // a connection request is received. This differs from
  373. // NtListenPort() which passes separate pointers for CONNECT_INFO.
  374. WinStationLpcHandleConnectionRequest( (PPORT_MESSAGE)&ApiMsg );
  375. ReplyMsg = NULL;
  376. continue;
  377. }
  378. /*
  379. * Process port closed message
  380. */
  381. if ( ApiMsg.h.u2.s2.Type == LPC_PORT_CLOSED ) {
  382. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStation LPC Service Thread got PORT_CLOSED message pContext %p\n",
  383. pContext));
  384. // NOTE: This function frees the CONTEXT struct
  385. WinStationLpcClientHasTerminated( pContext );
  386. ReplyMsg = NULL;
  387. continue;
  388. }
  389. ASSERT(sizeof(WinStationLpcDispatch)/sizeof(WinStationLpcDispatch[0]) == SMWinStationMaxApiNumber);
  390. ASSERT(sizeof(WinStationLpcName)/sizeof(WinStationLpcName[0]) == SMWinStationMaxApiNumber);
  391. /*
  392. * Process API request from client
  393. */
  394. ReplyMsg = &ApiMsg;
  395. if ((ULONG) ApiMsg.ApiNumber >= (ULONG)SMWinStationMaxApiNumber ) {
  396. DBGPRINT(( "TERMSRV: WinStation LPC Service Thread Bad API number %d\n",
  397. ApiMsg.ApiNumber ));
  398. ApiMsg.ReturnedStatus = STATUS_NOT_IMPLEMENTED;
  399. } else {
  400. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStation LPC Service Thread got %s message\n",
  401. WinStationLpcName[ApiMsg.ApiNumber] ));
  402. if ( WinStationLpcDispatch[ApiMsg.ApiNumber] ) {
  403. // Save Msg for use by CheckClientAccess
  404. NtCurrentTeb()->Win32ThreadInfo = &ApiMsg;
  405. // The functions set ApiMsg.ReturnedStatus
  406. Status = (WinStationLpcDispatch[ApiMsg.ApiNumber])( pContext, &ApiMsg );
  407. // Clear thread Msg pointer
  408. NtCurrentTeb()->Win32ThreadInfo = NULL;
  409. } else {
  410. // This API is not implemented in Session Manager
  411. ApiMsg.ReturnedStatus = STATUS_NOT_IMPLEMENTED;
  412. }
  413. /*
  414. * If client does not expect a reply or reply is pending
  415. * (will be sent asynchronously), then clear ReplyMsg pointer.
  416. */
  417. if ( !ApiMsg.WaitForReply || Status == STATUS_PENDING )
  418. ReplyMsg = NULL;
  419. }
  420. } except( WinStationExceptionFilter( L"WinStationLpcThread trapped!!",
  421. GetExceptionInformation() ) ) {
  422. ReplyMsg = NULL;
  423. }
  424. }
  425. return( STATUS_SUCCESS );
  426. }
  427. /*****************************************************************************
  428. *
  429. * WinStationLpcHandleConnectionRequest
  430. *
  431. * Handle connection requests and create our local data structures
  432. *
  433. * ENTRY:
  434. * ConnectionRequest (input)
  435. * NT LPC PORT_MESSAGE describing the request
  436. *
  437. * EXIT:
  438. * STATUS_SUCCESS - no error
  439. *
  440. ****************************************************************************/
  441. NTSTATUS
  442. WinStationLpcHandleConnectionRequest(
  443. IN PPORT_MESSAGE ConnectionRequest
  444. )
  445. {
  446. NTSTATUS st;
  447. HANDLE CommunicationPort;
  448. BOOLEAN Accept;
  449. PWINSTATIONAPI_CONNECT_INFO info;
  450. REMOTE_PORT_VIEW ClientView;
  451. REMOTE_PORT_VIEW *pClientView = NULL;
  452. PORT_VIEW ServerView;
  453. PORT_VIEW * pServerView = NULL;
  454. LARGE_INTEGER SectionSize;
  455. HANDLE PortSection = NULL ;
  456. PWINSTATION pWinStation;
  457. PLPC_CLIENT_CONTEXT pContext = NULL;
  458. ULONG ClientLogonId;
  459. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationLpcHandleConnectionRequest called\n" ));
  460. Accept = TRUE; // Assume we will accept
  461. // An undocumented NT LPC feature is that the CONNECT_INFO structure
  462. // follows the PORT_MESSAGE header when the connection request is
  463. // received through NtReplyWaitReceivePort(), which is useful since we
  464. // only have to maintain (1) thread for WinStation LPC API's, and
  465. // do not have to dedicated one to NtListenPort() just for connection
  466. // requests.
  467. if ( ConnectionRequest->u1.s1.DataLength != sizeof(WINSTATIONAPI_CONNECT_INFO) ) {
  468. TRACE((hTrace,TC_ICASRV,TT_ERROR, "TERMSRV: WSTAPI: Bad CONNECTINFO length %d\n",
  469. ConnectionRequest->u1.s1.DataLength ));
  470. Accept = FALSE;
  471. } else {
  472. info = (PWINSTATIONAPI_CONNECT_INFO)
  473. ((ULONG_PTR)ConnectionRequest + sizeof(PORT_MESSAGE));
  474. //
  475. // We can set Accept to FALSE at anytime here for certain types
  476. // of requests and/or caller identities.
  477. //
  478. if ( ConnectionRequest->ClientViewSize == 0 ) {
  479. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WSTAPI: Creating View memory\n" ));
  480. pServerView = &ServerView;
  481. // Setup Port memory for larger data transfers
  482. SectionSize.LowPart = WINSTATIONAPI_PORT_MEMORY_SIZE;
  483. SectionSize.HighPart = 0;
  484. st = NtCreateSection(&PortSection, SECTION_ALL_ACCESS, NULL,
  485. &SectionSize, PAGE_READWRITE, SEC_COMMIT, NULL);
  486. if (!NT_SUCCESS(st)) {
  487. TRACE((hTrace,TC_ICASRV,TT_ERROR,"TERMSRV: Error Creating Section 0x%x\n", st));
  488. Accept = FALSE;
  489. info->AcceptStatus = st;
  490. } else {
  491. ServerView.Length = sizeof(ServerView);
  492. ServerView.SectionHandle = PortSection;
  493. ServerView.SectionOffset = 0;
  494. ServerView.ViewSize = SectionSize.LowPart;
  495. ServerView.ViewBase = 0;
  496. ServerView.ViewRemoteBase = 0;
  497. }
  498. }
  499. if ( Accept ) {
  500. // Init the REMOTE_VIEW structure
  501. ClientView.Length = sizeof(ClientView);
  502. ClientView.ViewSize = 0;
  503. ClientView.ViewBase = 0;
  504. pClientView = &ClientView;
  505. info->AcceptStatus = STATUS_SUCCESS;
  506. if ( info->Version != CITRIX_WINSTATIONAPI_VERSION ) {
  507. info->AcceptStatus = 1; // Fill in bad version param code
  508. TRACE((hTrace,TC_ICASRV,TT_ERROR,"TERMSRV: WSTAPI: Bad Version %d\n", info->Version));
  509. Accept = FALSE;
  510. }
  511. // Add checks for info.RequestedAccess against the requesting
  512. // threads security rights for WinStation access. Use the Se* stuff
  513. // to do the checking and audit generation
  514. // On Security Access failure:
  515. // Accept = FALSE;
  516. // info->AcceptStatus = NT invalid rights message
  517. }
  518. }
  519. //
  520. // Get the ClientLogonId
  521. //
  522. if ( Accept ) {
  523. HANDLE ClientProcessHandle;
  524. OBJECT_ATTRIBUTES ObjA;
  525. InitializeObjectAttributes( &ObjA, NULL, 0, NULL, NULL );
  526. st = NtOpenProcess( &ClientProcessHandle, GENERIC_READ,
  527. &ObjA, &ConnectionRequest->ClientId );
  528. if (NT_SUCCESS(st)) {
  529. GetProcessLogonId( ClientProcessHandle, &ClientLogonId );
  530. NtClose( ClientProcessHandle );
  531. } else {
  532. Accept = FALSE;
  533. info->AcceptStatus = st;
  534. }
  535. }
  536. //
  537. // Allocate a context connection control block.
  538. // The address of this block is used as the
  539. // port context in all calls from a client process
  540. //
  541. if ( Accept ) {
  542. pContext = MemAlloc( sizeof(LPC_CLIENT_CONTEXT) );
  543. if ( pContext ) {
  544. pContext->CommunicationPort = NULL;
  545. pContext->AccessRights = info->RequestedAccess;
  546. } else {
  547. Accept = FALSE;
  548. info->AcceptStatus = STATUS_NO_MEMORY;
  549. }
  550. }
  551. // More undocumented NT. Many parameters are missing here and in ntlpcapi.h
  552. // from the documentation. The CONNECTION_INFO message is part
  553. // of the message body following PORT_MESSAGE, just like
  554. // NtReplyWaitReceivePort().
  555. TRACE((hTrace,TC_ICASRV,TT_API1,"TERMSRV: WSTAPI: Calling AcceptConnectPort, Accept %d\n", Accept));
  556. TRACE((hTrace,TC_ICASRV,TT_API1,"TERMSRV: pContext %p, ConnectionRequest %p, info %p\n",
  557. pContext, ConnectionRequest, info));
  558. if (!Accept) {
  559. pClientView = NULL;
  560. pServerView = NULL;
  561. }
  562. st = NtAcceptConnectPort(
  563. &CommunicationPort,
  564. (PVOID)pContext,
  565. ConnectionRequest,
  566. Accept,
  567. pServerView,
  568. pClientView
  569. );
  570. if (!NT_SUCCESS(st)) {
  571. if (PortSection != NULL) {
  572. NtClose(PortSection);
  573. }
  574. if (pContext != NULL) {
  575. MemFree( pContext );
  576. }
  577. return st;
  578. }
  579. // Close the PortSection (LPC will hold the reference now)
  580. if ( pServerView )
  581. NtClose(PortSection);
  582. // Insert the context before completing the connect because as soon
  583. // as the complete is done, the client thread can send a request and
  584. // if this request is serviced by another LPC thread then the context
  585. // won't be found (WinStationBrokenConnection case, by instance).
  586. InsertLpcContext(pContext);
  587. if ( Accept ) {
  588. pContext->ClientViewBase = ClientView.ViewBase;
  589. pContext->ClientViewBounds = (PVOID)((ULONG_PTR)ClientView.ViewBase + ClientView.ViewSize);
  590. if ( pServerView ) {
  591. pContext->ViewBase = ServerView.ViewBase;
  592. pContext->ViewSize = ServerView.ViewSize;
  593. pContext->ViewRemoteBase = ServerView.ViewRemoteBase;
  594. TRACE((hTrace,TC_ICASRV,TT_API1,"TERMSRV: ViewBase %p, ViewSize 0x%x, ViewRemoteBase %p\n",
  595. pContext->ViewBase, pContext->ViewSize, pContext->ViewRemoteBase));
  596. } else {
  597. pContext->ViewBase = NULL;
  598. pContext->ViewSize = 0;
  599. pContext->ViewRemoteBase = NULL;
  600. }
  601. pContext->ClientLogonId = ClientLogonId;
  602. TRACE((hTrace,TC_ICASRV,TT_API1,"TERMSRV: WSTAPI: Calling CompleteConnect port %p\n",CommunicationPort));
  603. pContext->CommunicationPort = CommunicationPort;
  604. st = NtCompleteConnectPort(CommunicationPort);
  605. }
  606. TRACE((hTrace,TC_ICASRV,TT_API1,"TERMSRV: WinStation LPC Connection %sAccepted, Logonid %d pContext %p Status 0x%x\n",
  607. (Accept?"":"Not "), pContext->ClientLogonId, pContext, st));
  608. return( st );
  609. }
  610. /*****************************************************************************
  611. *
  612. * WinStationLpcClientHasTerminated
  613. *
  614. * Cleanup after an LPC communications channel has been closed.
  615. *
  616. * ENTRY:
  617. * pContext (input)
  618. * Pointer to our context structure describing the connnection
  619. *
  620. * ClientId (input)
  621. * Pointer to the NT LPC CLIENT_ID structure that describes the
  622. * unique process and thread.
  623. *
  624. * EXIT:
  625. * VOID
  626. *
  627. ****************************************************************************/
  628. VOID
  629. WinStationLpcClientHasTerminated(
  630. IN PLPC_CLIENT_CONTEXT pContext
  631. )
  632. {
  633. PWINSTATION pWinStation;
  634. NTSTATUS Status;
  635. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationLpcClientHasTerminated called, pContext %p\n",
  636. pContext));
  637. //
  638. // We can be called here with a NULL pContext if the allocation failed
  639. // in WinStationLpcHandleConnectionRequest()
  640. //
  641. if (!pContext) {
  642. return;
  643. }
  644. RemoveLpcContext(pContext);
  645. // Hack for #241885
  646. // This bug is due to client diying in the window beetween
  647. // server doing NtAcceptConnectPort() and NtCompleteConnectPort().
  648. // This is an LPC problem (we should not reveive LPC_PORT_CLOSED in such a window).
  649. // or possibly to the way termsrv uses undocumented LPC features to avoid
  650. // using a dedicated thread to do NtListenPort(). This is a temporary workaround
  651. // to avoid stress break.
  652. //
  653. // Close the communication port handle
  654. try {
  655. if (pContext->CommunicationPort == NULL) {
  656. return;
  657. }
  658. Status = NtClose( pContext->CommunicationPort );
  659. if (!NT_SUCCESS(Status)) {
  660. return;
  661. }
  662. } except( EXCEPTION_EXECUTE_HANDLER ) {
  663. return;
  664. }
  665. /*
  666. * Flush the Win32 command queue.
  667. * If the Win32 command list is not empty, then loop through each
  668. * entry on the list and unlink it and trigger the wait event.
  669. */
  670. pWinStation = FindWinStationById( pContext->ClientLogonId, FALSE );
  671. if ( pWinStation != NULL ) {
  672. if ( pContext == pWinStation->pWin32Context ) {
  673. while ( !IsListEmpty( &pWinStation->Win32CommandHead ) ) {
  674. PLIST_ENTRY Head;
  675. PCOMMAND_ENTRY pCommand;
  676. Head = pWinStation->Win32CommandHead.Flink;
  677. pCommand = CONTAINING_RECORD( Head, COMMAND_ENTRY, Links );
  678. RemoveEntryList( &pCommand->Links );
  679. if ( !pCommand->pMsg->WaitForReply ) {
  680. ASSERT( pCommand->Event == NULL );
  681. MemFree( pCommand );
  682. } else {
  683. pCommand->Links.Flink = NULL;
  684. pCommand->pMsg->ReturnedStatus = STATUS_CTX_CLOSE_PENDING;
  685. NtSetEvent( pCommand->Event, NULL );
  686. }
  687. }
  688. pWinStation->pWin32Context = NULL;
  689. }
  690. ReleaseWinStation( pWinStation );
  691. }
  692. // Free the context struct passed in by the LPC
  693. MemFree( pContext );
  694. }
  695. /*****************************************************************************
  696. *
  697. * WinStationInternalCreate
  698. *
  699. * Message parameter unmarshalling function for WinStation API.
  700. *
  701. * ENTRY:
  702. * pContext (input)
  703. * Pointer to our context structure describing the connection.
  704. *
  705. * pMsg (input/output)
  706. * Pointer to the API message, a superset of NT LPC PORT_MESSAGE.
  707. *
  708. * EXIT:
  709. * STATUS_SUCCESS - no error
  710. *
  711. ****************************************************************************/
  712. NTSTATUS
  713. WinStationInternalCreate( PLPC_CLIENT_CONTEXT pContext,
  714. PWINSTATION_APIMSG pMsg )
  715. {
  716. WINSTATIONCREATEMSG *m = &pMsg->u.Create;
  717. /*
  718. * Call the create worker
  719. */
  720. if ( m->WinStationName[0] ) {
  721. pMsg->ReturnedStatus = WinStationCreateWorker( m->WinStationName,
  722. &m->LogonId );
  723. } else {
  724. pMsg->ReturnedStatus = WinStationCreateWorker( NULL,
  725. &m->LogonId );
  726. }
  727. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationCreate, Status=0x%x\n", pMsg->ReturnedStatus ));
  728. return( STATUS_SUCCESS );
  729. }
  730. /*****************************************************************************
  731. *
  732. * WinStationInternalReset
  733. *
  734. * Message parameter unmarshalling function for WinStation API.
  735. *
  736. * ENTRY:
  737. * pContext (input)
  738. * Pointer to our context structure describing the connection.
  739. *
  740. * pMsg (input/output)
  741. * Pointer to the API message, a superset of NT LPC PORT_MESSAGE.
  742. *
  743. * EXIT:
  744. * STATUS_SUCCESS - no error
  745. *
  746. ****************************************************************************/
  747. NTSTATUS
  748. WinStationInternalReset( PLPC_CLIENT_CONTEXT pContext,
  749. PWINSTATION_APIMSG pMsg )
  750. {
  751. WINSTATIONRESETMSG *m = &pMsg->u.Reset;
  752. /*
  753. * Call the reset worker
  754. */
  755. pMsg->ReturnedStatus = WinStationResetWorker( m->LogonId, FALSE, FALSE, TRUE );
  756. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationReset, Status=0x%x\n", pMsg->ReturnedStatus ));
  757. return( STATUS_SUCCESS );
  758. }
  759. /*****************************************************************************
  760. *
  761. * WinStationInternalDisconnect
  762. *
  763. * Message parameter unmarshalling function for WinStation API.
  764. *
  765. * ENTRY:
  766. * pContext (input)
  767. * Pointer to our context structure describing the connection.
  768. *
  769. * pMsg (input/output)
  770. * Pointer to the API message, a superset of NT LPC PORT_MESSAGE.
  771. *
  772. * EXIT:
  773. * STATUS_SUCCESS - no error
  774. *
  775. ****************************************************************************/
  776. NTSTATUS
  777. WinStationInternalDisconnect( PLPC_CLIENT_CONTEXT pContext,
  778. PWINSTATION_APIMSG pMsg )
  779. {
  780. WINSTATIONDISCONNECTMSG *m = &pMsg->u.Disconnect;
  781. /*
  782. * Call the disconnect worker
  783. */
  784. pMsg->ReturnedStatus = WinStationDisconnectWorker( m->LogonId, FALSE, FALSE );
  785. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationDisconnect, Status=0x%x\n", pMsg->ReturnedStatus ));
  786. return( STATUS_SUCCESS );
  787. }
  788. /*****************************************************************************
  789. *
  790. * WinStationWCharLog
  791. *
  792. * Message parameter unmarshalling function for WinStation API.
  793. *
  794. * ENTRY:
  795. * pContext (input)
  796. * Pointer to our context structure describing the connection.
  797. *
  798. * pMsg (input/output)
  799. * Pointer to the API message, a superset of NT LPC PORT_MESSAGE.
  800. *
  801. * EXIT:
  802. * STATUS_SUCCESS - no error
  803. *
  804. ****************************************************************************/
  805. NTSTATUS
  806. WinStationWCharLog( PLPC_CLIENT_CONTEXT pContext,
  807. PWINSTATION_APIMSG pMsg )
  808. {
  809. extern WCHAR gpszServiceName[];
  810. WINSTATIONWCHARLOG *m= &pMsg->u.WCharLog;
  811. PWCHAR ModulePath = m->Buffer;
  812. HANDLE h;
  813. h = RegisterEventSource(NULL, gpszServiceName);
  814. if (h != NULL)
  815. {
  816. ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, EVENT_STACK_LOAD_FAILED, NULL, 1, 0, &ModulePath, NULL);
  817. DeregisterEventSource(h);
  818. }
  819. return( STATUS_SUCCESS );
  820. }
  821. /*****************************************************************************
  822. *
  823. * WinStationGetSMCommand
  824. *
  825. * This is the API that the Winstations call in order to get
  826. * work to do. We send Winstations commands from SendWinStationCommand()
  827. * once they have called this API.
  828. *
  829. * NOTE: Only WinStations may call this command!
  830. *
  831. * ENTRY:
  832. * pContext (input)
  833. * Pointer to our context structure describing the connection.
  834. *
  835. * pMsg (input/output)
  836. * Pointer to the API message, a superset of NT LPC PORT_MESSAGE.
  837. *
  838. * EXIT:
  839. * STATUS_SUCCESS - no error
  840. *
  841. ****************************************************************************/
  842. NTSTATUS
  843. WinStationGetSMCommand( PLPC_CLIENT_CONTEXT pContext,
  844. PWINSTATION_APIMSG pMsg )
  845. {
  846. PLIST_ENTRY Head;
  847. PWINSTATION pWinStation;
  848. PCOMMAND_ENTRY pCommand;
  849. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationGetSMCommand, LogonId=%d\n",
  850. pContext->ClientLogonId ));
  851. /*
  852. * Find and lock client WinStation
  853. */
  854. pWinStation = FindWinStationById( pContext->ClientLogonId, FALSE );
  855. if ( pWinStation == NULL ) {
  856. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationGetSMCommand LogonId=%d not found\n",
  857. pContext->ClientLogonId ));
  858. return( STATUS_SUCCESS );
  859. }
  860. /*
  861. * Ensure this is the Win32 subsystem calling
  862. */
  863. if ( pWinStation->WindowsSubSysProcessId &&
  864. pMsg->h.ClientId.UniqueProcess != pWinStation->WindowsSubSysProcessId ) {
  865. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationGetSMCommand LogonId=%d wrong process id %d != %d\n",
  866. pContext->ClientLogonId,
  867. pMsg->h.ClientId.UniqueProcess,
  868. pWinStation->WindowsSubSysProcessId ));
  869. #if DBG
  870. DbgBreakPoint();
  871. #endif
  872. ReleaseWinStation( pWinStation );
  873. return( STATUS_SUCCESS );
  874. }
  875. /*
  876. * If the LPC context pointer has not been saved yet, do it now
  877. */
  878. if ( pWinStation->pWin32Context == NULL )
  879. pWinStation->pWin32Context = pContext;
  880. /*
  881. * If this message is a reply to a previous Win32 command,
  882. * then verify the reply is for the message on the head of the
  883. * Win32 command queue and complete the command processing.
  884. */
  885. if ( pMsg->WaitForReply ) {
  886. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationGetSMCommand wait for reply\n"));
  887. if ( !IsListEmpty( &pWinStation->Win32CommandHead ) ) {
  888. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationGetSMCommand list entry\n"));
  889. Head = pWinStation->Win32CommandHead.Flink;
  890. pCommand = CONTAINING_RECORD( Head, COMMAND_ENTRY, Links );
  891. if ( pCommand->pMsg->MessageId == pMsg->MessageId ) {
  892. WINSTATION_APINUMBER ApiNumber;
  893. /*
  894. * Copy reply msg back to command entry
  895. * (make sure we preserve original API number)
  896. */
  897. ApiNumber = pCommand->pMsg->ApiNumber;
  898. *pCommand->pMsg = *pMsg;
  899. pCommand->pMsg->ApiNumber = ApiNumber;
  900. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationGetSMCommand, LogonId=%d, Reply for Cmd %s, Status=0x%x\n",
  901. pContext->ClientLogonId,
  902. WinStationLpcName[pCommand->pMsg->ApiNumber],
  903. pMsg->ReturnedStatus ));
  904. /*
  905. * Unlink this command entry and
  906. * trigger event to wakeup the waiter.
  907. */
  908. RemoveEntryList( &pCommand->Links );
  909. pCommand->Links.Flink = NULL;
  910. NtSetEvent( pCommand->Event, NULL );
  911. }
  912. else {
  913. DBGPRINT(("TERMSRV: WinStationGetSMCommand, no cmd entry for MessageId 0x%x\n", pMsg->MessageId ));
  914. }
  915. }
  916. else {
  917. DBGPRINT(( "TERMSRV: WinStationGetSMCommand, cmd queue empty for MessageId 0x%x\n", pMsg->MessageId ));
  918. }
  919. }
  920. /*
  921. * If the head of the Win32 command queue is non-empty,
  922. * then send the first command in the queue to Win32.
  923. */
  924. if ( !IsListEmpty( &pWinStation->Win32CommandHead ) ) {
  925. Head = pWinStation->Win32CommandHead.Flink;
  926. pCommand = CONTAINING_RECORD( Head, COMMAND_ENTRY, Links );
  927. /*
  928. * Send the msg contained in the command entry, but be sure to use
  929. * the LPC PORT_MESSAGE fields from the original msg we received
  930. * since we are sending the command as an LPC reply message.
  931. */
  932. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationGetSMCommand, LogonId=%d, sending next cmd\n",
  933. pWinStation->LogonId ));
  934. #ifdef notdef // no longer needed - but good example of using view memory
  935. /*
  936. * Do connect needs to copy data to the view
  937. */
  938. if ( pCommand->pMsg->ApiNumber == SMWinStationDoConnect ) {
  939. pCommand->pMsg->u.DoConnect.VDInfoLength =
  940. min ( pCommand->pMsg->u.DoConnect.VDInfoLength,
  941. pContext->ViewSize );
  942. TRACE((hTrace,TC_ICASRV,TT_API1, "SMSS: WinStationGetSMCommand, Copying VD Info data %d\n", pCommand->pMsg->u.DoConnect.VDInfoLength ));
  943. RtlCopyMemory( pContext->ViewBase,
  944. pCommand->pMsg->u.DoConnect.VDInfo,
  945. pCommand->pMsg->u.DoConnect.VDInfoLength );
  946. pCommand->pMsg->u.DoConnect.VDInfo = pContext->ViewRemoteBase;
  947. }
  948. #endif
  949. /*
  950. * On DoMessage API copy to client view and free temp memory
  951. */
  952. if ( pCommand->pMsg->ApiNumber == SMWinStationDoMessage ) {
  953. PVOID pTitle;
  954. PVOID pMessage;
  955. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: pulled SMWinStationDoMessage, copy to client view\n" ));
  956. // Get pointers to client view of memory
  957. pTitle = pContext->ViewBase;
  958. pMessage = (PVOID)((ULONG_PTR)pTitle + pCommand->pMsg->u.SendMessage.TitleLength);
  959. // Copy out the pTitle and pMessage strings to client view
  960. RtlMoveMemory( pTitle, pCommand->pMsg->u.SendMessage.pTitle,
  961. pCommand->pMsg->u.SendMessage.TitleLength );
  962. RtlMoveMemory( pMessage, pCommand->pMsg->u.SendMessage.pMessage,
  963. pCommand->pMsg->u.SendMessage.MessageLength );
  964. MemFree( pCommand->pMsg->u.SendMessage.pTitle );
  965. MemFree( pCommand->pMsg->u.SendMessage.pMessage );
  966. pCommand->pMsg->u.SendMessage.pTitle =
  967. (PVOID)(pContext->ViewRemoteBase);
  968. pCommand->pMsg->u.SendMessage.pMessage =
  969. (PVOID) ((ULONG_PTR)pContext->ViewRemoteBase + pCommand->pMsg->u.SendMessage.TitleLength);
  970. } else if ( pCommand->pMsg->ApiNumber == SMWinStationShadowStart ||
  971. pCommand->pMsg->ApiNumber == SMWinStationShadowCleanup ) {
  972. PVOID pData;
  973. // Get pointers to client view of memory
  974. pData = pContext->ViewBase;
  975. // Copy out the Thinwire data to client view
  976. RtlMoveMemory( pData, pCommand->pMsg->u.ShadowStart.pThinwireData,
  977. pCommand->pMsg->u.ShadowStart.ThinwireDataLength );
  978. MemFree( pCommand->pMsg->u.ShadowStart.pThinwireData );
  979. pCommand->pMsg->u.ShadowStart.pThinwireData =
  980. (PVOID)(pContext->ViewRemoteBase);
  981. } else if ( pCommand->pMsg->ApiNumber == SMWinStationSendWindowMessage) {
  982. PVOID pView;
  983. // Get pointers to client view of memory
  984. pView = pContext->ViewBase;
  985. RtlMoveMemory( pView, pCommand->pMsg->u.sMsg.dataBuffer,
  986. pCommand->pMsg->u.sMsg.bufferSize );
  987. MemFree( pCommand->pMsg->u.sMsg.dataBuffer );
  988. // Update msg
  989. pCommand->pMsg->u.sMsg.dataBuffer =
  990. (PVOID)pContext->ViewRemoteBase;
  991. } else if ( pCommand->pMsg->ApiNumber == SMWinStationBroadcastSystemMessage) {
  992. PVOID pView;
  993. // Get pointers to client view of memory
  994. pView = pContext->ViewBase;
  995. RtlMoveMemory( pView, pCommand->pMsg->u.bMsg.dataBuffer,
  996. pCommand->pMsg->u.bMsg.bufferSize );
  997. MemFree( pCommand->pMsg->u.bMsg.dataBuffer );
  998. // Update msg
  999. pCommand->pMsg->u.bMsg.dataBuffer =
  1000. (PVOID)pContext->ViewRemoteBase;
  1001. }
  1002. pCommand->pMsg->h = pMsg->h;
  1003. NtReplyPort( pContext->CommunicationPort,
  1004. (PPORT_MESSAGE)pCommand->pMsg );
  1005. /*
  1006. * If no reply is expected, then unlink/free this command entry.
  1007. */
  1008. if ( !pCommand->pMsg->WaitForReply ) {
  1009. RemoveEntryList( &pCommand->Links );
  1010. ASSERT( pCommand->Event == NULL );
  1011. MemFree( pCommand );
  1012. }
  1013. /*
  1014. * The Win32 command queue is empty. Save the port handle and port
  1015. * message in the WinStation. The next time a command is to be
  1016. * sent to this WinStation, these will be used to send it.
  1017. */
  1018. } else {
  1019. ASSERT( pWinStation->Win32CommandPort == NULL );
  1020. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationGetSMCommand queue empty port %p\n",
  1021. pContext->CommunicationPort));
  1022. pWinStation->Win32CommandPort = pContext->CommunicationPort;
  1023. pWinStation->Win32CommandPortMsg = pMsg->h;
  1024. }
  1025. /*
  1026. * Release WinStation
  1027. */
  1028. ReleaseWinStation( pWinStation );
  1029. /*
  1030. * We ALWAYS return STATUS_PENDING so the msg dispatch routine
  1031. * does not send a reply message now. ALL replies to this message
  1032. * are handled above or in the SendWinStationCommand() routine.
  1033. */
  1034. return( STATUS_PENDING );
  1035. }
  1036. /*****************************************************************************
  1037. *
  1038. * WinStationBrokenConnection
  1039. *
  1040. * API called from Winstation requesting a broken connection
  1041. *
  1042. * ENTRY:
  1043. * pContext (input)
  1044. * Pointer to our context structure describing the connection.
  1045. *
  1046. * pMsg (input/output)
  1047. * Pointer to the API message, a superset of NT LPC PORT_MESSAGE.
  1048. *
  1049. * EXIT:
  1050. * STATUS_SUCCESS - no error
  1051. *
  1052. ****************************************************************************/
  1053. NTSTATUS
  1054. WinStationBrokenConnection( PLPC_CLIENT_CONTEXT pContext,
  1055. PWINSTATION_APIMSG pMsg )
  1056. {
  1057. WINSTATIONBROKENCONNECTIONMSG *m = &pMsg->u.Broken;
  1058. BROKENCLASS Reason = (BROKENCLASS) m->Reason;
  1059. PWINSTATION pWinStation;
  1060. ULONG SessionId;
  1061. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationBrokenConnection, LogonId=%d, Reason=%u\n",
  1062. pContext->ClientLogonId, Reason ));
  1063. /*
  1064. * Indicate A reply will be returned to client
  1065. */
  1066. pMsg->WaitForReply = TRUE;
  1067. /*
  1068. * Make sure the context is still active and get session Id from it.
  1069. */
  1070. if (!GetSessionIdFromLpcContext(pContext, &SessionId)) {
  1071. return STATUS_SUCCESS;
  1072. }
  1073. /*
  1074. * Find and lock client WinStation
  1075. */
  1076. pWinStation = FindWinStationById( SessionId, FALSE );
  1077. if ( pWinStation == NULL )
  1078. return( STATUS_SUCCESS );
  1079. /*
  1080. * Ensure this is the Win32 subsystem calling
  1081. */
  1082. if ( pWinStation->WindowsSubSysProcessId &&
  1083. pMsg->h.ClientId.UniqueProcess != pWinStation->WindowsSubSysProcessId ) {
  1084. ReleaseWinStation( pWinStation );
  1085. return( STATUS_SUCCESS );
  1086. }
  1087. /*
  1088. * If WinStation is already disconnected, then we're done
  1089. */
  1090. if ( !pWinStation->WinStationName[0] ) {
  1091. ReleaseWinStation( pWinStation );
  1092. return( STATUS_SUCCESS );
  1093. }
  1094. /*
  1095. * If busy with something already, don't do this
  1096. */
  1097. if ( pWinStation->Flags ) {
  1098. ReleaseWinStation( pWinStation );
  1099. return( STATUS_CTX_WINSTATION_BUSY );
  1100. }
  1101. /*
  1102. * Save reason/source for this broken connection
  1103. */
  1104. pWinStation->BrokenReason = Reason;
  1105. pWinStation->BrokenSource = m->Source;
  1106. if ( pWinStation->NeverConnected ) {
  1107. pWinStation->StateFlags |= WSF_ST_BROKEN_CONNECTION;
  1108. ReleaseWinStation( pWinStation );
  1109. return( STATUS_SUCCESS );
  1110. }
  1111. /*
  1112. * if any of the following is TRUE;
  1113. * - the session is a Salem 'help assistant' session.
  1114. * - no user is logged on (logon time is 0)
  1115. * - reset is requested
  1116. * - unexpected broken connection and current user is
  1117. * setup to reset on broken connection
  1118. * then queue a reset request
  1119. */
  1120. if (RtlLargeIntegerEqualToZero( pWinStation->LogonTime ) ||
  1121. (Reason == Broken_Terminate) ||
  1122. ((Reason == Broken_Unexpected) && pWinStation->Config.Config.User.fResetBroken) ||
  1123. TSIsSessionHelpSession(pWinStation, NULL)) {
  1124. QueueWinStationReset( pWinStation->LogonId);
  1125. /*
  1126. * Otherwise, disconnect the WinStation
  1127. */
  1128. } else {
  1129. QueueWinStationDisconnect( pWinStation->LogonId );
  1130. }
  1131. /*
  1132. * Release WinStation
  1133. */
  1134. ReleaseWinStation( pWinStation );
  1135. return( STATUS_SUCCESS );
  1136. }
  1137. /*****************************************************************************
  1138. *
  1139. * WinStationIcaReplyMessage
  1140. *
  1141. * API called from Winstation for user response to message box
  1142. *
  1143. * ENTRY:
  1144. * pContext (input)
  1145. * Pointer to our context structure describing the connection.
  1146. *
  1147. * pMsg (input/output)
  1148. * Pointer to the API message, a superset of NT LPC PORT_MESSAGE.
  1149. *
  1150. * EXIT:
  1151. * STATUS_SUCCESS - no error
  1152. *
  1153. ****************************************************************************/
  1154. NTSTATUS
  1155. WinStationIcaReplyMessage( PLPC_CLIENT_CONTEXT pContext,
  1156. PWINSTATION_APIMSG pMsg )
  1157. {
  1158. PWINSTATION pWinStation;
  1159. DBGPRINT(("TERMSRV: WinStationIcaReplyMessage, LogonId=%d\n",
  1160. pContext->ClientLogonId ));
  1161. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationIcaReplyMessage, LogonId=%d\n",
  1162. pContext->ClientLogonId ));
  1163. /*
  1164. * Indicate A reply will be returned to client
  1165. */
  1166. pMsg->WaitForReply = TRUE;
  1167. /*
  1168. * Find and lock client WinStation
  1169. */
  1170. pWinStation = FindWinStationById( pContext->ClientLogonId, FALSE );
  1171. if ( pWinStation == NULL )
  1172. return( STATUS_SUCCESS );
  1173. /*
  1174. * Ensure this is the Win32 subsystem calling
  1175. */
  1176. if ( pWinStation->WindowsSubSysProcessId &&
  1177. pMsg->h.ClientId.UniqueProcess != pWinStation->WindowsSubSysProcessId ) {
  1178. ReleaseWinStation( pWinStation );
  1179. return( STATUS_SUCCESS );
  1180. }
  1181. /*
  1182. * Fill in response
  1183. */
  1184. *pMsg->u.ReplyMessage.pResponse = pMsg->u.ReplyMessage.Response;
  1185. /*
  1186. * Release RPC thread
  1187. */
  1188. NtSetEvent( pMsg->u.ReplyMessage.hEvent, NULL );
  1189. /*
  1190. * Release WinStation
  1191. */
  1192. ReleaseWinStation( pWinStation );
  1193. return( STATUS_SUCCESS );
  1194. }
  1195. /*****************************************************************************
  1196. *
  1197. * WinStationIcaShadowHotkey
  1198. *
  1199. * API called from Winstation that has received a shadow hotkey
  1200. *
  1201. * ENTRY:
  1202. * pContext (input)
  1203. * Pointer to our context structure describing the connection.
  1204. *
  1205. * pMsg (input/output)
  1206. * Pointer to the API message, a superset of NT LPC PORT_MESSAGE.
  1207. *
  1208. * EXIT:
  1209. * STATUS_SUCCESS - no error
  1210. *
  1211. ****************************************************************************/
  1212. NTSTATUS
  1213. WinStationIcaShadowHotkey( PLPC_CLIENT_CONTEXT pContext,
  1214. PWINSTATION_APIMSG pMsg )
  1215. {
  1216. PWINSTATION pWinStation;
  1217. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationIcaShadowHotkey, LogonId=%d\n",
  1218. pContext->ClientLogonId ));
  1219. /*
  1220. * Indicate A reply will be returned to client
  1221. */
  1222. pMsg->WaitForReply = TRUE;
  1223. /*
  1224. * Find and lock client WinStation
  1225. */
  1226. pWinStation = FindWinStationById( pContext->ClientLogonId, FALSE );
  1227. if ( pWinStation == NULL )
  1228. return( STATUS_SUCCESS );
  1229. /*
  1230. * Ensure this is the Win32 subsystem calling
  1231. */
  1232. if ( pWinStation->WindowsSubSysProcessId &&
  1233. pMsg->h.ClientId.UniqueProcess != pWinStation->WindowsSubSysProcessId ) {
  1234. ReleaseWinStation( pWinStation );
  1235. return( STATUS_SUCCESS );
  1236. }
  1237. /*
  1238. * Process the shadow hotkey.
  1239. *
  1240. * If the shadow client is still waiting for the target
  1241. * to connect, then terminate the passthru stack now to break
  1242. * out of the connection wait. Also, set the shadow
  1243. * broken event if it is non-NULL.
  1244. */
  1245. if ( pWinStation->hPassthruStack &&
  1246. pWinStation->ShadowConnectionWait ) {
  1247. IcaStackClose( pWinStation->hPassthruStack );
  1248. pWinStation->hPassthruStack = NULL;
  1249. }
  1250. if ( pWinStation->ShadowBrokenEvent ) {
  1251. NtSetEvent( pWinStation->ShadowBrokenEvent, NULL );
  1252. }
  1253. /*
  1254. * Release WinStation
  1255. */
  1256. ReleaseWinStation( pWinStation );
  1257. return( STATUS_SUCCESS );
  1258. }
  1259. /*******************************************************************************
  1260. *
  1261. * SendWinStationCommand
  1262. *
  1263. * Send a command to a WinStation and optionally wait for a reply.
  1264. *
  1265. * NOTE: This works using a reverse LPC in which the WINSTATION must
  1266. * have sent a "request" to us for work to do. This prevents
  1267. * blocking the ICASRV while waiting on a WINSTATION that
  1268. * could be hung.
  1269. *
  1270. * ENTRY:
  1271. * pWinStation (input)
  1272. * Pointer to WinStation to send command to
  1273. * pMsg (input/output)
  1274. * Pointer to message to send
  1275. * WaitTime (input)
  1276. * Time in seconds to wait for a reply message
  1277. *
  1278. * EXIT:
  1279. * STATUS_SUCCESS - if successful
  1280. *
  1281. ******************************************************************************/
  1282. NTSTATUS
  1283. SendWinStationCommand( PWINSTATION pWinStation,
  1284. PWINSTATION_APIMSG pMsg,
  1285. ULONG WaitTime )
  1286. {
  1287. OBJECT_ATTRIBUTES ObjA;
  1288. COMMAND_ENTRY Command;
  1289. PCOMMAND_ENTRY pCommand;
  1290. NTSTATUS Status;
  1291. BOOLEAN bFreeCommand = FALSE;
  1292. BOOLEAN bTitlenMessageAllocated = FALSE;
  1293. //
  1294. // These are only used by the SendWindowMessage and the
  1295. // BroadcastSystemMessage APIs.
  1296. //
  1297. PVOID pdataBuffer;
  1298. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: SendWinStationCommand, LogonId=%d, Cmd=%s, Timeout=%d\n",
  1299. pWinStation->LogonId,
  1300. WinStationLpcName[pMsg->ApiNumber],
  1301. WaitTime ));
  1302. ASSERT( IsWinStationLockedByCaller( pWinStation ) );
  1303. ASSERT( !(pWinStation->Flags & WSF_LISTEN) );
  1304. /*
  1305. * Initialize the message id for this message
  1306. */
  1307. pMsg->MessageId = InterlockedIncrement(&MessageId);
  1308. pMsg->ReturnedStatus = 0;
  1309. pMsg->WaitForReply = (WaitTime != 0) ? TRUE : FALSE;
  1310. /*
  1311. * If we will wait for a reply, then create an event to wait on.
  1312. * Since we will wait for a response, its OK to use the static
  1313. * COMMAND entry above.
  1314. */
  1315. if ( pMsg->WaitForReply ) {
  1316. pCommand = &Command;
  1317. InitializeObjectAttributes( &ObjA, NULL, 0, NULL, NULL );
  1318. Status = NtCreateEvent( &pCommand->Event, EVENT_ALL_ACCESS, &ObjA,
  1319. NotificationEvent, FALSE );
  1320. if ( !NT_SUCCESS(Status) )
  1321. return( Status );
  1322. pCommand->pMsg = pMsg;
  1323. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: SendWinStationCommand pCommand %p pCommand->pMsg %p\n", pCommand, pCommand->pMsg ));
  1324. /*
  1325. * We will not wait for a reply, but the WinStation is currently busy
  1326. * processing a command. Allocate a dynamic COMMAND entry which will
  1327. * be linked into the the command list and sent when it reaches the
  1328. * head of the list.
  1329. */
  1330. } else if ( pWinStation->Win32CommandPort == NULL ) {
  1331. pCommand = MemAlloc( sizeof(*pCommand) + sizeof(*pMsg) );
  1332. /* makarp; check for MemAlloc failures. #182622 */
  1333. if (!pCommand) {
  1334. return (STATUS_NO_MEMORY);
  1335. }
  1336. pCommand->Event = NULL;
  1337. pCommand->pMsg = (PWINSTATION_APIMSG)(pCommand + 1);
  1338. *pCommand->pMsg = *pMsg;
  1339. Status = STATUS_SUCCESS;
  1340. /*
  1341. * We will not wait for a reply and the WinStation is NOT busy
  1342. * with a command, so there is no need for a COMMAND entry.
  1343. * The current message will be sent below.
  1344. */
  1345. } else {
  1346. pCommand = NULL;
  1347. }
  1348. /*
  1349. * On DoMessage API either copy message to client view or strdup strings.
  1350. */
  1351. if ( pMsg->ApiNumber == SMWinStationDoMessage ) {
  1352. PVOID pTitle;
  1353. PVOID pMessage;
  1354. PLPC_CLIENT_CONTEXT pContext;
  1355. // get winstation context
  1356. if ( (pContext = pWinStation->pWin32Context) == NULL ) {
  1357. TRACE((hTrace,TC_ICASRV,TT_ERROR, "TERMSRV: SendWinStationCommand, ERROR WinStationContext not valid\n" ));
  1358. Status = STATUS_CTX_WINSTATION_NOT_FOUND;
  1359. bFreeCommand = TRUE;
  1360. goto done;
  1361. }
  1362. // validate size of parameters
  1363. if ((pMsg->u.SendMessage.TitleLength + pMsg->u.SendMessage.MessageLength) > pContext->ViewSize ) {
  1364. TRACE((hTrace,TC_ICASRV,TT_ERROR, "TERMSRV: SendWinStationCommand, ERROR Message or Title too long\n" ));
  1365. Status = STATUS_INVALID_PARAMETER;
  1366. bFreeCommand = TRUE;
  1367. goto done;
  1368. }
  1369. // busy? then strdup string else copy to client view
  1370. if ( pWinStation->Win32CommandPort ) {
  1371. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: SendWinStationCommand - WinStation LPC IDLE, process now\n" ));
  1372. // Get pointers to client view of memory
  1373. pTitle = pContext->ViewBase;
  1374. pMessage = (PVOID)((ULONG_PTR)pTitle + pMsg->u.SendMessage.TitleLength);
  1375. // Copy out the pTitle and pMessage strings to client view
  1376. RtlMoveMemory( pTitle, pMsg->u.SendMessage.pTitle, pMsg->u.SendMessage.TitleLength );
  1377. RtlMoveMemory( pMessage, pMsg->u.SendMessage.pMessage, pMsg->u.SendMessage.MessageLength );
  1378. // Update msg
  1379. pMsg->u.SendMessage.pTitle =
  1380. (PVOID)(pContext->ViewRemoteBase);
  1381. pMsg->u.SendMessage.pMessage =
  1382. (PVOID) ((ULONG_PTR)pContext->ViewRemoteBase + pMsg->u.SendMessage.TitleLength);
  1383. }
  1384. else if ( pCommand ) {
  1385. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: SendWinStationCommand - WinStation LPC BUSY, queue for later processing\n" ));
  1386. // Get pointers to temporary memory
  1387. pTitle = MemAlloc( pMsg->u.SendMessage.TitleLength );
  1388. if (pTitle == NULL) {
  1389. Status = STATUS_NO_MEMORY;
  1390. bFreeCommand = TRUE;
  1391. goto done;
  1392. }
  1393. pMessage = MemAlloc( pMsg->u.SendMessage.MessageLength );
  1394. if (pMessage == NULL) {
  1395. Status = STATUS_NO_MEMORY;
  1396. MemFree( pTitle );
  1397. bFreeCommand = TRUE;
  1398. goto done;
  1399. }
  1400. bTitlenMessageAllocated = TRUE;
  1401. // Copy out the pTitle and pMessage strings to temp memory
  1402. RtlMoveMemory( pTitle, pMsg->u.SendMessage.pTitle, pMsg->u.SendMessage.TitleLength );
  1403. RtlMoveMemory( pMessage, pMsg->u.SendMessage.pMessage, pMsg->u.SendMessage.MessageLength );
  1404. // Update msg
  1405. pCommand->pMsg->u.SendMessage.pTitle = pTitle;
  1406. pCommand->pMsg->u.SendMessage.pMessage = pMessage;
  1407. }
  1408. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: SMWinStationDoMessage pTitle %S\n", pTitle ));
  1409. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: SMWinStationDoMessage pMessage %S\n", pMessage ));
  1410. } else if ( pMsg->ApiNumber == SMWinStationShadowStart ||
  1411. pMsg->ApiNumber == SMWinStationShadowCleanup ) {
  1412. PVOID pData;
  1413. PLPC_CLIENT_CONTEXT pContext;
  1414. // get winstation contect
  1415. if ( (pContext = pWinStation->pWin32Context) == NULL ) {
  1416. TRACE((hTrace,TC_ICASRV,TT_ERROR, "TERMSRV: SendWinStationCommand, ERROR WinStationContext not valid\n" ));
  1417. Status = STATUS_CTX_WINSTATION_NOT_FOUND;
  1418. bFreeCommand = TRUE;
  1419. goto done;
  1420. }
  1421. // busy? then strdup string else copy to client view
  1422. if ( pWinStation->Win32CommandPort ) {
  1423. // Get pointers to client view of memory
  1424. pData = pContext->ViewBase;
  1425. // Copy out the ThinwireData to client view
  1426. RtlCopyMemory( pData, pMsg->u.ShadowStart.pThinwireData,
  1427. pMsg->u.ShadowStart.ThinwireDataLength );
  1428. // Update msg
  1429. pMsg->u.ShadowStart.pThinwireData =
  1430. (PVOID) (pContext->ViewRemoteBase);
  1431. }
  1432. else if ( pCommand ) {
  1433. // Get pointers to temporary memory
  1434. pData = MemAlloc( pMsg->u.ShadowStart.ThinwireDataLength );
  1435. if (pData == NULL) {
  1436. Status = STATUS_NO_MEMORY;
  1437. bFreeCommand = TRUE;
  1438. goto done;
  1439. }
  1440. // Copy out the ThinwireData to temp memory
  1441. RtlCopyMemory( pData, pMsg->u.ShadowStart.pThinwireData,
  1442. pMsg->u.ShadowStart.ThinwireDataLength );
  1443. // Update msg
  1444. pCommand->pMsg->u.ShadowStart.pThinwireData = pData;
  1445. }
  1446. }
  1447. else if ( pMsg->ApiNumber == SMWinStationSendWindowMessage )// This msg always has WaitForReply=TRUE
  1448. {
  1449. PLPC_CLIENT_CONTEXT pContext;
  1450. PVOID pView;
  1451. // get winstation context
  1452. if ( (pContext = pWinStation->pWin32Context) == NULL ) {
  1453. TRACE((hTrace,TC_ICASRV,TT_ERROR, "TERMSRV: SendWinStationCommand, ERROR WinStationContext not valid\n" ));
  1454. Status = STATUS_CTX_WINSTATION_NOT_FOUND;
  1455. // @@@
  1456. // Do i need this? : bFreeCommand = TRUE;
  1457. // Since we are waiting for a reply, then we have not allocated memory for pCommand,
  1458. // hence, we don't need to set this flag.
  1459. goto done;
  1460. }
  1461. // validate size of parameters
  1462. if ((pMsg->u.sMsg.bufferSize ) > pContext->ViewSize ) {
  1463. TRACE((hTrace,TC_ICASRV,TT_ERROR, "TERMSRV: SendWinStationCommand, ERROR Message or Title too long\n" ));
  1464. Status = STATUS_INVALID_PARAMETER;
  1465. // @@@
  1466. // Do i need this? : bFreeCommand = TRUE;
  1467. // Since we are waiting for a reply, then we have not allocated memory for pCommand,
  1468. // hence, we don't need to set this flag.
  1469. goto done;
  1470. }
  1471. // if not busy? then copy to client view
  1472. if ( pWinStation->Win32CommandPort ) {
  1473. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: SendWinStationCommand - WinStation LPC IDLE, process now\n" ));
  1474. // Get pointers to client view of memory
  1475. pView = pContext->ViewBase;
  1476. RtlMoveMemory( pView, pMsg->u.sMsg.dataBuffer, pMsg->u.sMsg.bufferSize );
  1477. // Update msg
  1478. pMsg->u.sMsg.dataBuffer = (PVOID)pContext->ViewRemoteBase;
  1479. }
  1480. else if ( pCommand ) // this is on the stack, since this msg always has WaitForReply=TRUE
  1481. {
  1482. pdataBuffer = MemAlloc(pMsg->u.sMsg.bufferSize );
  1483. if ( pdataBuffer == NULL )
  1484. {
  1485. Status = STATUS_NO_MEMORY;
  1486. goto done;
  1487. }
  1488. // copy into tmp memory
  1489. RtlMoveMemory(pdataBuffer, pMsg->u.sMsg.dataBuffer, pMsg->u.sMsg.bufferSize );
  1490. pCommand->pMsg->u.sMsg.dataBuffer = pdataBuffer;
  1491. }
  1492. }
  1493. else if ( pMsg->ApiNumber == SMWinStationBroadcastSystemMessage )// this msg always has WaitForReply=TRUE
  1494. {
  1495. PLPC_CLIENT_CONTEXT pContext;
  1496. PVOID pView;
  1497. // get winstation context
  1498. if ( (pContext = pWinStation->pWin32Context) == NULL ) {
  1499. TRACE((hTrace,TC_ICASRV,TT_ERROR, "TERMSRV: SendWinStationCommand, ERROR WinStationContext not valid\n" ));
  1500. Status = STATUS_CTX_WINSTATION_NOT_FOUND;
  1501. // @@@
  1502. // Do i need this? : bFreeCommand = TRUE;
  1503. // Since we are waiting for a reply, then we have not allocated memory for pCommand,
  1504. // hence, we don't need to set this flag.
  1505. goto done;
  1506. }
  1507. // validate size of parameters
  1508. if ((pMsg->u.bMsg.bufferSize ) > pContext->ViewSize ) {
  1509. TRACE((hTrace,TC_ICASRV,TT_ERROR, "TERMSRV: SendWinStationCommand, ERROR Message or Title too long\n" ));
  1510. Status = STATUS_INVALID_PARAMETER;
  1511. // @@@
  1512. // Do i need this? : bFreeCommand = TRUE;
  1513. // Since we are waiting for a reply, then we have not allocated memory for pCommand,
  1514. // hence, we don't need to set this flag.
  1515. goto done;
  1516. }
  1517. // if not busy? then copy to client view
  1518. if ( pWinStation->Win32CommandPort ) {
  1519. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: SendWinStationCommand - WinStation LPC IDLE, process now\n" ));
  1520. // Get pointers to client view of memory
  1521. pView = pContext->ViewBase;
  1522. RtlMoveMemory( pView, pMsg->u.bMsg.dataBuffer, pMsg->u.bMsg.bufferSize );
  1523. // Update msg
  1524. pMsg->u.bMsg.dataBuffer = (PVOID)pContext->ViewRemoteBase;
  1525. }
  1526. else if ( pCommand ) // this is on the stack, since this msg always has WaitForReply=TRUE
  1527. {
  1528. pdataBuffer = MemAlloc(pMsg->u.bMsg.bufferSize );
  1529. if ( pdataBuffer == NULL )
  1530. {
  1531. Status = STATUS_NO_MEMORY;
  1532. goto done;
  1533. }
  1534. // copy into tmp memory
  1535. RtlMoveMemory(pdataBuffer, pMsg->u.bMsg.dataBuffer, pMsg->u.bMsg.bufferSize );
  1536. pCommand->pMsg->u.bMsg.dataBuffer = pdataBuffer;
  1537. }
  1538. }
  1539. /*
  1540. * If the WinStation is not currently busy processing a command,
  1541. * then send this command now.
  1542. */
  1543. if ( pWinStation->Win32CommandPort ) {
  1544. ASSERT( IsListEmpty( &pWinStation->Win32CommandHead ) );
  1545. /*
  1546. * Send the command msg, but be sure to use the LPC PORT_MESSAGE
  1547. * fields saved from the original msg we received since we are
  1548. * sending the command as an LPC reply message.
  1549. */
  1550. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: SendWinStationCommand, LogonId=%d, sending cmd\n",
  1551. pWinStation->LogonId ));
  1552. pMsg->h = pWinStation->Win32CommandPortMsg;
  1553. Status = NtReplyPort( pWinStation->Win32CommandPort,
  1554. (PPORT_MESSAGE) pMsg );
  1555. pWinStation->Win32CommandPort = NULL;
  1556. if ( !NT_SUCCESS( Status ) )
  1557. goto done;
  1558. }
  1559. /*
  1560. * If we have a command entry, add it to the command list.
  1561. */
  1562. if ( pCommand )
  1563. InsertTailList( &pWinStation->Win32CommandHead, &pCommand->Links );
  1564. /*
  1565. * If we need to wait for a reply, then do it now.
  1566. */
  1567. if ( pMsg->WaitForReply ) {
  1568. ULONG mSecs;
  1569. LARGE_INTEGER Timeout;
  1570. #if DBG
  1571. // if ( (WaitTime != (ULONG)(-1)) && WaitTime < 120 ) // give plenty of time on debug builds
  1572. // WaitTime = 120;
  1573. #endif
  1574. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: SendWinStationCommand, LogonId=%d, waiting for response\n",
  1575. pWinStation->LogonId ));
  1576. if ( WaitTime != (ULONG)(-1) ) {
  1577. mSecs = WaitTime * 1000;
  1578. Timeout = RtlEnlargedIntegerMultiply( mSecs, -10000 );
  1579. }
  1580. UnlockWinStation( pWinStation );
  1581. if ( WaitTime != (ULONG)(-1) ) {
  1582. Status = NtWaitForSingleObject( pCommand->Event, FALSE, &Timeout );
  1583. }
  1584. else {
  1585. DBGPRINT(("Waiting for command with no timeout\n"));
  1586. Status = NtWaitForSingleObject( pCommand->Event, FALSE, NULL );
  1587. }
  1588. if ( !RelockWinStation( pWinStation ) )
  1589. Status = STATUS_CTX_CLOSE_PENDING;
  1590. if ( pCommand->Links.Flink != NULL )
  1591. RemoveEntryList( &pCommand->Links );
  1592. if ( Status == STATUS_SUCCESS )
  1593. Status = pMsg->ReturnedStatus;
  1594. else if ( Status == STATUS_TIMEOUT )
  1595. Status = STATUS_CTX_WINSTATION_BUSY;
  1596. }
  1597. done:
  1598. if ( pCommand ) {
  1599. if ( pCommand->Event ) {
  1600. NtClose( pCommand->Event );
  1601. }
  1602. if ( !pMsg->WaitForReply && bFreeCommand ) {
  1603. // makarp:182622
  1604. if (bTitlenMessageAllocated)
  1605. {
  1606. ASSERT(pCommand->pMsg->u.SendMessage.pTitle);
  1607. ASSERT(pCommand->pMsg->u.SendMessage.pMessage);
  1608. MemFree(pCommand->pMsg->u.SendMessage.pTitle);
  1609. MemFree(pCommand->pMsg->u.SendMessage.pMessage);
  1610. }
  1611. MemFree( pCommand );
  1612. }
  1613. }
  1614. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: SendWinStationCommand, LogonId=%d, Cmd=%s, Status=0x%x\n",
  1615. pWinStation->LogonId,
  1616. WinStationLpcName[pMsg->ApiNumber],
  1617. Status ));
  1618. return( Status );
  1619. }
  1620. NTSTATUS RemoveBadHwnd(ULONG hWnd, ULONG SessionId);
  1621. NTSTATUS
  1622. WinStationWindowInvalid( PLPC_CLIENT_CONTEXT pContext,
  1623. PWINSTATION_APIMSG pMsg )
  1624. {
  1625. ASSERT(pMsg);
  1626. ASSERT(pMsg->ApiNumber == SMWinStationWindowInvalid);
  1627. ASSERT(pMsg->u.WindowInvalid.hWnd);
  1628. UNREFERENCED_PARAMETER(pContext);
  1629. return RemoveBadHwnd(pMsg->u.WindowInvalid.hWnd, pMsg->u.WindowInvalid.SessionId);
  1630. }
  1631. VOID InsertLpcContext(PVOID pContext)
  1632. {
  1633. PTERMSRVLPCCONTEXT pLpcContextEntry = MemAlloc(sizeof(TERMSRVLPCCONTEXT));
  1634. if (pLpcContextEntry != NULL) {
  1635. pLpcContextEntry->pContext = pContext;
  1636. RtlEnterCriticalSection( &ApiThreadLock );
  1637. InsertTailList( &gTermsrvLpcListHead, &pLpcContextEntry->Links );
  1638. RtlLeaveCriticalSection( &ApiThreadLock );
  1639. }
  1640. }
  1641. VOID RemoveLpcContext(PVOID pContext)
  1642. {
  1643. PTERMSRVLPCCONTEXT pLpcContextEntry ;
  1644. PLIST_ENTRY Head, Next;
  1645. BOOL bFoundContext = FALSE;
  1646. Head = &gTermsrvLpcListHead;
  1647. RtlEnterCriticalSection( &ApiThreadLock );
  1648. /*
  1649. * Search the list for a the same context .
  1650. */
  1651. for ( Next = Head->Flink; Next != Head; Next = Next->Flink ) {
  1652. pLpcContextEntry = CONTAINING_RECORD( Next, TERMSRVLPCCONTEXT, Links );
  1653. if ( pLpcContextEntry->pContext == pContext ) {
  1654. RemoveEntryList(&pLpcContextEntry->Links);
  1655. bFoundContext = TRUE;
  1656. break;
  1657. }
  1658. }
  1659. RtlLeaveCriticalSection( &ApiThreadLock );
  1660. if (bFoundContext) {
  1661. MemFree(pLpcContextEntry);
  1662. }
  1663. }
  1664. BOOL GetSessionIdFromLpcContext(PLPC_CLIENT_CONTEXT pContext,
  1665. PULONG pSessionId)
  1666. {
  1667. PTERMSRVLPCCONTEXT pLpcContextEntry ;
  1668. PLIST_ENTRY Head, Next;
  1669. BOOL bFoundContext = FALSE;
  1670. Head = &gTermsrvLpcListHead;
  1671. RtlEnterCriticalSection( &ApiThreadLock );
  1672. /*
  1673. * Search the list for a the same context .
  1674. */
  1675. for ( Next = Head->Flink; Next != Head; Next = Next->Flink ) {
  1676. pLpcContextEntry = CONTAINING_RECORD( Next, TERMSRVLPCCONTEXT, Links );
  1677. if ( pLpcContextEntry->pContext == pContext ) {
  1678. *pSessionId = pContext->ClientLogonId;
  1679. bFoundContext = TRUE;
  1680. break;
  1681. }
  1682. }
  1683. RtlLeaveCriticalSection( &ApiThreadLock );
  1684. return bFoundContext;
  1685. }