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.

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