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.

2575 lines
78 KiB

  1. /*************************************************************************
  2. *
  3. * shadow.c
  4. *
  5. * Citrix routines for supporting shadowing
  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 <winsock.h>
  18. // the highest required size for RDP is 431
  19. #define MODULE_SIZE 512
  20. typedef struct _SHADOW_PARMS {
  21. BOOLEAN ShadowerIsHelpSession; // True if the shadow target is being
  22. // shadowed in a Remote Assistance
  23. // scenario.
  24. ULONG ClientLogonId;
  25. ULONG ClientShadowId;
  26. PWSTR pTargetServerName;
  27. ULONG TargetLogonId;
  28. WINSTATIONCONFIG2 Config;
  29. ICA_STACK_ADDRESS Address;
  30. PVOID pModuleData;
  31. ULONG ModuleDataLength;
  32. PVOID pThinwireData;
  33. ULONG ThinwireDataLength;
  34. HANDLE ImpersonationToken;
  35. WCHAR ClientName[DOMAIN_LENGTH+USERNAME_LENGTH+4];
  36. BOOL fResetShadowMode;
  37. } SHADOW_PARMS, *PSHADOW_PARMS;
  38. /*
  39. * External procedures defined
  40. */
  41. NTSTATUS WinStationShadowWorker( ULONG, PWSTR, ULONG, BYTE, USHORT );
  42. NTSTATUS WinStationShadowTargetSetupWorker( ULONG );
  43. NTSTATUS WinStationShadowTargetWorker( BOOLEAN, BOOL, ULONG, PWINSTATIONCONFIG2, PICA_STACK_ADDRESS,
  44. PVOID, ULONG, PVOID, ULONG, PVOID);
  45. NTSTATUS WinStationStopAllShadows( PWINSTATION );
  46. BOOLEAN WINAPI
  47. _WinStationShadowTargetSetup(
  48. HANDLE hServer,
  49. ULONG LogonId
  50. );
  51. NTSTATUS WINAPI
  52. _WinStationShadowTarget(
  53. HANDLE hServer,
  54. ULONG LogonId,
  55. PWINSTATIONCONFIG2 pConfig,
  56. PICA_STACK_ADDRESS pAddress,
  57. PVOID pModuleData,
  58. ULONG ModuleDataLength,
  59. PVOID pThinwireData,
  60. ULONG ThinwireDataLength,
  61. PVOID pClientName,
  62. ULONG ClientNameLength
  63. );
  64. NTSTATUS
  65. WinStationWinerrorToNtStatus(ULONG ulWinError);
  66. /*
  67. * Internal procedures defined
  68. */
  69. NTSTATUS _CreateShadowAddress( ULONG, PWINSTATIONCONFIG2, PWSTR,
  70. PICA_STACK_ADDRESS, PICA_STACK_ADDRESS );
  71. NTSTATUS _WinStationShadowTargetThread( PVOID );
  72. NTSTATUS
  73. _CheckShadowLoop(
  74. IN ULONG ClientLogonId,
  75. IN PWSTR pTargetServerName,
  76. IN ULONG TargetLogonId
  77. );
  78. /*
  79. * External procedures used.
  80. */
  81. NTSTATUS RpcCheckClientAccess( PWINSTATION, ACCESS_MASK, BOOLEAN );
  82. NTSTATUS WinStationDoDisconnect( PWINSTATION, PRECONNECT_INFO, BOOLEAN bSyncNotify );
  83. NTSTATUS xxxWinStationQueryInformation(ULONG, WINSTATIONINFOCLASS,
  84. PVOID, ULONG, PULONG);
  85. BOOL GetSalemOutbufCount(PDWORD pdwValue);
  86. ULONG UniqueShadowId = 0;
  87. extern WCHAR g_DigProductId[CLIENT_PRODUCT_ID_LENGTH];
  88. /*****************************************************************************
  89. *
  90. * WinStationShadowWorker
  91. *
  92. * Start a Winstation shadow operation
  93. *
  94. * ENTRY:
  95. * ClientLogonId (input)
  96. * client of the shadow
  97. * pTargetServerName (input)
  98. * target server name
  99. * TargetLogonId (input)
  100. * target login id (where the app is running)
  101. * HotkeyVk (input)
  102. * virtual key to press to stop shadow
  103. * HotkeyModifiers (input)
  104. * virtual modifer to press to stop shadow (i.e. shift, control)
  105. *
  106. * EXIT:
  107. * STATUS_SUCCESS - no error
  108. *
  109. ****************************************************************************/
  110. NTSTATUS
  111. WinStationShadowWorker(
  112. IN ULONG ClientLogonId,
  113. IN PWSTR pTargetServerName,
  114. IN ULONG TargetLogonId,
  115. IN BYTE HotkeyVk,
  116. IN USHORT HotkeyModifiers
  117. )
  118. {
  119. PWINSTATION pWinStation;
  120. ULONG Length;
  121. LONG rc;
  122. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  123. OBJECT_ATTRIBUTES ObjA;
  124. HANDLE ClientToken;
  125. HANDLE ImpersonationToken;
  126. PVOID pModuleData;
  127. ULONG ModuleDataLength;
  128. PVOID pThinwireData;
  129. ULONG ThinwireDataLength;
  130. PWINSTATIONCONFIG2 pShadowConfig = NULL;
  131. ICA_STACK_ADDRESS ShadowAddress;
  132. ICA_STACK_ADDRESS RemoteShadowAddress;
  133. ICA_STACK_BROKEN Broken;
  134. ICA_STACK_HOTKEY Hotkey;
  135. WINSTATION_APIMSG msg;
  136. HANDLE hShadowThread;
  137. PSHADOW_PARMS pShadowParms;
  138. HANDLE hTargetThread;
  139. DWORD ThreadId;
  140. PVOID pEndpoint;
  141. ULONG EndpointLength;
  142. LARGE_INTEGER Timeout;
  143. LONG retry;
  144. NTSTATUS WaitStatus;
  145. NTSTATUS TargetStatus;
  146. NTSTATUS Status;
  147. int nFormattedlength;
  148. BOOL bShadowerHelpSession = FALSE;
  149. /*
  150. * Allocate memory
  151. */
  152. pShadowConfig = MemAlloc(sizeof(WINSTATIONCONFIG2));
  153. if (pShadowConfig == NULL) {
  154. Status = STATUS_NO_MEMORY;
  155. return Status;
  156. }
  157. /*
  158. * If target server name is ourself, then clear the target name
  159. */
  160. if ( pTargetServerName ) {
  161. if ( *pTargetServerName ) {
  162. WCHAR ServerName[MAX_COMPUTERNAME_LENGTH+1];
  163. Length = MAX_COMPUTERNAME_LENGTH+1;
  164. GetComputerName( ServerName, &Length );
  165. if ( !_wcsicmp( ServerName, pTargetServerName ) )
  166. pTargetServerName = NULL;
  167. } else {
  168. pTargetServerName = NULL;
  169. }
  170. }
  171. /*
  172. * Verify the target logonid is valid, is currently shadowable,
  173. * and that the caller (client) has shadow access.
  174. */
  175. if ( pTargetServerName == NULL ) {
  176. Status = WinStationShadowTargetSetupWorker( TargetLogonId );
  177. /*
  178. * Otherwise, open the remote targer server and call the shadow target API.
  179. */
  180. } else {
  181. HANDLE hServer;
  182. hServer = WinStationOpenServer( pTargetServerName );
  183. if ( hServer == NULL ) {
  184. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  185. } else {
  186. if (_WinStationShadowTargetSetup( hServer, TargetLogonId ) == FALSE) {
  187. Status = WinStationWinerrorToNtStatus(GetLastError());
  188. } else {
  189. Status = STATUS_SUCCESS;
  190. }
  191. WinStationCloseServer( hServer );
  192. }
  193. }
  194. /*
  195. * Check the status of the setup call.
  196. */
  197. if ( !NT_SUCCESS( Status ) )
  198. goto badsetup;
  199. /*
  200. * Find and lock client WinStation
  201. */
  202. pWinStation = FindWinStationById( ClientLogonId, FALSE );
  203. if ( pWinStation == NULL ) {
  204. Status = STATUS_ACCESS_DENIED;
  205. goto badsetup;
  206. }
  207. /*
  208. * If WinStation is not in the active state (connected and
  209. * a user is logged on), or there is no stack handle,
  210. * then deny the shadow request.
  211. */
  212. if ( pWinStation->State != State_Active ||
  213. pWinStation->hStack == NULL ) {
  214. Status = STATUS_CTX_SHADOW_INVALID;
  215. goto badstate;
  216. }
  217. /*
  218. * If shadower is help session, we already disable screen saver on logon notify
  219. */
  220. bShadowerHelpSession = TSIsSessionHelpSession(pWinStation, NULL);
  221. /*
  222. * Allocate a unique shadow id for this request.
  223. * (This is used by the shadow target thread in order
  224. * to synchronize the return status.)
  225. */
  226. pWinStation->ShadowId = InterlockedIncrement( &UniqueShadowId );
  227. /*
  228. * Set up shadow config structure to use Named Pipe transport driver
  229. */
  230. RtlZeroMemory( pShadowConfig, sizeof(WINSTATIONCONFIG2) );
  231. wcscpy( pShadowConfig->Pd[0].Create.PdName, L"namedpipe" );
  232. pShadowConfig->Pd[0].Create.SdClass = SdNetwork;
  233. wcscpy( pShadowConfig->Pd[0].Create.PdDLL, L"tdpipe" );
  234. pShadowConfig->Pd[0].Create.PdFlag =
  235. PD_TRANSPORT | PD_CONNECTION | PD_FRAME | PD_RELIABLE;
  236. pShadowConfig->Pd[0].Create.OutBufLength = 530;
  237. pShadowConfig->Pd[0].Create.OutBufCount = 6;
  238. //
  239. //344175 Mouse buffer size needs to be increased
  240. //check if this is a help session, if it is read OutBufCount from registry
  241. //
  242. if (bShadowerHelpSession) {
  243. if (!GetSalemOutbufCount((PDWORD)&pShadowConfig->Pd[0].Create.OutBufCount)) {
  244. //
  245. //set the default outbuf count to 25
  246. //we don't want any low water mark for help sessions
  247. //
  248. pShadowConfig->Pd[0].Create.OutBufCount = 25;
  249. }
  250. pShadowConfig->Pd[0].Create.PdFlag |= PD_NOLOW_WATERMARK; //no low water mark
  251. }
  252. pShadowConfig->Pd[0].Create.OutBufDelay = 0;
  253. pShadowConfig->Pd[0].Params.SdClass = SdNetwork;
  254. pShadowConfig->Pd[1].Create.SdClass = SdNone;
  255. /*
  256. * Use same WD as shadowing WinStation
  257. */
  258. pShadowConfig->Wd = pWinStation->Config.Wd;
  259. /*
  260. * Create a shadow address based on the config Pd[0] type.
  261. */
  262. Status = _CreateShadowAddress( pWinStation->ShadowId, pShadowConfig,
  263. pTargetServerName,
  264. &ShadowAddress, &RemoteShadowAddress );
  265. if (!NT_SUCCESS(Status)) {
  266. goto badAddress;
  267. }
  268. /*
  269. * Now impersonate the client and duplicate the impersonation token
  270. * so we can hand it off to the thread doing the target side work.
  271. */
  272. /*
  273. * Duplicate our impersonation token to allow the shadow
  274. * target thread to use it.
  275. */
  276. Status = NtOpenThreadToken( NtCurrentThread(),
  277. TOKEN_ALL_ACCESS,
  278. FALSE,
  279. &ClientToken );
  280. if (!NT_SUCCESS(Status)) {
  281. goto badtoken;
  282. }
  283. InitializeObjectAttributes( &ObjA, NULL, 0L, NULL, NULL );
  284. SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  285. SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
  286. SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  287. SecurityQualityOfService.EffectiveOnly = FALSE;
  288. ObjA.SecurityQualityOfService = &SecurityQualityOfService;
  289. Status = NtDuplicateToken( ClientToken,
  290. TOKEN_IMPERSONATE,
  291. &ObjA,
  292. FALSE,
  293. TokenImpersonation,
  294. &ImpersonationToken );
  295. NtClose( ClientToken );
  296. if (!NT_SUCCESS(Status)) {
  297. goto badtoken;
  298. }
  299. /*
  300. * Query client module data
  301. */
  302. pModuleData = MemAlloc( MODULE_SIZE );
  303. if ( !pModuleData ) {
  304. Status = STATUS_NO_MEMORY;
  305. goto badwddata;
  306. }
  307. // Check for availability
  308. if ( pWinStation->pWsx &&
  309. pWinStation->pWsx->pWsxIcaStackIoControl ) {
  310. Status = pWinStation->pWsx->pWsxIcaStackIoControl(
  311. pWinStation->pWsxContext,
  312. pWinStation->hIca,
  313. pWinStation->hStack,
  314. IOCTL_ICA_STACK_QUERY_MODULE_DATA,
  315. NULL,
  316. 0,
  317. pModuleData,
  318. MODULE_SIZE,
  319. &ModuleDataLength );
  320. }
  321. else {
  322. Status = STATUS_CTX_SHADOW_INVALID;
  323. }
  324. if ( Status == STATUS_BUFFER_TOO_SMALL ) {
  325. MemFree( pModuleData );
  326. pModuleData = MemAlloc( ModuleDataLength );
  327. if ( !pModuleData ) {
  328. Status = STATUS_NO_MEMORY;
  329. goto badwddata;
  330. }
  331. // Check for availability
  332. if ( pWinStation->pWsx &&
  333. pWinStation->pWsx->pWsxIcaStackIoControl ) {
  334. Status = pWinStation->pWsx->pWsxIcaStackIoControl(
  335. pWinStation->pWsxContext,
  336. pWinStation->hIca,
  337. pWinStation->hStack,
  338. IOCTL_ICA_STACK_QUERY_MODULE_DATA,
  339. NULL,
  340. 0,
  341. pModuleData,
  342. ModuleDataLength,
  343. &ModuleDataLength );
  344. }
  345. else {
  346. Status = STATUS_CTX_SHADOW_INVALID;
  347. }
  348. }
  349. if ( !NT_SUCCESS( Status ) ) {
  350. goto badwddata;
  351. }
  352. /*
  353. * Query thinwire module data
  354. */
  355. pThinwireData = MemAlloc( MODULE_SIZE );
  356. if ( !pThinwireData ) {
  357. Status = STATUS_NO_MEMORY;
  358. goto badthinwiredata;
  359. }
  360. Status = IcaChannelIoControl( pWinStation->hIcaThinwireChannel,
  361. IOCTL_ICA_VIRTUAL_QUERY_MODULE_DATA,
  362. NULL,
  363. 0,
  364. pThinwireData,
  365. MODULE_SIZE,
  366. &ThinwireDataLength );
  367. if ( Status == STATUS_BUFFER_TOO_SMALL ) {
  368. MemFree( pThinwireData );
  369. pThinwireData = MemAlloc( ThinwireDataLength );
  370. if ( !pThinwireData ) {
  371. Status = STATUS_NO_MEMORY;
  372. goto badthinwiredata;
  373. }
  374. Status = IcaChannelIoControl( pWinStation->hIcaThinwireChannel,
  375. IOCTL_ICA_VIRTUAL_QUERY_MODULE_DATA,
  376. NULL,
  377. 0,
  378. pThinwireData,
  379. ThinwireDataLength,
  380. &ThinwireDataLength );
  381. }
  382. if ( !NT_SUCCESS( Status ) ) {
  383. goto badthinwiredata;
  384. }
  385. /*
  386. * Create the local passthru stack
  387. */
  388. Status = IcaStackOpen( pWinStation->hIca, Stack_Passthru,
  389. (PROC)WsxStackIoControl, pWinStation,
  390. &pWinStation->hPassthruStack );
  391. if ( !NT_SUCCESS( Status ) )
  392. goto badstackopen;
  393. #ifdef notdef
  394. /*
  395. * Create the client endpoint.
  396. * This call will return the ICA_STACK_ADDRESS we bound to,
  397. * so we can pass it on to the shadow target routine.
  398. */
  399. Status = IcaStackCreateShadowEndpoint( pWinStation->hPassthruStack,
  400. pWinStation->ListenName,
  401. pShadowConfig,
  402. &ShadowAddress,
  403. NULL );
  404. if ( !NT_SUCCESS( Status ) )
  405. goto badshadowendpoint;
  406. #endif
  407. /*
  408. * Create stack broken event and register it
  409. */
  410. Status = NtCreateEvent( &pWinStation->ShadowBrokenEvent, EVENT_ALL_ACCESS,
  411. NULL, NotificationEvent, FALSE );
  412. if ( !NT_SUCCESS( Status ) )
  413. goto badevent;
  414. Broken.BrokenEvent = pWinStation->ShadowBrokenEvent;
  415. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: BrokenEvent(%ld) = %p\n",
  416. pWinStation->LogonId, pWinStation->ShadowBrokenEvent));
  417. // Check for availability
  418. if ( pWinStation->pWsx &&
  419. pWinStation->pWsx->pWsxIcaStackIoControl ) {
  420. Status = pWinStation->pWsx->pWsxIcaStackIoControl(
  421. pWinStation->pWsxContext,
  422. pWinStation->hIca,
  423. pWinStation->hPassthruStack,
  424. IOCTL_ICA_STACK_REGISTER_BROKEN,
  425. &Broken,
  426. sizeof(Broken),
  427. NULL,
  428. 0,
  429. NULL );
  430. }
  431. else {
  432. Status = STATUS_CTX_SHADOW_INVALID;
  433. }
  434. if ( !NT_SUCCESS(Status) )
  435. goto badbroken;
  436. /*
  437. * Register hotkey
  438. */
  439. Hotkey.HotkeyVk = HotkeyVk;
  440. Hotkey.HotkeyModifiers = HotkeyModifiers;
  441. // Check for availability
  442. if ( pWinStation->pWsx &&
  443. pWinStation->pWsx->pWsxIcaStackIoControl ) {
  444. Status = pWinStation->pWsx->pWsxIcaStackIoControl(
  445. pWinStation->pWsxContext,
  446. pWinStation->hIca,
  447. pWinStation->hStack,
  448. IOCTL_ICA_STACK_REGISTER_HOTKEY,
  449. &Hotkey,
  450. sizeof(Hotkey),
  451. NULL,
  452. 0,
  453. NULL );
  454. }
  455. else {
  456. Status = STATUS_CTX_SHADOW_INVALID;
  457. }
  458. if ( !NT_SUCCESS(Status) )
  459. goto badhotkey;
  460. /*
  461. * Before we enable passthru mode, change the WinStation state
  462. */
  463. pWinStation->State = State_Shadow;
  464. NotifySystemEvent( WEVENT_STATECHANGE );
  465. /*
  466. * Tell win32k about passthru mode being enabled
  467. */
  468. msg.ApiNumber = SMWinStationPassthruEnable;
  469. Status = SendWinStationCommand( pWinStation, &msg, 60 );
  470. if ( !NT_SUCCESS( Status ) )
  471. goto badpassthru;
  472. /*
  473. * Allocate a SHADOW_PARMS struct to pass to the target thread
  474. */
  475. pShadowParms = MemAlloc( sizeof(SHADOW_PARMS) );
  476. if ( !pShadowParms ) {
  477. Status = STATUS_NO_MEMORY;
  478. goto badshadowparms;
  479. }
  480. /*
  481. * Create a thread to load the target shadow stack
  482. */
  483. pShadowParms->fResetShadowMode = bShadowerHelpSession; // Only reset if client is HelpAssistant session
  484. pShadowParms->ShadowerIsHelpSession = bShadowerHelpSession ? TRUE : FALSE;
  485. pShadowParms->ClientLogonId = ClientLogonId;
  486. pShadowParms->ClientShadowId = pWinStation->ShadowId;
  487. pShadowParms->pTargetServerName = pTargetServerName;
  488. pShadowParms->TargetLogonId = TargetLogonId;
  489. pShadowParms->Config = *pShadowConfig;
  490. pShadowParms->Address = ShadowAddress;
  491. pShadowParms->pModuleData = pModuleData;
  492. pShadowParms->ModuleDataLength = ModuleDataLength;
  493. pShadowParms->pThinwireData = pThinwireData;
  494. pShadowParms->ThinwireDataLength = ThinwireDataLength;
  495. pShadowParms->ImpersonationToken = ImpersonationToken;
  496. nFormattedlength = _snwprintf(pShadowParms->ClientName,
  497. sizeof(pShadowParms->ClientName) / sizeof(WCHAR),
  498. L"%s\\%s", pWinStation->Domain, pWinStation->UserName);
  499. if (nFormattedlength < 0 || nFormattedlength ==
  500. sizeof(pShadowParms->ClientName) / sizeof(WCHAR)) {
  501. Status = STATUS_INVALID_PARAMETER;
  502. goto badClientName;
  503. }
  504. pWinStation->ShadowTargetStatus = 0;
  505. hTargetThread = CreateThread( NULL,
  506. 0,
  507. (LPTHREAD_START_ROUTINE)_WinStationShadowTargetThread,
  508. pShadowParms,
  509. THREAD_SET_INFORMATION,
  510. &ThreadId );
  511. if ( hTargetThread == NULL ){
  512. Status = STATUS_NO_MEMORY;
  513. goto badthread;
  514. }
  515. pModuleData = NULL; // Target thread will free
  516. pThinwireData = NULL; // Target thread will free
  517. ImpersonationToken = NULL; // Target thread will close
  518. pShadowParms = NULL; // Target thread will free
  519. /*
  520. * Allocate an endpoint buffer
  521. */
  522. EndpointLength = MODULE_SIZE;
  523. pEndpoint = MemAlloc( MODULE_SIZE );
  524. if ( !pEndpoint ) {
  525. Status = STATUS_NO_MEMORY;
  526. goto badmalloc;
  527. }
  528. /*
  529. * Unlock WinStation while we try to connect to the shadow target
  530. */
  531. UnlockWinStation( pWinStation );
  532. /*
  533. * Wait for connection from the shadow target
  534. *
  535. * We must do this in a loop since we don't know how long it
  536. * will take the target side thread to get to the corresponding
  537. * IcaStackConnectionWait() call. In between calls, we delay for
  538. * 1 second, but break out if the ShadowBrokenEvent gets triggered.
  539. */
  540. for ( retry = 0; retry < 35; retry++ ) {
  541. ULONG ReturnedLength;
  542. Status = IcaStackConnectionRequest( pWinStation->hPassthruStack,
  543. pWinStation->ListenName,
  544. pShadowConfig,
  545. &RemoteShadowAddress,
  546. pEndpoint,
  547. EndpointLength,
  548. &ReturnedLength );
  549. if ( Status == STATUS_BUFFER_TOO_SMALL ) {
  550. MemFree( pEndpoint );
  551. pEndpoint = MemAlloc( ReturnedLength );
  552. if ( !pEndpoint ) {
  553. Status = STATUS_NO_MEMORY;
  554. break;
  555. }
  556. EndpointLength = ReturnedLength;
  557. Status = IcaStackConnectionRequest( pWinStation->hPassthruStack,
  558. pWinStation->ListenName,
  559. pShadowConfig,
  560. &RemoteShadowAddress,
  561. pEndpoint,
  562. EndpointLength,
  563. &ReturnedLength );
  564. }
  565. if ( Status != STATUS_OBJECT_NAME_NOT_FOUND )
  566. break;
  567. Timeout = RtlEnlargedIntegerMultiply( 1000, -10000 );
  568. WaitStatus = NtWaitForSingleObject( pWinStation->ShadowBrokenEvent, FALSE, &Timeout );
  569. if ( WaitStatus != STATUS_TIMEOUT )
  570. break;
  571. /*
  572. * If the shadow has already completed, we don't need to continue
  573. * trying to initiate it
  574. */
  575. if (pWinStation->ShadowTargetStatus)
  576. {
  577. break;
  578. }
  579. }
  580. /*
  581. * Now relock the WinStation
  582. */
  583. RelockWinStation( pWinStation );
  584. /*
  585. * Check the status from the wait for connection
  586. */
  587. if ( !NT_SUCCESS( Status ) ) {
  588. // The pipe disconnected before the worker thread can set an error
  589. // code. Wait for worker thread to set error code.
  590. if ( Status == STATUS_PIPE_DISCONNECTED ) {
  591. UnlockWinStation( pWinStation );
  592. Timeout = RtlEnlargedIntegerMultiply( 10000, -10000 );
  593. WaitStatus = NtWaitForSingleObject( hTargetThread,
  594. FALSE, &Timeout );
  595. RelockWinStation( pWinStation );
  596. }
  597. if ( pWinStation->ShadowTargetStatus ) {
  598. Status = pWinStation->ShadowTargetStatus;
  599. }
  600. goto badconnect;
  601. }
  602. #ifdef notdef
  603. /*
  604. * Now accept the shadow target connection
  605. */
  606. // Check for availability
  607. if ( pWinStation->pWsx &&
  608. pWinStation->pWsx->pWsxIcaStackIoControl ) {
  609. Status = pWinStation->pWsx->pWsxIcaStackIoControl(
  610. pWinStation->pWsxContext,
  611. pWinStation->hIca,
  612. pWinStation->hPassthruStack,
  613. IOCTL_ICA_STACK_OPEN_ENDPOINT,
  614. pEndpoint,
  615. EndpointLength,
  616. NULL,
  617. 0,
  618. NULL );
  619. }
  620. else {
  621. Status = STATUS_CTX_SHADOW_INVALID;
  622. }
  623. if ( !NT_SUCCESS( Status ) )
  624. goto badaccept;
  625. #endif
  626. /*
  627. * Enable I/O for the passthru stack
  628. */
  629. // Check for availability
  630. if ( pWinStation->pWsx &&
  631. pWinStation->pWsx->pWsxIcaStackIoControl ) {
  632. Status = pWinStation->pWsx->pWsxIcaStackIoControl(
  633. pWinStation->pWsxContext,
  634. pWinStation->hIca,
  635. pWinStation->hPassthruStack,
  636. IOCTL_ICA_STACK_ENABLE_IO,
  637. NULL,
  638. 0,
  639. NULL,
  640. 0,
  641. NULL );
  642. }
  643. else {
  644. Status = STATUS_CTX_SHADOW_INVALID;
  645. }
  646. if ( !NT_SUCCESS(Status) )
  647. goto badenableio;
  648. /*
  649. * Since we don't do the stack query for a shadow stack,
  650. * simply call an ioctl to mark the stack as connected now.
  651. */
  652. // Check for availability
  653. if ( pWinStation->pWsx &&
  654. pWinStation->pWsx->pWsxIcaStackIoControl ) {
  655. Status = pWinStation->pWsx->pWsxIcaStackIoControl(
  656. pWinStation->pWsxContext,
  657. pWinStation->hIca,
  658. pWinStation->hPassthruStack,
  659. IOCTL_ICA_STACK_SET_CONNECTED,
  660. NULL,
  661. 0,
  662. NULL,
  663. 0,
  664. NULL );
  665. }
  666. else {
  667. Status = STATUS_CTX_SHADOW_INVALID;
  668. }
  669. if ( !NT_SUCCESS( Status ) )
  670. goto badsetconnect;
  671. /*
  672. * Wait for shadow broken event to be triggered
  673. */
  674. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: Waiting for BrokenEvent(%ld) = %p\n",
  675. pWinStation->LogonId, pWinStation->ShadowBrokenEvent));
  676. if( !bShadowerHelpSession ) {
  677. /*
  678. * Notify WinLogon shadow Started.
  679. */
  680. msg.ApiNumber = SMWinStationNotify;
  681. msg.WaitForReply = FALSE;
  682. msg.u.DoNotify.NotifyEvent = WinStation_Notify_DisableScrnSaver;
  683. Status = SendWinStationCommand( pWinStation, &msg, 0 );
  684. //
  685. // Not critical, just performance issue
  686. //
  687. ASSERT( NT_SUCCESS( Status ) );
  688. }
  689. UnlockWinStation( pWinStation );
  690. Status = NtWaitForSingleObject( pWinStation->ShadowBrokenEvent, FALSE, NULL );
  691. RelockWinStation( pWinStation );
  692. if( !bShadowerHelpSession ) {
  693. /*
  694. * Notify WinLogon shadow Ended.
  695. */
  696. msg.ApiNumber = SMWinStationNotify;
  697. msg.WaitForReply = FALSE;
  698. msg.u.DoNotify.NotifyEvent = WinStation_Notify_EnableScrnSaver;
  699. Status = SendWinStationCommand( pWinStation, &msg, 0 );
  700. //
  701. // Not critical, just performance issue
  702. //
  703. ASSERT( NT_SUCCESS( Status ) );
  704. }
  705. /*
  706. * Disable I/O for the passthru stack
  707. */
  708. // Check for availability
  709. if ( pWinStation->pWsx &&
  710. pWinStation->pWsx->pWsxIcaStackIoControl ) {
  711. Status = pWinStation->pWsx->pWsxIcaStackIoControl(
  712. pWinStation->pWsxContext,
  713. pWinStation->hIca,
  714. pWinStation->hPassthruStack,
  715. IOCTL_ICA_STACK_DISABLE_IO,
  716. NULL,
  717. 0,
  718. NULL,
  719. 0,
  720. NULL );
  721. }
  722. else {
  723. Status = STATUS_CTX_SHADOW_INVALID;
  724. }
  725. ASSERT( NT_SUCCESS( Status ) );
  726. /*
  727. * Tell win32k about passthru mode being disabled
  728. */
  729. msg.ApiNumber = SMWinStationPassthruDisable;
  730. Status = SendWinStationCommand( pWinStation, &msg, 60 );
  731. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: Passthru mode disabled\n"));
  732. //ASSERT( NT_SUCCESS( Status ) );
  733. /*
  734. * Restore WinStation state
  735. */
  736. if ( pWinStation->State == State_Shadow ) {
  737. pWinStation->State = State_Active;
  738. NotifySystemEvent( WEVENT_STATECHANGE );
  739. }
  740. /*
  741. * Turn off hotkey registration
  742. */
  743. RtlZeroMemory( &Hotkey, sizeof(Hotkey) );
  744. if ( pWinStation->hStack ) {
  745. // Check for availability
  746. if ( pWinStation->pWsx &&
  747. pWinStation->pWsx->pWsxIcaStackIoControl ) {
  748. Status = pWinStation->pWsx->pWsxIcaStackIoControl(
  749. pWinStation->pWsxContext,
  750. pWinStation->hIca,
  751. pWinStation->hStack,
  752. IOCTL_ICA_STACK_REGISTER_HOTKEY,
  753. &Hotkey,
  754. sizeof(Hotkey),
  755. NULL,
  756. 0,
  757. NULL );
  758. }
  759. else {
  760. Status = STATUS_CTX_SHADOW_INVALID;
  761. }
  762. ASSERT( NT_SUCCESS( Status ) );
  763. }
  764. /*
  765. * Close broken event and passthru stack
  766. */
  767. NtClose( pWinStation->ShadowBrokenEvent );
  768. pWinStation->ShadowBrokenEvent = NULL;
  769. if ( pWinStation->hPassthruStack ) {
  770. IcaStackConnectionClose( pWinStation->hPassthruStack,
  771. pShadowConfig,
  772. pEndpoint,
  773. EndpointLength );
  774. IcaStackClose( pWinStation->hPassthruStack );
  775. pWinStation->hPassthruStack = NULL;
  776. }
  777. MemFree( pEndpoint );
  778. /*
  779. * Now give target thread a chance to exit. If it fails to exit within the
  780. * allotted time period we just allow it to orphan and close its handle so
  781. * it will be destroyed when it finally does exit. This can occur in
  782. * highly loaded stress situations and is not part of normal execution.
  783. */
  784. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: Waiting for target thread to exit\n"));
  785. UnlockWinStation( pWinStation );
  786. Timeout = RtlEnlargedIntegerMultiply( 5000, -10000 );
  787. WaitStatus = NtWaitForSingleObject( hTargetThread, FALSE, &Timeout );
  788. NtClose( hTargetThread );
  789. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: Target thread exit status: %lx\n",
  790. WaitStatus));
  791. /*
  792. * Relock WinStation and get target thread exit status
  793. */
  794. RelockWinStation( pWinStation );
  795. TargetStatus = pWinStation->ShadowTargetStatus;
  796. /*
  797. * If there is a shadow done event, then signal the waiter now
  798. */
  799. if ( pWinStation->ShadowDoneEvent )
  800. SetEvent( pWinStation->ShadowDoneEvent );
  801. /*
  802. * Release winstation
  803. */
  804. ReleaseWinStation( pWinStation );
  805. if (pShadowConfig != NULL) {
  806. MemFree(pShadowConfig);
  807. pShadowConfig = NULL;
  808. }
  809. return( TargetStatus );
  810. /*=============================================================================
  811. == Error returns
  812. =============================================================================*/
  813. badsetconnect:
  814. if ( pWinStation->hPassthruStack ) {
  815. // Check for availability
  816. if ( pWinStation->pWsx &&
  817. pWinStation->pWsx->pWsxIcaStackIoControl ) {
  818. (void) pWinStation->pWsx->pWsxIcaStackIoControl(
  819. pWinStation->pWsxContext,
  820. pWinStation->hIca,
  821. pWinStation->hPassthruStack,
  822. IOCTL_ICA_STACK_DISABLE_IO,
  823. NULL,
  824. 0,
  825. NULL,
  826. 0,
  827. NULL );
  828. }
  829. }
  830. badenableio:
  831. #ifdef notdef
  832. badaccept:
  833. #endif
  834. if ( pWinStation->hPassthruStack ) {
  835. IcaStackConnectionClose( pWinStation->hPassthruStack,
  836. pShadowConfig,
  837. pEndpoint,
  838. EndpointLength );
  839. }
  840. badconnect:
  841. if ( pEndpoint )
  842. MemFree( pEndpoint );
  843. badmalloc:
  844. UnlockWinStation( pWinStation );
  845. //Timeout = RtlEnlargedIntegerMultiply( 5000, -10000 );
  846. //WaitStatus = NtWaitForSingleObject( hTargetThread, FALSE, &Timeout );
  847. //ASSERT( WaitStatus == STATUS_SUCCESS );
  848. NtClose( hTargetThread );
  849. /*
  850. * Relock WinStation and get target thread exit status
  851. */
  852. RelockWinStation( pWinStation );
  853. if ( pWinStation->ShadowTargetStatus )
  854. Status = pWinStation->ShadowTargetStatus;
  855. badthread:
  856. badClientName:
  857. if ( pShadowParms )
  858. MemFree( pShadowParms );
  859. badshadowparms:
  860. msg.ApiNumber = SMWinStationPassthruDisable;
  861. SendWinStationCommand( pWinStation, &msg, 60 );
  862. badpassthru:
  863. if ( pWinStation->State == State_Shadow ) {
  864. pWinStation->State = State_Active;
  865. NotifySystemEvent( WEVENT_STATECHANGE );
  866. }
  867. RtlZeroMemory( &Hotkey, sizeof(Hotkey) );
  868. // Check for availability
  869. if ( pWinStation->pWsx &&
  870. pWinStation->pWsx->pWsxIcaStackIoControl && pWinStation->hStack) {
  871. (void) pWinStation->pWsx->pWsxIcaStackIoControl(
  872. pWinStation->pWsxContext,
  873. pWinStation->hIca,
  874. pWinStation->hStack,
  875. IOCTL_ICA_STACK_REGISTER_HOTKEY,
  876. &Hotkey,
  877. sizeof(Hotkey),
  878. NULL,
  879. 0,
  880. NULL );
  881. }
  882. badhotkey:
  883. badbroken:
  884. NtClose( pWinStation->ShadowBrokenEvent );
  885. pWinStation->ShadowBrokenEvent = NULL;
  886. badevent:
  887. #ifdef notdef
  888. badshadowendpoint:
  889. #endif
  890. if ( pWinStation->hPassthruStack ) {
  891. IcaStackClose( pWinStation->hPassthruStack );
  892. pWinStation->hPassthruStack = NULL;
  893. }
  894. badstackopen:
  895. badthinwiredata:
  896. if ( pThinwireData )
  897. MemFree( pThinwireData );
  898. badwddata:
  899. if ( pModuleData )
  900. MemFree( pModuleData );
  901. if ( ImpersonationToken )
  902. NtClose( ImpersonationToken );
  903. badAddress:
  904. badtoken:
  905. badstate:
  906. ReleaseWinStation( pWinStation );
  907. badsetup:
  908. if (pShadowConfig != NULL) {
  909. MemFree(pShadowConfig);
  910. pShadowConfig = NULL;
  911. }
  912. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationShadowWorker, Status=0x%x\n", Status ));
  913. return( Status );
  914. }
  915. /*****************************************************************************
  916. *
  917. * WinStationShadowTargetSetupWorker
  918. *
  919. * Setup the target side of a Winstation shadow operation
  920. *
  921. * ENTRY:
  922. * LogonId (input)
  923. * client of the shadow
  924. *
  925. *
  926. * EXIT:
  927. * STATUS_SUCCESS - no error
  928. *
  929. ****************************************************************************/
  930. NTSTATUS
  931. WinStationShadowTargetSetupWorker(
  932. IN ULONG TargetLogonId )
  933. {
  934. PWINSTATION pWinStation;
  935. NTSTATUS Status;
  936. /*
  937. * Find and lock target WinStation
  938. */
  939. pWinStation = FindWinStationById( TargetLogonId, FALSE );
  940. if ( pWinStation == NULL ) {
  941. return( STATUS_ACCESS_DENIED );
  942. }
  943. /*
  944. * Check the target WinStation state. We only allow shadow of
  945. * active (connected, logged on) WinStations.
  946. */
  947. if ( pWinStation->State != State_Active ) {
  948. Status = STATUS_CTX_SHADOW_INVALID;
  949. goto shadowinvalid;
  950. }
  951. /*
  952. * Stop attempts to shadow an RDP session that is already shadowed.
  953. * RDP stacks don't support that yet.
  954. * TODO: Add support for multiple RDP shadows.
  955. */
  956. if ((pWinStation->Config).Wd.WdFlag & WDF_TSHARE)
  957. {
  958. if ( !IsListEmpty( &pWinStation->ShadowHead ) ) {
  959. Status = STATUS_CTX_SHADOW_DENIED;
  960. goto shadowdenied;
  961. }
  962. }
  963. /*
  964. * Verify that client has WINSTATION_SHADOW access to the target WINSTATION
  965. */
  966. Status = RpcCheckClientAccess( pWinStation, WINSTATION_SHADOW, TRUE );
  967. if ( !NT_SUCCESS( Status ) )
  968. goto shadowinvalid;
  969. ReleaseWinStation( pWinStation );
  970. return( STATUS_SUCCESS );
  971. /*=============================================================================
  972. == Error returns
  973. =============================================================================*/
  974. shadowinvalid:
  975. shadowdenied:
  976. ReleaseWinStation( pWinStation );
  977. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationShadowTargetSetupWorker, Status=0x%x\n", Status ));
  978. return( Status );
  979. }
  980. /*****************************************************************************
  981. *
  982. * WinStationShadowTargetWorker
  983. *
  984. * Start the target side of a Winstation shadow operation
  985. *
  986. * ENTRY:
  987. * fResetShadowSetting(input)
  988. * Reset session shadow class back to original value
  989. * ShadowerIsHelpSession
  990. * true if the shadowing session is logged in as help assistant.
  991. * LogonId (input)
  992. * client of the shadow
  993. * pConfig (input)
  994. * pointer to WinStation config data (for shadow stack)
  995. * pAddress (input)
  996. * address of shadow client
  997. * pModuleData (input)
  998. * pointer to client module data
  999. * ModuleDataLength (input)
  1000. * length of client module data
  1001. * pThinwireData (input)
  1002. * pointer to thinwire module data
  1003. * ThinwireDataLength (input)
  1004. * length of thinwire module data
  1005. * pClientName (input)
  1006. * pointer to client name string (domain/username)
  1007. *
  1008. *
  1009. * EXIT:
  1010. * STATUS_SUCCESS - no error
  1011. *
  1012. ****************************************************************************/
  1013. NTSTATUS
  1014. WinStationShadowTargetWorker(
  1015. IN BOOLEAN ShadowerIsHelpSession,
  1016. IN BOOL fResetShadowSetting,
  1017. IN ULONG TargetLogonId,
  1018. IN PWINSTATIONCONFIG2 pConfig,
  1019. IN PICA_STACK_ADDRESS pAddress,
  1020. IN PVOID pModuleData,
  1021. IN ULONG ModuleDataLength,
  1022. IN PVOID pThinwireData,
  1023. IN ULONG ThinwireDataLength,
  1024. IN PVOID pClientName)
  1025. {
  1026. PWINSTATION pWinStation;
  1027. WINSTATION_APIMSG msg;
  1028. ULONG ShadowResponse;
  1029. OBJECT_ATTRIBUTES ObjA;
  1030. PSHADOW_INFO pShadow;
  1031. ICA_STACK_BROKEN Broken;
  1032. NTSTATUS Status, Status2, EndStatus = STATUS_SUCCESS;
  1033. BOOLEAN fConcurrentLicense = FALSE;
  1034. DWORD ProtocolMask;
  1035. BOOLEAN fChainedDD = FALSE;
  1036. int cchTitle, cchMessage;
  1037. ULONG shadowIoctlCode;
  1038. HANDLE hIca;
  1039. HANDLE hStack;
  1040. PWSEXTENSION pWsx;
  1041. PVOID pWsxContext;
  1042. BOOL bResetStateFlags = FALSE;
  1043. HANDLE ChannelHandle;
  1044. /*
  1045. * Find and lock target WinStation
  1046. */
  1047. pWinStation = FindWinStationById( TargetLogonId, FALSE );
  1048. if ( pWinStation == NULL ) {
  1049. Status = STATUS_ACCESS_DENIED;
  1050. goto done;
  1051. }
  1052. //
  1053. // save current the console winstation parameters and
  1054. // set them to the global values.
  1055. //
  1056. if (pWinStation->fOwnsConsoleTerminal) {
  1057. hIca = pWinStation->hIca;
  1058. hStack = pWinStation->hStack;
  1059. pWsx = pWinStation->pWsx;
  1060. pWsxContext = pWinStation->pWsxContext;
  1061. }
  1062. /*
  1063. * Check the target WinStation state. We only allow shadow of
  1064. * active (connected, logged on) WinStations.
  1065. */
  1066. if ( pWinStation->State != State_Active ) {
  1067. // the line below is the fix for bug #230870
  1068. Status = STATUS_CTX_SHADOW_INVALID;
  1069. goto shadowinvalid;
  1070. }
  1071. /*
  1072. * Check if we are shadowing the same protocol winstation or not.
  1073. * But let any shadow happen if it's the console and it isn't being shadowed.
  1074. */
  1075. if (!(pWinStation->fOwnsConsoleTerminal && IsListEmpty( &pWinStation->ShadowHead ))) {
  1076. ProtocolMask=WDF_ICA|WDF_TSHARE;
  1077. if (((pConfig->Wd).WdFlag & ProtocolMask) != ((pWinStation->Config).Wd.WdFlag & ProtocolMask))
  1078. {
  1079. Status=STATUS_CTX_SHADOW_INVALID;
  1080. goto shadowinvalid;
  1081. }
  1082. }
  1083. //
  1084. // Stop attempts to shadow an RDP session that is already shadowed.
  1085. // RDP stacks don't support that yet.
  1086. //
  1087. if( pWinStation->fOwnsConsoleTerminal || ((pWinStation->Config).Wd.WdFlag & WDF_TSHARE ))
  1088. {
  1089. if ( pWinStation->StateFlags & WSF_ST_SHADOW ) {
  1090. //
  1091. // Bug 195616, we release winstation lock when
  1092. // waiting for user to accept/deny shadow request,
  1093. // another thread can come in and weird thing can
  1094. // happen
  1095. Status = STATUS_CTX_SHADOW_DENIED;
  1096. goto shadowdenied;
  1097. }
  1098. pWinStation->StateFlags |= WSF_ST_SHADOW;
  1099. bResetStateFlags = TRUE;
  1100. }
  1101. /*
  1102. * Check shadowing options
  1103. */
  1104. switch ( pWinStation->Config.Config.User.Shadow ) {
  1105. WCHAR szTitle[32];
  1106. WCHAR szMsg2[256];
  1107. WCHAR ShadowMsg[256];
  1108. /*
  1109. * If shadowing is disabled, then deny this request
  1110. */
  1111. case Shadow_Disable :
  1112. Status = STATUS_CTX_SHADOW_DISABLED;
  1113. goto shadowinvalid;
  1114. break;
  1115. /*
  1116. * If one of the Notify shadow options is set,
  1117. * then ask for permission from session being shadowed.
  1118. * But deny the shadow if this WinStation is currently
  1119. * disconnected (i.e. there is no user to answer the request).
  1120. */
  1121. case Shadow_EnableInputNotify :
  1122. case Shadow_EnableNoInputNotify :
  1123. if ( pWinStation->State == State_Disconnected ) {
  1124. Status = STATUS_CTX_SHADOW_INVALID;
  1125. goto shadowinvalid;
  1126. }
  1127. cchTitle = LoadString( hModuleWin, STR_CITRIX_SHADOW_TITLE, szTitle, sizeof(szTitle)/sizeof(WCHAR));
  1128. cchMessage = LoadString( hModuleWin, STR_CITRIX_SHADOW_MSG_2, szMsg2, sizeof(szMsg2)/sizeof(WCHAR));
  1129. if ((cchMessage == 0) || (cchMessage == sizeof(szMsg2)/sizeof(WCHAR))) {
  1130. Status = STATUS_CTX_SHADOW_INVALID;
  1131. goto shadowinvalid;
  1132. }
  1133. cchMessage = _snwprintf( ShadowMsg, sizeof(ShadowMsg)/sizeof(WCHAR), L" %s %s", pClientName, szMsg2 );
  1134. if ((cchMessage <= 0) || (cchMessage == sizeof(ShadowMsg)/sizeof(WCHAR))) {
  1135. Status = STATUS_CTX_SHADOW_INVALID;
  1136. goto shadowinvalid;
  1137. }
  1138. /*
  1139. * Send message and wait for reply
  1140. */
  1141. msg.u.SendMessage.pTitle = szTitle;
  1142. msg.u.SendMessage.TitleLength = (cchTitle+1) * sizeof(WCHAR);
  1143. msg.u.SendMessage.pMessage = ShadowMsg;
  1144. msg.u.SendMessage.MessageLength = (cchMessage+1) * sizeof(WCHAR);
  1145. msg.u.SendMessage.Style = MB_YESNO | MB_DEFBUTTON2 | MB_ICONQUESTION;
  1146. msg.u.SendMessage.Timeout = 30;
  1147. msg.u.SendMessage.DoNotWait = FALSE;
  1148. msg.u.SendMessage.pResponse = &ShadowResponse;
  1149. msg.ApiNumber = SMWinStationDoMessage;
  1150. /*
  1151. * Create wait event
  1152. */
  1153. InitializeObjectAttributes( &ObjA, NULL, 0, NULL, NULL );
  1154. Status = NtCreateEvent( &msg.u.SendMessage.hEvent, EVENT_ALL_ACCESS, &ObjA,
  1155. NotificationEvent, FALSE );
  1156. if ( !NT_SUCCESS(Status) ) {
  1157. goto shadowinvalid;
  1158. }
  1159. /*
  1160. * Initialize response to IDTIMEOUT
  1161. */
  1162. ShadowResponse = IDTIMEOUT;
  1163. /*
  1164. * Tell the WinStation to display the message box
  1165. */
  1166. Status = SendWinStationCommand( pWinStation, &msg, 0 );
  1167. /*
  1168. * Wait for response
  1169. */
  1170. if ( Status == STATUS_SUCCESS ) {
  1171. TRACE((hTrace,TC_ICASRV,TT_API1, "WinStationSendMessage: wait for response\n" ));
  1172. UnlockWinStation( pWinStation );
  1173. Status = NtWaitForSingleObject( msg.u.SendMessage.hEvent, FALSE, NULL );
  1174. if ( !RelockWinStation( pWinStation ) ) {
  1175. Status = STATUS_CTX_CLOSE_PENDING;
  1176. }
  1177. TRACE((hTrace,TC_ICASRV,TT_API1, "WinStationSendMessage: got response %u\n", ShadowResponse ));
  1178. NtClose( msg.u.SendMessage.hEvent );
  1179. }
  1180. else
  1181. {
  1182. /* makarp; close the event in case of SendWinStationCommand failure as well. #182792 */
  1183. NtClose( msg.u.SendMessage.hEvent );
  1184. }
  1185. if ( Status == STATUS_SUCCESS && ShadowResponse != IDYES )
  1186. Status = STATUS_CTX_SHADOW_DENIED;
  1187. /*
  1188. * Check again the target WinStation state as the user could logoff.
  1189. * We only allow shadow of active (connected, logged on) WinStations.
  1190. */
  1191. if ( Status == STATUS_SUCCESS && pWinStation->State != State_Active ) {
  1192. Status = STATUS_CTX_SHADOW_INVALID;
  1193. }
  1194. if ( Status != STATUS_SUCCESS ) {
  1195. goto shadowinvalid;
  1196. }
  1197. break;
  1198. }
  1199. /*
  1200. * The shadow request is accepted: for the console session, we now need
  1201. * to chain in the DD or there won't be much output to shadow
  1202. */
  1203. TRACE((hTrace,TC_ICASRV,TT_API3, "TERMSRV: Logon ID %ld\n",
  1204. pWinStation->LogonId ));
  1205. /*
  1206. * If the session is connected to the local console, we need to load
  1207. * the chained shadow display driver before starting the shadoe sequence
  1208. */
  1209. if (pWinStation->fOwnsConsoleTerminal)
  1210. {
  1211. Status = ConsoleShadowStart( pWinStation, pConfig, pModuleData, ModuleDataLength );
  1212. if (NT_SUCCESS(Status))
  1213. {
  1214. fChainedDD = TRUE;
  1215. TRACE((hTrace,TC_ICASRV,TT_API3, "TERMSRV: success\n"));
  1216. }
  1217. else
  1218. {
  1219. TRACE((hTrace,TC_ICASRV,TT_API3, "TERMSRV: ConsoleConnect failed 0x%x\n", Status));
  1220. goto shadowinvalid;
  1221. }
  1222. }
  1223. /*
  1224. * Allocate shadow data structure
  1225. */
  1226. pShadow = MemAlloc( sizeof(*pShadow) );
  1227. if ( pShadow == NULL ) {
  1228. Status = STATUS_NO_MEMORY;
  1229. goto shadowinvalid;
  1230. }
  1231. /*
  1232. * Create shadow stack
  1233. */
  1234. Status = IcaStackOpen( pWinStation->hIca, Stack_Shadow,
  1235. (PROC)WsxStackIoControl, pWinStation,
  1236. &pShadow->hStack );
  1237. if ( !NT_SUCCESS(Status) )
  1238. goto badopen;
  1239. /*
  1240. * Create stack broken event and register it
  1241. */
  1242. Status = NtCreateEvent( &pShadow->hBrokenEvent, EVENT_ALL_ACCESS,
  1243. NULL, NotificationEvent, FALSE );
  1244. if ( !NT_SUCCESS( Status ) )
  1245. goto badevent;
  1246. Broken.BrokenEvent = pShadow->hBrokenEvent;
  1247. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: BrokenEvent(%ld) = %p\n",
  1248. pWinStation->LogonId, pShadow->hBrokenEvent));
  1249. // Check for availability
  1250. if ( pWinStation->pWsx &&
  1251. pWinStation->pWsx->pWsxIcaStackIoControl ) {
  1252. Status = pWinStation->pWsx->pWsxIcaStackIoControl(
  1253. pWinStation->pWsxContext,
  1254. pWinStation->hIca,
  1255. pShadow->hStack,
  1256. IOCTL_ICA_STACK_REGISTER_BROKEN,
  1257. &Broken,
  1258. sizeof(Broken),
  1259. NULL,
  1260. 0,
  1261. NULL );
  1262. }
  1263. else {
  1264. Status = STATUS_CTX_SHADOW_INVALID;
  1265. }
  1266. if ( !NT_SUCCESS(Status) )
  1267. goto badbroken;
  1268. /*
  1269. * Add the shadow structure to the shadow list for the WinStation
  1270. */
  1271. InsertTailList( &pWinStation->ShadowHead, &pShadow->Links );
  1272. /*
  1273. * Allocate an endpoint buffer
  1274. */
  1275. pShadow->pEndpoint = MemAlloc( MODULE_SIZE );
  1276. if ( pShadow->pEndpoint == NULL ) {
  1277. Status = STATUS_NO_MEMORY;
  1278. goto badendpoint;
  1279. }
  1280. /*
  1281. * Unlock WinStation while we attempt to connect to the client
  1282. * side of the shadow.
  1283. */
  1284. UnlockWinStation( pWinStation );
  1285. /*
  1286. * Connect to client side of shadow
  1287. */
  1288. Status = IcaStackConnectionWait ( pShadow->hStack,
  1289. pWinStation->ListenName,
  1290. pConfig,
  1291. pAddress,
  1292. pShadow->pEndpoint,
  1293. MODULE_SIZE,
  1294. &pShadow->EndpointLength );
  1295. if ( Status == STATUS_BUFFER_TOO_SMALL ) {
  1296. MemFree( pShadow->pEndpoint );
  1297. pShadow->pEndpoint = MemAlloc( pShadow->EndpointLength );
  1298. if ( pShadow->pEndpoint == NULL ) {
  1299. Status = STATUS_NO_MEMORY;
  1300. RelockWinStation( pWinStation );
  1301. goto badendpoint;
  1302. }
  1303. Status = IcaStackConnectionWait ( pShadow->hStack,
  1304. pWinStation->ListenName,
  1305. pConfig,
  1306. pAddress,
  1307. pShadow->pEndpoint,
  1308. pShadow->EndpointLength,
  1309. &pShadow->EndpointLength );
  1310. }
  1311. if ( !NT_SUCCESS(Status) ) {
  1312. RelockWinStation( pWinStation );
  1313. goto badconnect;
  1314. }
  1315. /*
  1316. * Relock the WinStation.
  1317. * If the WinStation is going away, then bail out.
  1318. */
  1319. if ( !RelockWinStation( pWinStation ) ) {
  1320. Status = STATUS_CTX_CLOSE_PENDING;
  1321. goto closing;
  1322. }
  1323. /*
  1324. * Now accept the shadow target connection
  1325. */
  1326. // Check for availability
  1327. if (pWinStation->pWsx &&
  1328. pWinStation->pWsx->pWsxIcaStackIoControl) {
  1329. Status = pWinStation->pWsx->pWsxIcaStackIoControl(
  1330. pWinStation->pWsxContext,
  1331. pWinStation->hIca,
  1332. pShadow->hStack,
  1333. IOCTL_ICA_STACK_OPEN_ENDPOINT,
  1334. pShadow->pEndpoint,
  1335. pShadow->EndpointLength,
  1336. NULL,
  1337. 0,
  1338. NULL);
  1339. }
  1340. else {
  1341. Status = STATUS_CTX_SHADOW_INVALID;
  1342. }
  1343. if (!NT_SUCCESS(Status))
  1344. goto PostCreateConnection;
  1345. /*
  1346. * If user is configured to permit shadow input,
  1347. * then enable shadow input on the keyboard/mouse channels,
  1348. * if not permitting shadow input, disable keyboard/mouse
  1349. * channels.
  1350. */
  1351. switch ( pWinStation->Config.Config.User.Shadow ) {
  1352. case Shadow_EnableInputNotify :
  1353. case Shadow_EnableInputNoNotify :
  1354. shadowIoctlCode = IOCTL_ICA_CHANNEL_ENABLE_SHADOW;
  1355. break;
  1356. case Shadow_EnableNoInputNotify :
  1357. case Shadow_EnableNoInputNoNotify :
  1358. shadowIoctlCode = IOCTL_ICA_CHANNEL_DISABLE_SHADOW;
  1359. break;
  1360. default:
  1361. Status = STATUS_INVALID_PARAMETER;
  1362. }
  1363. if( !NT_SUCCESS(Status) )
  1364. goto PostCreateConnection;
  1365. Status = IcaChannelOpen( pWinStation->hIca,
  1366. Channel_Keyboard,
  1367. NULL,
  1368. &ChannelHandle );
  1369. if( !NT_SUCCESS( Status ) )
  1370. goto PostCreateConnection;
  1371. Status = IcaChannelIoControl( ChannelHandle,
  1372. shadowIoctlCode,
  1373. NULL, 0, NULL, 0, NULL );
  1374. ASSERT( NT_SUCCESS( Status ) );
  1375. IcaChannelClose( ChannelHandle );
  1376. if( !NT_SUCCESS( Status ) )
  1377. goto PostCreateConnection;
  1378. Status = IcaChannelOpen( pWinStation->hIca,
  1379. Channel_Mouse,
  1380. NULL,
  1381. &ChannelHandle );
  1382. if ( !NT_SUCCESS( Status ) )
  1383. goto PostCreateConnection;
  1384. Status = IcaChannelIoControl( ChannelHandle,
  1385. shadowIoctlCode,
  1386. NULL, 0, NULL, 0, NULL );
  1387. ASSERT( NT_SUCCESS( Status ) );
  1388. IcaChannelClose( ChannelHandle );
  1389. if( !NT_SUCCESS( Status ) )
  1390. goto PostCreateConnection;
  1391. /*
  1392. * Tell win32k about the pending shadow operation
  1393. */
  1394. msg.ApiNumber = SMWinStationShadowSetup;
  1395. Status = SendWinStationCommand( pWinStation, &msg, 60 );
  1396. if ( !NT_SUCCESS( Status ) )
  1397. goto badsetup;
  1398. /*
  1399. * Since we don't do the stack query for a shadow stack,
  1400. * simply call an ioctl to mark the stack as connected now.
  1401. */
  1402. // Check for availability
  1403. if (pWinStation->pWsx &&
  1404. pWinStation->pWsx->pWsxIcaStackIoControl) {
  1405. Status = pWinStation->pWsx->pWsxIcaStackIoControl(
  1406. pWinStation->pWsxContext,
  1407. pWinStation->hIca,
  1408. pShadow->hStack,
  1409. IOCTL_ICA_STACK_SET_CONNECTED,
  1410. pModuleData,
  1411. ModuleDataLength,
  1412. NULL,
  1413. 0,
  1414. NULL);
  1415. }
  1416. else {
  1417. Status = STATUS_CTX_SHADOW_INVALID;
  1418. }
  1419. if (!NT_SUCCESS(Status))
  1420. goto badsetconnect;
  1421. /*
  1422. * Enable I/O for the shadow stack
  1423. */
  1424. // Check for availability
  1425. if ( pWinStation->pWsx &&
  1426. pWinStation->pWsx->pWsxIcaStackIoControl ) {
  1427. Status = pWinStation->pWsx->pWsxIcaStackIoControl(
  1428. pWinStation->pWsxContext,
  1429. pWinStation->hIca,
  1430. pShadow->hStack,
  1431. IOCTL_ICA_STACK_ENABLE_IO,
  1432. NULL,
  1433. 0,
  1434. NULL,
  1435. 0,
  1436. NULL );
  1437. }
  1438. else {
  1439. Status = STATUS_CTX_SHADOW_INVALID;
  1440. }
  1441. if ( !NT_SUCCESS(Status) )
  1442. goto badenableio;
  1443. /*
  1444. * If this is a help assistant scenario then notify the target winlogon (via Win32k)
  1445. * that HA shadow is about to commence.
  1446. */
  1447. if (ShadowerIsHelpSession) {
  1448. msg.ApiNumber = SMWinStationNotify;
  1449. msg.WaitForReply = TRUE;
  1450. msg.u.DoNotify.NotifyEvent = WinStation_Notify_HelpAssistantShadowStart;
  1451. SendWinStationCommand( pWinStation, &msg, 60);
  1452. }
  1453. /*
  1454. * Start shadowing
  1455. */
  1456. msg.ApiNumber = SMWinStationShadowStart;
  1457. msg.u.ShadowStart.pThinwireData = pThinwireData;
  1458. msg.u.ShadowStart.ThinwireDataLength = ThinwireDataLength;
  1459. Status = SendWinStationCommand( pWinStation, &msg, 60 );
  1460. if ( NT_SUCCESS( Status ) ) {
  1461. /*
  1462. * Wait for the shadow to be terminated
  1463. */
  1464. UnlockWinStation( pWinStation );
  1465. if ( fChainedDD ) {
  1466. HANDLE hEvents[2];
  1467. hEvents[0] = pShadow->hBrokenEvent;
  1468. hEvents[1] = pWinStation->ShadowDisplayChangeEvent;
  1469. Status = NtWaitForMultipleObjects( 2, hEvents, WaitAny, FALSE, NULL );
  1470. } else {
  1471. NtWaitForSingleObject( pShadow->hBrokenEvent, FALSE, NULL );
  1472. }
  1473. RelockWinStation( pWinStation );
  1474. if ( fChainedDD && (Status == WAIT_OBJECT_0 + 1) ) {
  1475. // valid only if there's one shadower?
  1476. NtResetEvent(pWinStation->ShadowDisplayChangeEvent, NULL);
  1477. EndStatus = STATUS_CTX_SHADOW_ENDED_BY_MODE_CHANGE;
  1478. }
  1479. /*
  1480. * Stop shadowing
  1481. */
  1482. msg.ApiNumber = SMWinStationShadowStop;
  1483. Status = SendWinStationCommand( pWinStation, &msg, 60 );
  1484. ASSERT( NT_SUCCESS( Status ) );
  1485. }
  1486. /*
  1487. * If this is a help assistant scenario then notify the target winlogon (via Win32k)
  1488. * that HA shadow is done.
  1489. */
  1490. if (ShadowerIsHelpSession) {
  1491. msg.ApiNumber = SMWinStationNotify;
  1492. msg.WaitForReply = FALSE;
  1493. msg.u.DoNotify.NotifyEvent = WinStation_Notify_HelpAssistantShadowFinish;
  1494. SendWinStationCommand( pWinStation, &msg, 0);
  1495. }
  1496. /*
  1497. * Disable I/O for the shadow stack
  1498. */
  1499. // Check for availability
  1500. if ( pWinStation->pWsx &&
  1501. pWinStation->pWsx->pWsxIcaStackIoControl ) {
  1502. (void) pWinStation->pWsx->pWsxIcaStackIoControl(
  1503. pWinStation->pWsxContext,
  1504. pWinStation->hIca,
  1505. pShadow->hStack,
  1506. IOCTL_ICA_STACK_DISABLE_IO,
  1507. NULL,
  1508. 0,
  1509. NULL,
  1510. 0,
  1511. NULL );
  1512. }
  1513. /*
  1514. * Do final shadow cleanup
  1515. */
  1516. msg.ApiNumber = SMWinStationShadowCleanup;
  1517. msg.u.ShadowCleanup.pThinwireData = pThinwireData;
  1518. msg.u.ShadowCleanup.ThinwireDataLength = ThinwireDataLength;
  1519. Status2 = SendWinStationCommand( pWinStation, &msg, 60 );
  1520. ASSERT( NT_SUCCESS( Status2 ) );
  1521. RemoveEntryList( &pShadow->Links );
  1522. IcaStackConnectionClose( pShadow->hStack, pConfig,
  1523. pShadow->pEndpoint, pShadow->EndpointLength );
  1524. MemFree( pShadow->pEndpoint );
  1525. NtClose( pShadow->hBrokenEvent );
  1526. IcaStackClose( pShadow->hStack );
  1527. MemFree( pShadow );
  1528. /*
  1529. * If there is a shadow done event and this was the last shadow,
  1530. * then signal the waiter now.
  1531. */
  1532. if ( pWinStation->ShadowDoneEvent && IsListEmpty( &pWinStation->ShadowHead ) )
  1533. SetEvent( pWinStation->ShadowDoneEvent );
  1534. /*
  1535. * For the console session, we now need to unchain the DD for
  1536. * performance reasons. Ignore this return code -- we don't need it and
  1537. * we also don't want to overwrite the value in Status.
  1538. */
  1539. if (fChainedDD == TRUE)
  1540. {
  1541. TRACE((hTrace,TC_ICASRV,TT_API3, "TERMSRV: unchain console DD\n"));
  1542. pWinStation->Flags |= WSF_DISCONNECT;
  1543. ConsoleShadowStop( pWinStation );
  1544. pWinStation->Flags &= ~WSF_DISCONNECT;
  1545. fChainedDD = FALSE;
  1546. }
  1547. //
  1548. // reset the console winstation parameters.
  1549. //
  1550. if (pWinStation->fOwnsConsoleTerminal) {
  1551. pWinStation->hIca = hIca;
  1552. pWinStation->hStack = hStack;
  1553. pWinStation->pWsx = pWsx;
  1554. pWinStation->pWsxContext = pWsxContext;
  1555. } else if( fResetShadowSetting ) {
  1556. // Console shadow already reset back to original value
  1557. // can't do this in WinStationShadowWorker(), might run into
  1558. // some timing problem.
  1559. pWinStation->Config.Config.User.Shadow = pWinStation->OriginalShadowClass;
  1560. }
  1561. if( bResetStateFlags ) {
  1562. pWinStation->StateFlags &= ~WSF_ST_SHADOW;
  1563. }
  1564. /*
  1565. * Unlock winstation
  1566. */
  1567. ReleaseWinStation( pWinStation );
  1568. if ( NT_SUCCESS(Status) && (EndStatus != STATUS_SUCCESS) ) {
  1569. Status = EndStatus;
  1570. }
  1571. return( Status );
  1572. /*=============================================================================
  1573. == Error returns
  1574. =============================================================================*/
  1575. badenableio:
  1576. badsetconnect:
  1577. msg.ApiNumber = SMWinStationShadowCleanup;
  1578. msg.u.ShadowCleanup.pThinwireData = pThinwireData;
  1579. msg.u.ShadowCleanup.ThinwireDataLength = ThinwireDataLength;
  1580. SendWinStationCommand( pWinStation, &msg, 60 );
  1581. badsetup:
  1582. PostCreateConnection:
  1583. closing:
  1584. IcaStackConnectionClose( pShadow->hStack, pConfig,
  1585. pShadow->pEndpoint, pShadow->EndpointLength );
  1586. badconnect:
  1587. MemFree( pShadow->pEndpoint );
  1588. badendpoint:
  1589. RemoveEntryList( &pShadow->Links );
  1590. badbroken:
  1591. NtClose( pShadow->hBrokenEvent );
  1592. badevent:
  1593. IcaStackClose( pShadow->hStack );
  1594. badopen:
  1595. MemFree( pShadow );
  1596. shadowinvalid:
  1597. shadowdenied:
  1598. /*
  1599. * For the console session, we now need to unchain the DD for
  1600. * performance reasons
  1601. */
  1602. if (fChainedDD == TRUE)
  1603. {
  1604. TRACE((hTrace,TC_ICASRV,TT_API3, "TERMSRV: unchain console DD\n"));
  1605. pWinStation->Flags |= WSF_DISCONNECT;
  1606. /*
  1607. * Ignore this return code -- we don't need it and we also don't want
  1608. * to overwrite the value in Status.
  1609. */
  1610. (void)ConsoleShadowStop( pWinStation );
  1611. pWinStation->Flags &= ~WSF_DISCONNECT;
  1612. fChainedDD = FALSE;
  1613. }
  1614. //
  1615. // reset the console winstation parameters.
  1616. //
  1617. if (pWinStation->fOwnsConsoleTerminal) {
  1618. pWinStation->hIca = hIca;
  1619. pWinStation->hStack = hStack;
  1620. pWinStation->pWsx = pWsx;
  1621. pWinStation->pWsxContext = pWsxContext;
  1622. } else if( fResetShadowSetting ) {
  1623. // Console shadow already reset back to original value
  1624. // can't do this in WinStationShadowWorker(), might run into
  1625. // some timing problem.
  1626. pWinStation->Config.Config.User.Shadow = pWinStation->OriginalShadowClass;
  1627. }
  1628. if( bResetStateFlags ) {
  1629. pWinStation->StateFlags &= ~WSF_ST_SHADOW;
  1630. }
  1631. ReleaseWinStation( pWinStation );
  1632. done:
  1633. TRACE((hTrace,TC_ICASRV,TT_ERROR, "TERMSRV: WinStationShadowTarget, Status=0x%x\n",
  1634. Status ));
  1635. return Status;
  1636. }
  1637. /*****************************************************************************
  1638. *
  1639. * WinStationStopAllShadows
  1640. *
  1641. * Stop all shadow activity for this Winstation
  1642. *
  1643. * ENTRY:
  1644. * pWinStation (input)
  1645. * pointer to WinStation
  1646. *
  1647. *
  1648. * EXIT:
  1649. * STATUS_SUCCESS - no error
  1650. *
  1651. ****************************************************************************/
  1652. NTSTATUS
  1653. WinStationStopAllShadows( PWINSTATION pWinStation )
  1654. {
  1655. PLIST_ENTRY Head, Next;
  1656. NTSTATUS Status;
  1657. /*
  1658. * If this WinStation is a shadow client, then set the shadow broken
  1659. * event and create an event to wait on for it the shadow to terminate.
  1660. */
  1661. if ( pWinStation->hPassthruStack ) {
  1662. pWinStation->ShadowDoneEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  1663. ASSERT( pWinStation->ShadowDoneEvent );
  1664. if ( pWinStation->ShadowBrokenEvent ) {
  1665. SetEvent( pWinStation->ShadowBrokenEvent );
  1666. }
  1667. }
  1668. /*
  1669. * If this WinStation is a shadow target, then loop through the
  1670. * shadow structures and signal the broken event for each one.
  1671. */
  1672. if ( !IsListEmpty( &pWinStation->ShadowHead ) ) {
  1673. pWinStation->ShadowDoneEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  1674. ASSERT( pWinStation->ShadowDoneEvent );
  1675. Head = &pWinStation->ShadowHead;
  1676. for ( Next = Head->Flink; Next != Head; Next = Next->Flink ) {
  1677. PSHADOW_INFO pShadow;
  1678. pShadow = CONTAINING_RECORD( Next, SHADOW_INFO, Links );
  1679. NtSetEvent( pShadow->hBrokenEvent, NULL );
  1680. }
  1681. }
  1682. /*
  1683. * If a shadow done event was created above, then we'll wait on it
  1684. * now (for either the shadow client or shadow target to complete).
  1685. */
  1686. if ( pWinStation->ShadowDoneEvent ) {
  1687. UnlockWinStation( pWinStation );
  1688. Status = WaitForSingleObject( pWinStation->ShadowDoneEvent, 60*1000 );
  1689. RelockWinStation( pWinStation );
  1690. CloseHandle( pWinStation->ShadowDoneEvent );
  1691. pWinStation->ShadowDoneEvent = NULL;
  1692. }
  1693. return( STATUS_SUCCESS );
  1694. }
  1695. NTSTATUS
  1696. _CreateShadowAddress(
  1697. ULONG ShadowId,
  1698. PWINSTATIONCONFIG2 pConfig,
  1699. PWSTR pTargetServerName,
  1700. PICA_STACK_ADDRESS pAddress,
  1701. PICA_STACK_ADDRESS pRemoteAddress
  1702. )
  1703. {
  1704. WCHAR ServerName[MAX_COMPUTERNAME_LENGTH+1];
  1705. ULONG Length;
  1706. int nFormattedLength;
  1707. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  1708. RtlZeroMemory( pAddress, sizeof(*pAddress) );
  1709. if ( !_wcsicmp( pConfig->Pd[0].Create.PdDLL, L"tdpipe" ) ) {
  1710. Length = MAX_COMPUTERNAME_LENGTH+1;
  1711. ServerName[0] = (WCHAR)0;
  1712. GetComputerName( ServerName, &Length );
  1713. *((PWCHAR)pAddress) = (WCHAR)0;
  1714. nFormattedLength = _snwprintf( (PWSTR)pAddress, sizeof(ICA_STACK_ADDRESS)/sizeof(WCHAR), L"\\??\\Pipe\\Shadowpipe\\%d", ShadowId );
  1715. if (nFormattedLength < 0 || nFormattedLength == sizeof(ICA_STACK_ADDRESS)/sizeof(WCHAR)) {
  1716. return STATUS_INVALID_PARAMETER;
  1717. }
  1718. if ( pTargetServerName ) {
  1719. *((PWCHAR)pRemoteAddress) = (WCHAR)0;
  1720. nFormattedLength = _snwprintf( (PWSTR)pRemoteAddress, sizeof(ICA_STACK_ADDRESS)/sizeof(WCHAR), L"\\??\\UNC\\%ws\\Pipe\\Shadowpipe\\%d",
  1721. pTargetServerName, ShadowId );
  1722. if (nFormattedLength < 0 || nFormattedLength == sizeof(ICA_STACK_ADDRESS)/sizeof(WCHAR)) {
  1723. return STATUS_INVALID_PARAMETER;
  1724. }
  1725. } else {
  1726. *pRemoteAddress = *pAddress;
  1727. }
  1728. } else if ( !_wcsicmp( pConfig->Pd[0].Create.PdDLL, L"tdnetb" ) ) {
  1729. *(PUSHORT)pAddress = AF_NETBIOS;
  1730. GetSystemTimeAsFileTime( (LPFILETIME)((PUSHORT)(pAddress)+1) );
  1731. pConfig->Pd[0].Params.Network.LanAdapter = 1;
  1732. *pRemoteAddress = *pAddress;
  1733. } else if ( !_wcsicmp( pConfig->Pd[0].Create.PdDLL, L"tdtcp" ) ) {
  1734. *(PUSHORT)pAddress = AF_INET;
  1735. *pRemoteAddress = *pAddress;
  1736. } else if ( !_wcsicmp( pConfig->Pd[0].Create.PdDLL, L"tdipx" ) ||
  1737. !_wcsicmp( pConfig->Pd[0].Create.PdDLL, L"tdspx" ) ) {
  1738. *(PUSHORT)pAddress = AF_IPX;
  1739. *pRemoteAddress = *pAddress;
  1740. } else {
  1741. return STATUS_INVALID_PARAMETER;
  1742. }
  1743. return( STATUS_SUCCESS );
  1744. }
  1745. NTSTATUS
  1746. _WinStationShadowTargetThread( PVOID p )
  1747. {
  1748. PSHADOW_PARMS pShadowParms;
  1749. HANDLE NullToken;
  1750. PWINSTATION pWinStation;
  1751. //DWORD WNetRc;
  1752. NTSTATUS Status;
  1753. NTSTATUS ShadowStatus;
  1754. pShadowParms = (PSHADOW_PARMS)p;
  1755. /*
  1756. * Impersonate the client using the token handle passed to us.
  1757. */
  1758. ShadowStatus = NtSetInformationThread( NtCurrentThread(),
  1759. ThreadImpersonationToken,
  1760. (PVOID)&pShadowParms->ImpersonationToken,
  1761. (ULONG)sizeof(HANDLE) );
  1762. ASSERT( NT_SUCCESS( ShadowStatus ) );
  1763. if ( !NT_SUCCESS( ShadowStatus ) )
  1764. goto impersonatefailed;
  1765. /*
  1766. * If target server name was not specified, then call the
  1767. * target worker function directly and avoid the RPC overhead.
  1768. */
  1769. if ( pShadowParms->pTargetServerName == NULL ) {
  1770. ShadowStatus = WinStationShadowTargetWorker(
  1771. pShadowParms->ShadowerIsHelpSession,
  1772. pShadowParms->fResetShadowMode,
  1773. pShadowParms->TargetLogonId,
  1774. &pShadowParms->Config,
  1775. &pShadowParms->Address,
  1776. pShadowParms->pModuleData,
  1777. pShadowParms->ModuleDataLength,
  1778. pShadowParms->pThinwireData,
  1779. pShadowParms->ThinwireDataLength,
  1780. pShadowParms->ClientName);
  1781. SetLastError(RtlNtStatusToDosError(ShadowStatus));
  1782. /*
  1783. * Otherwise, open the remote targer server and call the shadow target API.
  1784. */
  1785. } else {
  1786. HANDLE hServer;
  1787. hServer = WinStationOpenServer( pShadowParms->pTargetServerName );
  1788. if ( hServer == NULL ) {
  1789. ShadowStatus = STATUS_OBJECT_NAME_NOT_FOUND;
  1790. } else {
  1791. ShadowStatus = _WinStationShadowTarget(
  1792. hServer,
  1793. pShadowParms->TargetLogonId,
  1794. &pShadowParms->Config,
  1795. &pShadowParms->Address,
  1796. pShadowParms->pModuleData,
  1797. pShadowParms->ModuleDataLength,
  1798. pShadowParms->pThinwireData,
  1799. pShadowParms->ThinwireDataLength,
  1800. pShadowParms->ClientName,
  1801. sizeof(pShadowParms->ClientName) );
  1802. if (ShadowStatus != STATUS_SUCCESS) {
  1803. ShadowStatus = WinStationWinerrorToNtStatus(GetLastError());
  1804. }
  1805. WinStationCloseServer( hServer );
  1806. }
  1807. }
  1808. /*
  1809. * Revert back to our threads default token.
  1810. */
  1811. NullToken = NULL;
  1812. Status = NtSetInformationThread( NtCurrentThread(),
  1813. ThreadImpersonationToken,
  1814. (PVOID)&NullToken,
  1815. (ULONG)sizeof(HANDLE) );
  1816. ASSERT( NT_SUCCESS( Status ) );
  1817. impersonatefailed:
  1818. /*
  1819. * Now find and lock the client WinStation and return the status
  1820. * from the above call to the client WinStation.
  1821. */
  1822. pWinStation = FindWinStationById( pShadowParms->ClientLogonId, FALSE );
  1823. if ( pWinStation != NULL ) {
  1824. if ( pWinStation->ShadowId == pShadowParms->ClientShadowId ) {
  1825. pWinStation->ShadowTargetStatus = ShadowStatus;
  1826. }
  1827. ReleaseWinStation( pWinStation );
  1828. }
  1829. NtClose( pShadowParms->ImpersonationToken );
  1830. MemFree( pShadowParms->pModuleData );
  1831. MemFree( pShadowParms->pThinwireData );
  1832. MemFree( pShadowParms );
  1833. TRACE((hTrace,TC_ICASRV,TT_ERROR, "TERMSRV: ShadowTargetThread got: Status=0x%x\n",
  1834. ShadowStatus ));
  1835. return( ShadowStatus );
  1836. }
  1837. /*****************************************************************************
  1838. *
  1839. * WinStationShadowChangeMode
  1840. *
  1841. * Change the mode of the current shadow: interactive/non interactive
  1842. *
  1843. * ENTRY:
  1844. * pWinStation (input/output)
  1845. * pointer to WinStation
  1846. * pWinStationShadow (input)
  1847. * pointer to WINSTATIONSHADOW struct
  1848. * ulLength (input)
  1849. * length of the input buffer
  1850. *
  1851. *
  1852. * EXIT:
  1853. * STATUS_xxx error
  1854. *
  1855. ****************************************************************************/
  1856. NTSTATUS WinStationShadowChangeMode(
  1857. PWINSTATION pWinStation,
  1858. PWINSTATIONSHADOW pWinStationShadow,
  1859. ULONG ulLength )
  1860. {
  1861. NTSTATUS Status = STATUS_SUCCESS; //assume success
  1862. if (ulLength >= sizeof(WINSTATIONSHADOW)) {
  1863. //
  1864. // If the session is being shadowed then check the new shadow mode
  1865. //
  1866. if ( pWinStation->State == State_Active &&
  1867. !IsListEmpty(&pWinStation->ShadowHead) ) {
  1868. HANDLE ChannelHandle;
  1869. ULONG IoCtlCode = 0;
  1870. switch ( pWinStationShadow->ShadowClass ) {
  1871. case Shadow_EnableInputNotify :
  1872. case Shadow_EnableInputNoNotify :
  1873. //
  1874. // we want input : enable it regardless of current state!
  1875. //
  1876. IoCtlCode = IOCTL_ICA_CHANNEL_ENABLE_SHADOW;
  1877. break;
  1878. case Shadow_EnableNoInputNotify :
  1879. case Shadow_EnableNoInputNoNotify :
  1880. //
  1881. // We want no input, disable it.
  1882. //
  1883. IoCtlCode = IOCTL_ICA_CHANNEL_DISABLE_SHADOW;
  1884. break;
  1885. case Shadow_Disable :
  1886. Status = STATUS_INVALID_PARAMETER;
  1887. break;
  1888. default:
  1889. Status = STATUS_INVALID_PARAMETER;
  1890. break;
  1891. }
  1892. if ( IoCtlCode != 0 ) {
  1893. KEYBOARD_INDICATOR_PARAMETERS KbdLeds;
  1894. NTSTATUS Status2;
  1895. Status = IcaChannelOpen( pWinStation->hIca,
  1896. Channel_Keyboard,
  1897. NULL,
  1898. &ChannelHandle );
  1899. if ( NT_SUCCESS( Status ) ) {
  1900. // if we're re-enabling input, get the leds state on the primary stack...
  1901. if ( IoCtlCode == IOCTL_ICA_CHANNEL_ENABLE_SHADOW ) {
  1902. Status2 = IcaChannelIoControl( ChannelHandle, IOCTL_KEYBOARD_QUERY_INDICATORS,
  1903. NULL, 0, &KbdLeds, sizeof(KbdLeds), NULL);
  1904. }
  1905. Status = IcaChannelIoControl( ChannelHandle, IoCtlCode,
  1906. NULL, 0, NULL, 0, NULL );
  1907. // and update all stacks with this state.
  1908. if ( IoCtlCode == IOCTL_ICA_CHANNEL_ENABLE_SHADOW &&
  1909. NT_SUCCESS( Status ) &&
  1910. NT_SUCCESS( Status2 ) ) {
  1911. Status2 = IcaChannelIoControl( ChannelHandle, IOCTL_KEYBOARD_SET_INDICATORS,
  1912. &KbdLeds, sizeof(KbdLeds), NULL, 0, NULL);
  1913. }
  1914. IcaChannelClose( ChannelHandle );
  1915. }
  1916. if ( NT_SUCCESS( Status ) ) {
  1917. Status = IcaChannelOpen( pWinStation->hIca,
  1918. Channel_Mouse,
  1919. NULL,
  1920. &ChannelHandle );
  1921. if ( NT_SUCCESS( Status ) ) {
  1922. Status = IcaChannelIoControl( ChannelHandle, IoCtlCode,
  1923. NULL, 0, NULL, 0, NULL );
  1924. IcaChannelClose( ChannelHandle );
  1925. }
  1926. }
  1927. }
  1928. // Do not update WinStation shadow config, user should not
  1929. // be able to bypass what's defined in Group Policy.
  1930. }
  1931. } else {
  1932. Status = STATUS_BUFFER_TOO_SMALL;
  1933. }
  1934. return Status;
  1935. }
  1936. /*****************************************************************************
  1937. *
  1938. * _DetectLoop
  1939. *
  1940. * Detects a loop by walking the chain of containers.
  1941. *
  1942. * ENTRY:
  1943. * RemoteSessionId (input)
  1944. * id of the session from where we start the search
  1945. * pRemoteServerDigProductId (input)
  1946. * product id of the machine from where we start the search
  1947. * TargetSessionId (input)
  1948. * id of the session looked up
  1949. * pTargetServerDigProductId (input)
  1950. * product id of the machine looked up
  1951. * pLocalServerProductId (input)
  1952. * product id of the local machine
  1953. * pbLoop (output)
  1954. * pointer to the result of the search
  1955. *
  1956. * EXIT:
  1957. * STATUS_SUCCESS - no error
  1958. *
  1959. ****************************************************************************/
  1960. NTSTATUS
  1961. _DetectLoop(
  1962. IN ULONG RemoteSessionId,
  1963. IN PWSTR pRemoteServerDigProductId,
  1964. IN ULONG TargetSessionId,
  1965. IN PWSTR pTargetServerDigProductId,
  1966. IN PWSTR pLocalServerProductId,
  1967. OUT BOOL* pbLoop
  1968. )
  1969. {
  1970. NTSTATUS Status = STATUS_SUCCESS;
  1971. PWINSTATION pWinStation;
  1972. WCHAR TmpDigProductId[CLIENT_PRODUCT_ID_LENGTH];
  1973. if ( pbLoop == NULL )
  1974. return STATUS_INVALID_PARAMETER;
  1975. else
  1976. *pbLoop = FALSE;
  1977. do {
  1978. if ( _wcsicmp( pLocalServerProductId, pRemoteServerDigProductId ) != 0 ) {
  1979. // For now limit the search to the local cases.
  1980. // Later we can add a RPC call or any other
  1981. // mechanism (by instance through the client)
  1982. // to get this info from the distant machine.
  1983. Status = STATUS_UNSUCCESSFUL;
  1984. // The solution could be to RPC the remote machine to get
  1985. // the client data for the session id. Then from these data
  1986. // we can get the client computer name and the client session id.
  1987. // RPC to use: WinStationQueryInformation with information
  1988. // class set to WinStationClient.
  1989. // No need to add a new RPC call.
  1990. } else {
  1991. // we're sure that the remote session is on the same server
  1992. pWinStation = FindWinStationById( RemoteSessionId, FALSE );
  1993. if ( pWinStation != NULL ) {
  1994. // set the new remote info
  1995. RemoteSessionId = pWinStation->Client.ClientSessionId;
  1996. memcpy(TmpDigProductId, pWinStation->Client.clientDigProductId, sizeof( TmpDigProductId ));
  1997. pRemoteServerDigProductId = TmpDigProductId;
  1998. ReleaseWinStation( pWinStation );
  1999. } else {
  2000. Status = STATUS_ACCESS_DENIED;
  2001. }
  2002. }
  2003. if( !*pRemoteServerDigProductId )
  2004. //older client, can't do anything, allow shadow
  2005. break;
  2006. if ( Status == STATUS_SUCCESS ) {
  2007. if ( (RemoteSessionId == TargetSessionId) &&
  2008. (_wcsicmp( pRemoteServerDigProductId, pTargetServerDigProductId ) == 0) ) {
  2009. *pbLoop = TRUE;
  2010. } else if ( RemoteSessionId == LOGONID_NONE ) {
  2011. // no loop, return success.
  2012. break;
  2013. }
  2014. }
  2015. } while ( (*pbLoop == FALSE) && (Status == STATUS_SUCCESS) );
  2016. return Status;
  2017. }
  2018. /*****************************************************************************
  2019. *
  2020. * _CheckShadowLoop
  2021. *
  2022. * Detects a loop in the shadow.
  2023. *
  2024. * ENTRY:
  2025. pWinStation
  2026. pointer to the current Winstation
  2027. * ClientLogonId (input)
  2028. * client of the shadow
  2029. * pTargetServerName (input)
  2030. * target server name
  2031. * TargetLogonId (input)
  2032. * target login id (where the app is running)
  2033. *
  2034. * EXIT:
  2035. * STATUS_SUCCESS - no error
  2036. *
  2037. ****************************************************************************/
  2038. NTSTATUS
  2039. _CheckShadowLoop(
  2040. IN ULONG ClientLogonId,
  2041. IN PWSTR pTargetServerName,
  2042. IN ULONG TargetLogonId
  2043. )
  2044. {
  2045. NTSTATUS Status = STATUS_SUCCESS;
  2046. BOOL bLoop;
  2047. WCHAR LocalDigProductId [ CLIENT_PRODUCT_ID_LENGTH ];
  2048. WCHAR* pTargetServerDigProductId = NULL;
  2049. WINSTATIONPRODID WinStationProdId;
  2050. ULONG len;
  2051. memcpy( LocalDigProductId, g_DigProductId, sizeof( LocalDigProductId ));
  2052. //get the target's sessionid and digital product id
  2053. if ( pTargetServerName == NULL ) {
  2054. pTargetServerDigProductId = LocalDigProductId;
  2055. /*
  2056. * Otherwise, open the remote targer server and call the shadow target API.
  2057. */
  2058. }
  2059. else
  2060. {
  2061. HANDLE hServer;
  2062. ZeroMemory( &WinStationProdId, sizeof( WINSTATIONPRODID ));
  2063. hServer = WinStationOpenServer( pTargetServerName );
  2064. if ( hServer == NULL )
  2065. {
  2066. //ignore errors, we allow shadowing
  2067. goto done;
  2068. }
  2069. else
  2070. {
  2071. //ignore errors
  2072. WinStationQueryInformation( hServer, TargetLogonId, WinStationDigProductId, &WinStationProdId, sizeof(WinStationProdId), &len);
  2073. WinStationCloseServer( hServer );
  2074. }
  2075. pTargetServerDigProductId = WinStationProdId.DigProductId;
  2076. }
  2077. //
  2078. // First pass: start from the local session (i.e. the shadow client)
  2079. // and walk the chain of containers up to the outtermost session in case
  2080. // we reach the target session in the chain.
  2081. //
  2082. if( *LocalDigProductId && *pTargetServerDigProductId ) {
  2083. Status = _DetectLoop( ClientLogonId,
  2084. LocalDigProductId,
  2085. TargetLogonId,
  2086. pTargetServerDigProductId,
  2087. LocalDigProductId,
  2088. &bLoop);
  2089. if ( Status == STATUS_SUCCESS ) {
  2090. if (bLoop) {
  2091. // Status = STATUS_CTX_SHADOW_CIRCULAR;
  2092. Status = STATUS_ACCESS_DENIED;
  2093. goto done;
  2094. }
  2095. } //else ignore errors and do the second pass
  2096. //
  2097. // Second pass: start from the target session (i.e. the shadow target)
  2098. // and walk the chain of containers up to the outtermost session in case
  2099. // we reach the client session in the chain.
  2100. //
  2101. Status = _DetectLoop( TargetLogonId,
  2102. pTargetServerDigProductId,
  2103. ClientLogonId,
  2104. LocalDigProductId,
  2105. LocalDigProductId,
  2106. &bLoop);
  2107. if ( Status == STATUS_SUCCESS ) {
  2108. if (bLoop) {
  2109. //Status = STATUS_CTX_SHADOW_CIRCULAR;
  2110. Status = STATUS_ACCESS_DENIED;
  2111. }
  2112. } else {
  2113. //else ignore errors and grant shadow
  2114. Status = STATUS_SUCCESS;
  2115. }
  2116. }
  2117. done:
  2118. return Status;
  2119. }
  2120. /*****************************************************************************
  2121. *
  2122. * GetSalemOutbufCount
  2123. *
  2124. * Gets the outbufcount from the registry for the help assistant
  2125. *
  2126. * ENTRY:
  2127. * pdwValue
  2128. * output where the value is stored
  2129. * EXIT:
  2130. * TRUE - no error
  2131. *
  2132. ****************************************************************************/
  2133. BOOL GetSalemOutbufCount(PDWORD pdwValue)
  2134. {
  2135. BOOL fSuccess = FALSE;
  2136. HKEY hKey = NULL;
  2137. if( NULL == pdwValue )
  2138. return FALSE;
  2139. if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  2140. REG_CONTROL_SALEM,
  2141. 0,
  2142. KEY_READ,
  2143. &hKey
  2144. ) == ERROR_SUCCESS ) {
  2145. DWORD dwSize = sizeof(DWORD);
  2146. DWORD dwType;
  2147. if((RegQueryValueEx(hKey,
  2148. WIN_OUTBUFCOUNT,
  2149. NULL,
  2150. &dwType,
  2151. (PBYTE) pdwValue,
  2152. &dwSize
  2153. ) == ERROR_SUCCESS)
  2154. && dwType == REG_DWORD
  2155. && *pdwValue > 0) {
  2156. fSuccess = TRUE;
  2157. }
  2158. }
  2159. if(NULL != hKey )
  2160. RegCloseKey(hKey);
  2161. return fSuccess;
  2162. }