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.

1022 lines
34 KiB

  1. /*************************************************************************
  2. *
  3. * wait.c
  4. *
  5. * WinStation wait for connection routines
  6. *
  7. * Copyright Microsoft Corporation, 1998
  8. *
  9. *
  10. *************************************************************************/
  11. /*
  12. * Includes
  13. */
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. #include "conntfy.h"
  17. // These are the maximum lengths of UserName, Password and Domain allowed by Winlogon
  18. #define MAX_ALLOWED_USERNAME_LEN 255
  19. #define MAX_ALLOWED_PASSWORD_LEN 126
  20. #define MAX_ALLOWED_DOMAIN_LEN 255
  21. /*=============================================================================
  22. == Data
  23. =============================================================================*/
  24. NTSTATUS
  25. WinStationInheritSecurityDescriptor(
  26. PVOID pSecurityDescriptor,
  27. PWINSTATION pTargetWinStation
  28. );
  29. NTSTATUS
  30. WaitForConsoleConnectWorker( PWINSTATION pWinStation );
  31. BOOL
  32. IsKernelDebuggerAttached();
  33. extern PSECURITY_DESCRIPTOR DefaultConsoleSecurityDescriptor;
  34. extern WINSTATIONCONFIG2 gConsoleConfig;
  35. extern HANDLE WinStationIdleControlEvent;
  36. extern RTL_CRITICAL_SECTION ConsoleLock;
  37. extern RTL_RESOURCE WinStationSecurityLock;
  38. /*****************************************************************************
  39. *
  40. * WaitForConnectWorker
  41. *
  42. * Message parameter unmarshalling function for WinStation API.
  43. *
  44. * ENTRY:
  45. * pWinStation (input)
  46. * Pointer to our WinStation (locked)
  47. *
  48. * Note, comes in locked and returned released.
  49. *
  50. * EXIT:
  51. * STATUS_SUCCESS - no error
  52. *
  53. ****************************************************************************/
  54. NTSTATUS
  55. WaitForConnectWorker( PWINSTATION pWinStation, HANDLE ClientProcessId )
  56. {
  57. OBJECT_ATTRIBUTES ObjA;
  58. ULONG ReturnLength;
  59. BYTE version;
  60. ULONG Offset;
  61. ICA_STACK_LAST_ERROR tdlasterror;
  62. WINSTATION_APIMSG WMsg;
  63. BOOLEAN rc;
  64. NTSTATUS Status;
  65. BOOLEAN fOwnsConsoleTerminal = FALSE;
  66. ULONG BytesGot ;
  67. #define MODULE_SIZE 1024
  68. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WaitForConnectWorker, LogonId=%d\n",
  69. pWinStation->LogonId ));
  70. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_INFO_LEVEL, "TERMSRV: WaitForConnectWorker, LogonId=%d\n",pWinStation->LogonId ));
  71. /*
  72. * You only go through this API once
  73. */
  74. if ( !pWinStation->NeverConnected ) {
  75. ReleaseWinStation( pWinStation );
  76. #ifdef DBG
  77. DbgBreakPoint();
  78. #endif
  79. return( STATUS_ACCESS_DENIED );
  80. }
  81. // Should really be winlogon only here, however if ntsd is started
  82. // then the first time we know it's winlogon is here.
  83. /*
  84. * Ensure this is WinLogon calling
  85. */
  86. if ( ClientProcessId != pWinStation->InitialCommandProcessId ) {
  87. /*
  88. * If NTSD is started instead of winlogon, the InitialCommandProcessId is wrong.
  89. */
  90. if ( !pWinStation->InitialProcessSet ) {
  91. // need to close handle if already opened
  92. if ( pWinStation->InitialCommandProcess ) {
  93. NtClose( pWinStation->InitialCommandProcess );
  94. pWinStation->InitialCommandProcess = NULL;
  95. InvalidateTerminateWaitList();
  96. }
  97. pWinStation->InitialCommandProcess = OpenProcess(
  98. PROCESS_ALL_ACCESS,
  99. FALSE,
  100. (DWORD)(UINT_PTR)ClientProcessId );
  101. if ( pWinStation->InitialCommandProcess == NULL ) {
  102. ReleaseWinStation( pWinStation );
  103. Status = STATUS_ACCESS_DENIED;
  104. goto done;
  105. }
  106. pWinStation->InitialCommandProcessId = ClientProcessId;
  107. pWinStation->InitialProcessSet = TRUE;
  108. }
  109. else {
  110. ReleaseWinStation( pWinStation );
  111. Status = STATUS_SUCCESS;
  112. goto done;
  113. }
  114. }
  115. else {
  116. /*
  117. * Only do this once
  118. */
  119. pWinStation->InitialProcessSet = TRUE;
  120. }
  121. /*
  122. * Console's work is done
  123. */
  124. /*
  125. * At this point the create is done.
  126. */
  127. if (pWinStation->CreateEvent != NULL) {
  128. NtSetEvent( pWinStation->CreateEvent, NULL );
  129. }
  130. /*
  131. * At this point The session may be terminating. If this is
  132. * the case, fail the call now.
  133. */
  134. if ( pWinStation->Terminating ) {
  135. ReleaseWinStation( pWinStation );
  136. Status = STATUS_CTX_CLOSE_PENDING;
  137. goto done;
  138. }
  139. /*
  140. * We are going to wait for a connect (Idle)
  141. */
  142. memset( &WMsg, 0, sizeof(WMsg) );
  143. pWinStation->State = State_Idle;
  144. NotifySystemEvent( WEVENT_STATECHANGE );
  145. /*
  146. * Initialize connect event to wait on
  147. */
  148. InitializeObjectAttributes( &ObjA, NULL, 0, NULL, NULL );
  149. Status = NtCreateEvent( &pWinStation->ConnectEvent, EVENT_ALL_ACCESS, &ObjA,
  150. NotificationEvent, FALSE );
  151. if ( !NT_SUCCESS( Status ) ) {
  152. ReleaseWinStation( pWinStation );
  153. goto done;
  154. }
  155. /*
  156. * OK, now wait for a connection
  157. */
  158. UnlockWinStation( pWinStation );
  159. Status = NtWaitForSingleObject( pWinStation->ConnectEvent, FALSE, NULL );
  160. rc = RelockWinStation( pWinStation );
  161. if ( !NT_SUCCESS(Status) ) {
  162. ReleaseWinStation( pWinStation );
  163. goto done;
  164. }
  165. fOwnsConsoleTerminal = pWinStation->fOwnsConsoleTerminal;
  166. if (pWinStation->ConnectEvent) {
  167. NtClose( pWinStation->ConnectEvent );
  168. pWinStation->ConnectEvent = NULL;
  169. }
  170. if ( !rc || pWinStation->Terminating ) {
  171. ReleaseWinStation( pWinStation );
  172. Status = STATUS_CTX_CLOSE_PENDING;
  173. goto done;
  174. }
  175. // if this is a connect to the console session, Do all the console specific.
  176. if (fOwnsConsoleTerminal) {
  177. Status = WaitForConsoleConnectWorker( pWinStation );
  178. ReleaseWinStation( pWinStation );
  179. goto done;
  180. }
  181. /*
  182. * Reset the broken connection Flag.
  183. *
  184. */
  185. pWinStation->StateFlags &= ~WSF_ST_BROKEN_CONNECTION;
  186. /*
  187. * Duplicate the beep channel.
  188. * This is one channel that both CSR and ICASRV have open.
  189. */
  190. Status = IcaChannelOpen( pWinStation->hIca,
  191. Channel_Beep,
  192. NULL,
  193. &pWinStation->hIcaBeepChannel );
  194. if ( !NT_SUCCESS( Status ) ) {
  195. ReleaseWinStation( pWinStation );
  196. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WinStationWaitForConnect, LogonId=%d, IcaChannelOpen 0x%x\n",
  197. pWinStation->LogonId, Status ));
  198. goto done;
  199. }
  200. Status = NtDuplicateObject( NtCurrentProcess(),
  201. pWinStation->hIcaBeepChannel,
  202. pWinStation->WindowsSubSysProcess,
  203. &WMsg.u.DoConnect.hIcaBeepChannel,
  204. 0,
  205. 0,
  206. DUPLICATE_SAME_ACCESS );
  207. if ( !NT_SUCCESS( Status ) ) {
  208. ReleaseWinStation( pWinStation );
  209. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WinStationWaitForConnect, LogonId=%d, NtDuplicateObject 0x%x\n",
  210. pWinStation->LogonId, Status ));
  211. goto done;
  212. }
  213. /*
  214. * Duplicate the thinwire channel.
  215. * This is one channel that both CSR and ICASRV have open.
  216. */
  217. Status = IcaChannelOpen( pWinStation->hIca,
  218. Channel_Virtual,
  219. VIRTUAL_THINWIRE,
  220. &pWinStation->hIcaThinwireChannel );
  221. if ( !NT_SUCCESS( Status ) ) {
  222. ReleaseWinStation( pWinStation );
  223. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WinStationWaitForConnect, LogonId=%d, IcaChannelOpen 0x%x\n",
  224. pWinStation->LogonId, Status ));
  225. goto done;
  226. }
  227. Status = NtDuplicateObject( NtCurrentProcess(),
  228. pWinStation->hIcaThinwireChannel,
  229. pWinStation->WindowsSubSysProcess,
  230. &WMsg.u.DoConnect.hIcaThinwireChannel,
  231. 0,
  232. 0,
  233. DUPLICATE_SAME_ACCESS );
  234. if ( !NT_SUCCESS( Status ) ) {
  235. ReleaseWinStation( pWinStation );
  236. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WinStationWaitForConnect, LogonId=%d, NtDuplicateObject 0x%x\n",
  237. pWinStation->LogonId, Status ));
  238. goto done;
  239. }
  240. Status = IcaChannelIoControl( pWinStation->hIcaThinwireChannel,
  241. IOCTL_ICA_CHANNEL_ENABLE_SHADOW,
  242. NULL, 0, NULL, 0, NULL );
  243. ASSERT( NT_SUCCESS( Status ) );
  244. /*
  245. * Video channel
  246. */
  247. Status = WinStationOpenChannel( pWinStation->hIca,
  248. pWinStation->WindowsSubSysProcess,
  249. Channel_Video,
  250. NULL,
  251. &WMsg.u.DoConnect.hIcaVideoChannel );
  252. if ( !NT_SUCCESS( Status ) ) {
  253. ReleaseWinStation( pWinStation );
  254. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WinStationOpenChannel, LogonId=%d, NtDuplicateObject 0x%x\n",
  255. pWinStation->LogonId, Status ));
  256. goto done;
  257. }
  258. /*
  259. * Keyboard channel
  260. */
  261. Status = WinStationOpenChannel( pWinStation->hIca,
  262. pWinStation->WindowsSubSysProcess,
  263. Channel_Keyboard,
  264. NULL,
  265. &WMsg.u.DoConnect.hIcaKeyboardChannel );
  266. if ( !NT_SUCCESS( Status ) ) {
  267. ReleaseWinStation( pWinStation );
  268. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WinStationOpenChannel, LogonId=%d, NtDuplicateObject 0x%x\n",
  269. pWinStation->LogonId, Status ));
  270. goto done;
  271. }
  272. /*
  273. * Mouse channel
  274. */
  275. Status = WinStationOpenChannel( pWinStation->hIca,
  276. pWinStation->WindowsSubSysProcess,
  277. Channel_Mouse,
  278. NULL,
  279. &WMsg.u.DoConnect.hIcaMouseChannel );
  280. if ( !NT_SUCCESS( Status ) ) {
  281. ReleaseWinStation( pWinStation );
  282. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WinStationOpenChannel, LogonId=%d, NtDuplicateObject 0x%x\n",
  283. pWinStation->LogonId, Status ));
  284. goto done;
  285. }
  286. /*
  287. * Command channel
  288. */
  289. Status = WinStationOpenChannel( pWinStation->hIca,
  290. pWinStation->WindowsSubSysProcess,
  291. Channel_Command,
  292. NULL,
  293. &WMsg.u.DoConnect.hIcaCommandChannel );
  294. if ( !NT_SUCCESS( Status ) ) {
  295. ReleaseWinStation( pWinStation );
  296. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WinStationOpenChannel, LogonId=%d, NtDuplicateObject 0x%x\n",
  297. pWinStation->LogonId, Status ));
  298. goto done;
  299. }
  300. /*
  301. * Secure any virtual channels
  302. */
  303. VirtualChannelSecurity( pWinStation );
  304. /*
  305. * Client specific connection extension completion
  306. */
  307. if ( pWinStation->pWsx &&
  308. pWinStation->pWsx->pWsxInitializeClientData ) {
  309. Status = pWinStation->pWsx->pWsxInitializeClientData( pWinStation->pWsxContext,
  310. pWinStation->hStack,
  311. pWinStation->hIca,
  312. pWinStation->hIcaThinwireChannel,
  313. pWinStation->VideoModuleName,
  314. sizeof(pWinStation->VideoModuleName),
  315. &pWinStation->Config.Config.User,
  316. &pWinStation->Client.HRes,
  317. &pWinStation->Client.VRes,
  318. &pWinStation->Client.ColorDepth,
  319. &WMsg.u.DoConnect );
  320. if ( !NT_SUCCESS( Status ) ) {
  321. ReleaseWinStation( pWinStation );
  322. goto done;
  323. }
  324. if (pWinStation->LogonId == 0 || g_bPersonalTS) {
  325. if (pWinStation->hWinmmConsoleAudioEvent) {
  326. if (pWinStation->Client.fRemoteConsoleAudio) {
  327. // Set the console audio event - means console audio can be remoted
  328. SetEvent(pWinStation->hWinmmConsoleAudioEvent);
  329. }
  330. else {
  331. // Set the console audio event - means console audio can't be remoted
  332. ResetEvent(pWinStation->hWinmmConsoleAudioEvent);
  333. }
  334. }
  335. }
  336. }
  337. /* Get long UserNames and Password now */
  338. if ( pWinStation->pWsx &&
  339. pWinStation->pWsx->pWsxEscape ) {
  340. pWinStation->pNewClientCredentials = MemAlloc( sizeof(ExtendedClientCredentials) );
  341. if (pWinStation->pNewClientCredentials == NULL) {
  342. ReleaseWinStation( pWinStation );
  343. goto done;
  344. }
  345. Status = pWinStation->pWsx->pWsxEscape( pWinStation->pWsxContext,
  346. GET_LONG_USERNAME,
  347. NULL,
  348. 0,
  349. pWinStation->pNewClientCredentials,
  350. sizeof(ExtendedClientCredentials),
  351. &BytesGot) ;
  352. if (NT_SUCCESS(Status)) {
  353. // WsxEscape for GET_LONG_USERNAME succeeded
  354. // Check if u need the ExtendedClientCredentials - the common case is short UserName and
  355. // short password - so optimize the common case
  356. if ( (wcslen(pWinStation->pNewClientCredentials->UserName) <= USERNAME_LENGTH) &&
  357. (wcslen(pWinStation->pNewClientCredentials->Password) <= PASSWORD_LENGTH) &&
  358. (wcslen(pWinStation->pNewClientCredentials->Domain) <= DOMAIN_LENGTH) ) {
  359. // We can use the old credentials itself
  360. MemFree(pWinStation->pNewClientCredentials);
  361. pWinStation->pNewClientCredentials = NULL ;
  362. }
  363. // Winlogon does not allow > 126 chars for Password and > 255 chars for UserName and Domain in some code paths
  364. // So we have to use the old truncated credentials in case the extended credentials exceed these limits
  365. if (pWinStation->pNewClientCredentials != NULL) {
  366. if (wcslen(pWinStation->pNewClientCredentials->UserName) > MAX_ALLOWED_USERNAME_LEN) {
  367. wcscpy(pWinStation->pNewClientCredentials->UserName, pWinStation->Config.Config.User.UserName);
  368. }
  369. if (wcslen(pWinStation->pNewClientCredentials->Password) > MAX_ALLOWED_PASSWORD_LEN) {
  370. wcscpy(pWinStation->pNewClientCredentials->Password, pWinStation->Config.Config.User.Password);
  371. }
  372. if (wcslen(pWinStation->pNewClientCredentials->Domain) > MAX_ALLOWED_DOMAIN_LEN) {
  373. wcscpy(pWinStation->pNewClientCredentials->Domain, pWinStation->Config.Config.User.Domain);
  374. }
  375. }
  376. } else {
  377. // WsxEscape for GET_LONG_USERNAME failed
  378. MemFree(pWinStation->pNewClientCredentials);
  379. pWinStation->pNewClientCredentials = NULL ;
  380. }
  381. }
  382. /*
  383. * Store WinStation name in connect msg
  384. */
  385. RtlCopyMemory( WMsg.u.DoConnect.WinStationName,
  386. pWinStation->WinStationName,
  387. sizeof(WINSTATIONNAME) );
  388. /*
  389. * KLUDGE ALERT!!
  390. * The Wsx initializes AudioDriverName in the DoConnect struct.
  391. * However, we need to save it for later use during reconnect,
  392. * so we now copy it into the WinStation->Client struct.
  393. * (This field was NOT not initialized during the earlier
  394. * IOCTL_ICA_STACK_QUERY_CLIENT call.)
  395. */
  396. RtlCopyMemory( pWinStation->Client.AudioDriverName,
  397. WMsg.u.DoConnect.AudioDriverName,
  398. sizeof( pWinStation->Client.AudioDriverName ) );
  399. /*
  400. * Store protocol and Display driver name in WINSTATION since we may need them later for reconnect.
  401. */
  402. memset(pWinStation->ProtocolName, 0, sizeof(pWinStation->ProtocolName));
  403. memcpy(pWinStation->ProtocolName, WMsg.u.DoConnect.ProtocolName, sizeof(pWinStation->ProtocolName) - sizeof(WCHAR));
  404. memset(pWinStation->DisplayDriverName, 0, sizeof(pWinStation->DisplayDriverName));
  405. memcpy(pWinStation->DisplayDriverName, WMsg.u.DoConnect.DisplayDriverName, sizeof(pWinStation->DisplayDriverName) - sizeof(WCHAR));
  406. /*
  407. * Save protocol type, screen resolution, and color depth
  408. */
  409. WMsg.u.DoConnect.HRes = pWinStation->Client.HRes;
  410. WMsg.u.DoConnect.VRes = pWinStation->Client.VRes;
  411. WMsg.u.DoConnect.ProtocolType = pWinStation->Client.ProtocolType;
  412. /*
  413. * Translate the color to the format excpected in winsrv
  414. */
  415. switch(pWinStation->Client.ColorDepth){
  416. case 1:
  417. WMsg.u.DoConnect.ColorDepth=4 ; // 16 colors
  418. break;
  419. case 2:
  420. WMsg.u.DoConnect.ColorDepth=8 ; // 256
  421. break;
  422. case 4:
  423. WMsg.u.DoConnect.ColorDepth= 16;// 64K
  424. break;
  425. case 8:
  426. WMsg.u.DoConnect.ColorDepth= 24;// 16M
  427. break;
  428. #define DC_HICOLOR
  429. #ifdef DC_HICOLOR
  430. case 16:
  431. WMsg.u.DoConnect.ColorDepth= 15;// 32K
  432. break;
  433. #endif
  434. default:
  435. WMsg.u.DoConnect.ColorDepth=8 ;
  436. break;
  437. }
  438. WMsg.u.DoConnect.KeyboardType = pWinStation->Client.KeyboardType;
  439. WMsg.u.DoConnect.KeyboardSubType = pWinStation->Client.KeyboardSubType;
  440. WMsg.u.DoConnect.KeyboardFunctionKey = pWinStation->Client.KeyboardFunctionKey;
  441. /*
  442. * Tell Win32 about the connection
  443. */
  444. WMsg.ApiNumber = SMWinStationDoConnect;
  445. Status = SendWinStationCommand( pWinStation, &WMsg, 600 );
  446. TRACE((hTrace,TC_ICASRV,TT_API1,"TERMSRV: SMWinStationDoConnect %d Status=0x%x\n",
  447. pWinStation->LogonId, Status));
  448. if ( !NT_SUCCESS( Status ) ) {
  449. ReleaseWinStation( pWinStation );
  450. goto done;
  451. } else {
  452. pWinStation->StateFlags |= WSF_ST_CONNECTED_TO_CSRSS;
  453. }
  454. //
  455. //Set session time zone information.
  456. //
  457. #ifdef TERMSRV_USE_CLIENT_TIME_ZONE
  458. {
  459. WINSTATION_APIMSG TimezoneMsg;
  460. memset( &TimezoneMsg, 0, sizeof(TimezoneMsg) );
  461. TimezoneMsg.ApiNumber = SMWinStationSetTimeZone;
  462. memcpy(&(TimezoneMsg.u.SetTimeZone.TimeZone),&(pWinStation->Client.ClientTimeZone),
  463. sizeof(TS_TIME_ZONE_INFORMATION));
  464. SendWinStationCommand( pWinStation, &TimezoneMsg, 600 );
  465. }
  466. #endif
  467. /*
  468. * Indicate we're now connected. Only after succesful connection to Win32/CSR.
  469. */
  470. pWinStation->NeverConnected = FALSE;
  471. /*
  472. * Check if we received a broken connection indication while connecting to to Win32/CSR.
  473. */
  474. if (pWinStation->StateFlags & WSF_ST_BROKEN_CONNECTION) {
  475. QueueWinStationReset(pWinStation->LogonId);
  476. Status = STATUS_CTX_CLOSE_PENDING;
  477. ReleaseWinStation( pWinStation );
  478. goto done;
  479. }
  480. /*
  481. * Set connect time and start disconnect timer
  482. */
  483. NtQuerySystemTime( &pWinStation->ConnectTime );
  484. /*
  485. * Attempt to connect to the CdmRedirector
  486. * for Client Drive Mapping
  487. *
  488. * NOTE: We still init the WinStation even if Client Drive
  489. * mapping does not connect.
  490. */
  491. if ( pWinStation->pWsx &&
  492. pWinStation->pWsx->pWsxCdmConnect ) {
  493. Status = pWinStation->pWsx->pWsxCdmConnect( pWinStation->pWsxContext,
  494. pWinStation->LogonId,
  495. pWinStation->hIca );
  496. }
  497. TRACE((hTrace,TC_ICASRV,TT_API1,"TERMSRV: CdmConnect %d Status=0x%x\n",
  498. pWinStation->LogonId, Status));
  499. Status = STATUS_SUCCESS;
  500. pWinStation->State = State_Connected;
  501. NotifySystemEvent( WEVENT_CONNECT | WEVENT_STATECHANGE );
  502. Status = NotifyConnect(pWinStation, fOwnsConsoleTerminal);
  503. if ( !NT_SUCCESS(Status) ) {
  504. DBGPRINT(( "TERMSRV: NotifyConsoleConnect failed Status= 0x%x\n", Status));
  505. }
  506. /*
  507. * Release WinStation
  508. */
  509. ReleaseWinStation( pWinStation );
  510. done:
  511. /*
  512. * Failure here will cause Winlogon to terminate the session. If we are failing
  513. * the console session, let wake up the IdleControlThread, he may have to create
  514. * a new console session.
  515. */
  516. if (!NT_SUCCESS( Status ) && fOwnsConsoleTerminal) {
  517. NtSetEvent(WinStationIdleControlEvent, NULL);
  518. }
  519. return( Status );
  520. }
  521. // Since the physical console does not have a real client, init data to some defaults
  522. void InitializeConsoleClientData( PWINSTATIONCLIENTW pWC )
  523. {
  524. pWC->fTextOnly = FALSE;
  525. pWC->fDisableCtrlAltDel = FALSE;
  526. pWC->fMouse = TRUE;
  527. pWC->fDoubleClickDetect = FALSE;
  528. pWC->fINetClient = FALSE;
  529. pWC->fPromptForPassword = FALSE;
  530. pWC->fMaximizeShell = TRUE;
  531. pWC->fEnableWindowsKey = TRUE;
  532. pWC->fRemoteConsoleAudio= FALSE;
  533. wcscpy( pWC->ClientName , L"");
  534. wcscpy( pWC->Domain , L"");
  535. wcscpy( pWC->UserName , L"");
  536. wcscpy( pWC->Password , L"");
  537. wcscpy( pWC->WorkDirectory , L"");
  538. wcscpy( pWC->InitialProgram , L"");
  539. pWC->SerialNumber = 0; // client computer unique serial number
  540. pWC->EncryptionLevel = 3; // security level of encryption pd
  541. pWC->ClientAddressFamily = 0;
  542. wcscpy( pWC->ClientAddress , L"");
  543. pWC->HRes = 640;
  544. pWC->VRes = 480;
  545. pWC->ColorDepth = 0x2;
  546. pWC->ProtocolType = PROTOCOL_CONSOLE ;
  547. pWC->KeyboardLayout = 0;
  548. pWC->KeyboardType = 0;
  549. pWC->KeyboardSubType = 0;
  550. pWC->KeyboardFunctionKey = 0;
  551. wcscpy( pWC->imeFileName , L"");
  552. wcscpy( pWC->ClientDirectory, L"");
  553. wcscpy( pWC->ClientLicense , L"");
  554. wcscpy( pWC->ClientModem , L"");
  555. pWC->ClientBuildNumber = 0;
  556. pWC->ClientHardwareId = 0; // client software serial number
  557. pWC->ClientProductId = 0; // client software product id
  558. pWC->OutBufCountHost = 0; // number of outbufs on host
  559. pWC->OutBufCountClient = 0; // number of outbufs on client
  560. pWC->OutBufLength = 0; // length of outbufs in bytes
  561. wcscpy( pWC->AudioDriverName, L"" );
  562. pWC->ClientSessionId = LOGONID_NONE;
  563. {
  564. //This time zone information is invalid
  565. //using it we set BaseSrvpStaticServerData->TermsrvClientTimeZoneId to
  566. //TIME_ZONE_ID_INVALID!
  567. TS_TIME_ZONE_INFORMATION InvalidTZ={0,L"",
  568. {0,10,0,6/*this number makes it invalid; day numbers >5 not allowed*/,0,0,0,0},0,L"",
  569. {0,4,0,6/*this number makes it invalid*/,0,0,0,0},0};
  570. memcpy(&(pWC->ClientTimeZone), &InvalidTZ,
  571. sizeof(TS_TIME_ZONE_INFORMATION));
  572. }
  573. pWC->clientDigProductId[0] = 0;
  574. }
  575. BOOLEAN gConsoleNeverConnected = TRUE;
  576. NTSTATUS
  577. WaitForConsoleConnectWorker( PWINSTATION pWinStation )
  578. {
  579. OBJECT_ATTRIBUTES ObjA;
  580. ULONG ReturnLength;
  581. BYTE version;
  582. ULONG Offset;
  583. ICA_STACK_LAST_ERROR tdlasterror;
  584. WINSTATION_APIMSG WMsg;
  585. BOOLEAN rc;
  586. NTSTATUS Status;
  587. #define MODULE_SIZE 1024
  588. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WaitForConnectWorker, LogonId=%d\n",
  589. pWinStation->LogonId ));
  590. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_INFO_LEVEL, "TERMSRV: WaitForConsoleConnectWorker, LogonId=%d\n", pWinStation->LogonId ));
  591. if (pWinStation->LogonId == 0) {
  592. /*
  593. * We need to acquire console lock. UnLock winstation first to avoid deadlock.
  594. */
  595. UnlockWinStation( pWinStation );
  596. ENTERCRIT( &ConsoleLock );
  597. if (!RelockWinStation( pWinStation )) {
  598. LEAVECRIT( &ConsoleLock );
  599. return STATUS_CTX_WINSTATION_NOT_FOUND;
  600. }
  601. /*
  602. * You only go through this API once for console session.
  603. */
  604. if (!gConsoleNeverConnected) {
  605. LEAVECRIT( &ConsoleLock );
  606. return STATUS_SUCCESS;
  607. }
  608. }
  609. if (!pWinStation->pSecurityDescriptor && pWinStation->LogonId) {
  610. RtlAcquireResourceShared(&WinStationSecurityLock, TRUE);
  611. Status = RtlCopySecurityDescriptor(DefaultConsoleSecurityDescriptor,
  612. &(pWinStation->pSecurityDescriptor));
  613. RtlReleaseResource(&WinStationSecurityLock);
  614. }
  615. // Read console config,
  616. // For the session 0, this was already initalized in WinStationCreateWorker()
  617. if (pWinStation->LogonId != 0) {
  618. pWinStation->Config = gConsoleConfig;
  619. // initalize client data, since there isn't any real rdp client sending anythhing to us
  620. InitializeConsoleClientData( & pWinStation->Client );
  621. }
  622. /*
  623. * We are going to wait for a connect (Idle)
  624. */
  625. memset( &WMsg, 0, sizeof(WMsg) );
  626. pWinStation->State = State_ConnectQuery;
  627. NotifySystemEvent( WEVENT_STATECHANGE );
  628. /*
  629. * Initialize connect event to wait on
  630. */
  631. InitializeObjectAttributes( &ObjA, NULL, 0, NULL, NULL );
  632. if (pWinStation->ConnectEvent == NULL) {
  633. Status = NtCreateEvent( &pWinStation->ConnectEvent, EVENT_ALL_ACCESS, &ObjA,
  634. NotificationEvent, FALSE );
  635. if ( !NT_SUCCESS( Status ) ) {
  636. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WaitForConsoleConnectWorker, LogonId=%d, NtCreateEvent 0x%x\n",
  637. pWinStation->LogonId, Status ));
  638. goto done;
  639. }
  640. }
  641. /*
  642. * Duplicate the beep channel.
  643. * This is one channel that both CSR and ICASRV have open.
  644. */
  645. if (pWinStation->hIcaBeepChannel == NULL) {
  646. Status = IcaChannelOpen( pWinStation->hIca,
  647. Channel_Beep,
  648. NULL,
  649. &pWinStation->hIcaBeepChannel );
  650. if ( !NT_SUCCESS( Status ) ) {
  651. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WaitForConsoleConnectWorker, LogonId=%d, IcaChannelOpen 0x%x\n",
  652. pWinStation->LogonId, Status ));
  653. goto done;
  654. }
  655. }
  656. Status = NtDuplicateObject( NtCurrentProcess(),
  657. pWinStation->hIcaBeepChannel,
  658. pWinStation->WindowsSubSysProcess,
  659. &WMsg.u.DoConnect.hIcaBeepChannel,
  660. 0,
  661. 0,
  662. DUPLICATE_SAME_ACCESS );
  663. if ( !NT_SUCCESS( Status ) ) {
  664. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WaitForConsoleConnectWorker, LogonId=%d, NtDuplicateObject 0x%x\n",
  665. pWinStation->LogonId, Status ));
  666. goto done;
  667. }
  668. /*
  669. * Duplicate the thinwire channel.
  670. * This is one channel that both CSR and ICASRV have open.
  671. */
  672. if (pWinStation->hIcaThinwireChannel == NULL) {
  673. Status = IcaChannelOpen( pWinStation->hIca,
  674. Channel_Virtual,
  675. VIRTUAL_THINWIRE,
  676. &pWinStation->hIcaThinwireChannel );
  677. if ( !NT_SUCCESS( Status ) ) {
  678. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WaitForConsoleConnectWorker, LogonId=%d, IcaChannelOpen 0x%x\n",
  679. pWinStation->LogonId, Status ));
  680. goto done;
  681. }
  682. }
  683. Status = NtDuplicateObject( NtCurrentProcess(),
  684. pWinStation->hIcaThinwireChannel,
  685. pWinStation->WindowsSubSysProcess,
  686. &WMsg.u.DoConnect.hIcaThinwireChannel,
  687. 0,
  688. 0,
  689. DUPLICATE_SAME_ACCESS );
  690. if ( !NT_SUCCESS( Status ) ) {
  691. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WaitForConsoleConnectWorker, LogonId=%d, NtDuplicateObject 0x%x\n",
  692. pWinStation->LogonId, Status ));
  693. goto done;
  694. }
  695. Status = IcaChannelIoControl( pWinStation->hIcaThinwireChannel,
  696. IOCTL_ICA_CHANNEL_ENABLE_SHADOW,
  697. NULL, 0, NULL, 0, NULL );
  698. ASSERT( NT_SUCCESS( Status ) );
  699. /*
  700. * Video channel
  701. */
  702. Status = WinStationOpenChannel( pWinStation->hIca,
  703. pWinStation->WindowsSubSysProcess,
  704. Channel_Video,
  705. NULL,
  706. &WMsg.u.DoConnect.hIcaVideoChannel );
  707. if ( !NT_SUCCESS( Status ) ) {
  708. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WaitForConsoleConnectWorker, LogonId=%d, NtDuplicateObject 0x%x\n",
  709. pWinStation->LogonId, Status ));
  710. goto done;
  711. }
  712. /*
  713. * Keyboard channel
  714. */
  715. Status = WinStationOpenChannel( pWinStation->hIca,
  716. pWinStation->WindowsSubSysProcess,
  717. Channel_Keyboard,
  718. NULL,
  719. &WMsg.u.DoConnect.hIcaKeyboardChannel );
  720. if ( !NT_SUCCESS( Status ) ) {
  721. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WaitForConsoleConnectWorker, LogonId=%d, NtDuplicateObject 0x%x\n",
  722. pWinStation->LogonId, Status ));
  723. goto done;
  724. }
  725. /*
  726. * Mouse channel
  727. */
  728. Status = WinStationOpenChannel( pWinStation->hIca,
  729. pWinStation->WindowsSubSysProcess,
  730. Channel_Mouse,
  731. NULL,
  732. &WMsg.u.DoConnect.hIcaMouseChannel );
  733. if ( !NT_SUCCESS( Status ) ) {
  734. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WaitForConsoleConnectWorker, LogonId=%d, NtDuplicateObject 0x%x\n",
  735. pWinStation->LogonId, Status ));
  736. goto done;
  737. }
  738. /*
  739. * Command channel
  740. */
  741. Status = WinStationOpenChannel( pWinStation->hIca,
  742. pWinStation->WindowsSubSysProcess,
  743. Channel_Command,
  744. NULL,
  745. &WMsg.u.DoConnect.hIcaCommandChannel );
  746. if ( !NT_SUCCESS( Status ) ) {
  747. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WaitForConsoleConnectWorker, LogonId=%d, NtDuplicateObject 0x%x\n",
  748. pWinStation->LogonId, Status ));
  749. goto done;
  750. }
  751. if (!pWinStation->LogonId) {
  752. goto SkipClientData;
  753. }
  754. /*
  755. * Secure any virtual channels
  756. */
  757. VirtualChannelSecurity( pWinStation );
  758. /*
  759. * Tell Win32 about the connection
  760. */
  761. WMsg.u.DoConnect.fEnableWindowsKey = (BOOLEAN) pWinStation->Client.fEnableWindowsKey;
  762. SkipClientData:
  763. WMsg.ApiNumber = SMWinStationDoConnect;
  764. Status = SendWinStationCommand( pWinStation, &WMsg, 600 );
  765. TRACE((hTrace,TC_ICASRV,TT_API1,"TERMSRV: SMWinStationDoConnect %d Status=0x%x\n",
  766. pWinStation->LogonId, Status));
  767. if ( !NT_SUCCESS( Status ) ) {
  768. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WaitForConsoleConnectWorker SMWinStationDoConnect failed Status= 0x%x\n", Status));
  769. goto done;
  770. } else {
  771. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_INFO_LEVEL, "TERMSRV: WaitForConsoleConnectWorker SMWinStationDoConnect OK\n"));
  772. pWinStation->StateFlags |= WSF_ST_CONNECTED_TO_CSRSS;
  773. if (pWinStation->LogonId == 0) {
  774. gConsoleNeverConnected=FALSE;
  775. }
  776. }
  777. /*
  778. * Indicate we're now connected. Only after succesful connection to Win32/CSR.
  779. */
  780. pWinStation->NeverConnected = FALSE;
  781. /*
  782. * Check if we received a broken connection indication while connecting to to Win32/CSR.
  783. */
  784. if (pWinStation->StateFlags & WSF_ST_BROKEN_CONNECTION) {
  785. QueueWinStationReset(pWinStation->LogonId);
  786. Status = STATUS_CTX_CLOSE_PENDING;
  787. goto done;
  788. }
  789. /*
  790. * Set connect time and start disconnect timer
  791. */
  792. NtQuerySystemTime( &pWinStation->ConnectTime );
  793. /*
  794. * Attempt to connect to the CdmRedirector
  795. * for Client Drive Mapping
  796. *
  797. * NOTE: We still init the WinStation even if Client Drive
  798. * mapping does not connect.
  799. */
  800. if ( pWinStation->pWsx &&
  801. pWinStation->pWsx->pWsxCdmConnect ) {
  802. Status = pWinStation->pWsx->pWsxCdmConnect( pWinStation->pWsxContext,
  803. pWinStation->LogonId,
  804. pWinStation->hIca );
  805. }
  806. TRACE((hTrace,TC_ICASRV,TT_API1,"TERMSRV: CdmConnect %d Status=0x%x\n",
  807. pWinStation->LogonId, Status));
  808. Status = STATUS_SUCCESS;
  809. /*
  810. * Start logon timers
  811. */
  812. StartLogonTimers( pWinStation );
  813. pWinStation->State = State_Connected;
  814. NotifySystemEvent( WEVENT_CONNECT | WEVENT_STATECHANGE );
  815. Status = NotifyConnect(pWinStation, pWinStation->fOwnsConsoleTerminal);
  816. if ( !NT_SUCCESS(Status) ) {
  817. DBGPRINT(( "TERMSRV: NotifyConsoleConnect failed Status= 0x%x\n", Status));
  818. }
  819. done:
  820. //
  821. // Set the licensing policy for the console session. This must be done
  822. // to prevent a weird state when a console session goes remote. This must
  823. // Done weither wi faill or succeed. Licensing code assumes the policy is
  824. // set.
  825. //
  826. if (pWinStation->LogonId == 0) {
  827. LEAVECRIT( &ConsoleLock );
  828. }
  829. LCAssignPolicy(pWinStation);
  830. return( Status );
  831. }