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.

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