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.

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