|
|
/*************************************************************************
* * wait.c * * WinStation wait for connection routines * * Copyright Microsoft Corporation, 1998 * * *************************************************************************/
/*
* Includes */ #include "precomp.h"
#pragma hdrstop
#include "conntfy.h"
// These are the maximum lengths of UserName, Password and Domain allowed by Winlogon
#define MAX_ALLOWED_USERNAME_LEN 255
#define MAX_ALLOWED_PASSWORD_LEN 126
#define MAX_ALLOWED_DOMAIN_LEN 255
/*=============================================================================
== Data =============================================================================*/
NTSTATUS WinStationInheritSecurityDescriptor( PVOID pSecurityDescriptor, PWINSTATION pTargetWinStation ); NTSTATUS WaitForConsoleConnectWorker( PWINSTATION pWinStation ); BOOL IsKernelDebuggerAttached();
//
//From regapi.dll
//
BOOLEAN RegIsTimeZoneRedirectionEnabled();
extern PSECURITY_DESCRIPTOR DefaultConsoleSecurityDescriptor;
extern WINSTATIONCONFIG2 gConsoleConfig; extern HANDLE WinStationIdleControlEvent; extern RTL_CRITICAL_SECTION ConsoleLock; extern RTL_RESOURCE WinStationSecurityLock;
/*****************************************************************************
* * WaitForConnectWorker * * Message parameter unmarshalling function for WinStation API. * * ENTRY: * pWinStation (input) * Pointer to our WinStation (locked) * * Note, comes in locked and returned released. * * EXIT: * STATUS_SUCCESS - no error * ****************************************************************************/
NTSTATUS WaitForConnectWorker( PWINSTATION pWinStation, HANDLE ClientProcessId ) { OBJECT_ATTRIBUTES ObjA; ULONG ReturnLength; BYTE version; ULONG Offset; ICA_STACK_LAST_ERROR tdlasterror; WINSTATION_APIMSG WMsg; BOOLEAN rc; NTSTATUS Status; BOOLEAN fOwnsConsoleTerminal = FALSE; ULONG BytesGot ;
#define MODULE_SIZE 1024
TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WaitForConnectWorker, LogonId=%d\n", pWinStation->LogonId ));
KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_INFO_LEVEL, "TERMSRV: WaitForConnectWorker, LogonId=%d\n",pWinStation->LogonId ));
/*
* You only go through this API once */ if ( !pWinStation->NeverConnected ) { ReleaseWinStation( pWinStation ); #ifdef DBG
DbgBreakPoint(); #endif
return( STATUS_ACCESS_DENIED ); }
// Should really be winlogon only here, however if ntsd is started
// then the first time we know it's winlogon is here.
/*
* Ensure this is WinLogon calling */ if ( ClientProcessId != pWinStation->InitialCommandProcessId ) {
/*
* If NTSD is started instead of winlogon, the InitialCommandProcessId is wrong. */ if ( !pWinStation->InitialProcessSet ) {
// need to close handle if already opened
if ( pWinStation->InitialCommandProcess ) { NtClose( pWinStation->InitialCommandProcess ); pWinStation->InitialCommandProcess = NULL; InvalidateTerminateWaitList(); }
pWinStation->InitialCommandProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, (DWORD)(UINT_PTR)ClientProcessId );
if ( pWinStation->InitialCommandProcess == NULL ) { ReleaseWinStation( pWinStation ); Status = STATUS_ACCESS_DENIED; goto done; } pWinStation->InitialCommandProcessId = ClientProcessId; pWinStation->InitialProcessSet = TRUE;
} else { ReleaseWinStation( pWinStation ); Status = STATUS_SUCCESS; goto done; } } else { /*
* Only do this once */ pWinStation->InitialProcessSet = TRUE; }
/*
* Console's work is done */
/*
* At this point the create is done. */ if (pWinStation->CreateEvent != NULL) { NtSetEvent( pWinStation->CreateEvent, NULL ); }
/*
* At this point The session may be terminating. If this is * the case, fail the call now. */
if ( pWinStation->Terminating ) { ReleaseWinStation( pWinStation ); Status = STATUS_CTX_CLOSE_PENDING; goto done; }
/*
* We are going to wait for a connect (Idle) */ memset( &WMsg, 0, sizeof(WMsg) ); pWinStation->State = State_Idle; NotifySystemEvent( WEVENT_STATECHANGE );
/*
* Initialize connect event to wait on */ InitializeObjectAttributes( &ObjA, NULL, 0, NULL, NULL ); Status = NtCreateEvent( &pWinStation->ConnectEvent, EVENT_ALL_ACCESS, &ObjA, NotificationEvent, FALSE );
if ( !NT_SUCCESS( Status ) ) { ReleaseWinStation( pWinStation ); goto done; }
/*
* OK, now wait for a connection */ UnlockWinStation( pWinStation ); Status = NtWaitForSingleObject( pWinStation->ConnectEvent, FALSE, NULL ); rc = RelockWinStation( pWinStation );
if ( !NT_SUCCESS(Status) ) { ReleaseWinStation( pWinStation ); goto done;
}
fOwnsConsoleTerminal = pWinStation->fOwnsConsoleTerminal;
if (pWinStation->ConnectEvent) { NtClose( pWinStation->ConnectEvent ); pWinStation->ConnectEvent = NULL; } if ( !rc || pWinStation->Terminating ) { ReleaseWinStation( pWinStation ); Status = STATUS_CTX_CLOSE_PENDING; goto done; }
// if this is a connect to the console session, Do all the console specific.
if (fOwnsConsoleTerminal) { Status = WaitForConsoleConnectWorker( pWinStation ); ReleaseWinStation( pWinStation ); goto done; }
/*
* Reset the broken connection Flag. * */
pWinStation->StateFlags &= ~WSF_ST_BROKEN_CONNECTION;
/*
* Duplicate the beep channel. * This is one channel that both CSR and ICASRV have open. */ Status = IcaChannelOpen( pWinStation->hIca, Channel_Beep, NULL, &pWinStation->hIcaBeepChannel );
if ( !NT_SUCCESS( Status ) ) { ReleaseWinStation( pWinStation ); KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WinStationWaitForConnect, LogonId=%d, IcaChannelOpen 0x%x\n", pWinStation->LogonId, Status )); goto done; }
Status = NtDuplicateObject( NtCurrentProcess(), pWinStation->hIcaBeepChannel, pWinStation->WindowsSubSysProcess, &WMsg.u.DoConnect.hIcaBeepChannel, 0, 0, DUPLICATE_SAME_ACCESS );
if ( !NT_SUCCESS( Status ) ) { ReleaseWinStation( pWinStation ); KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WinStationWaitForConnect, LogonId=%d, NtDuplicateObject 0x%x\n", pWinStation->LogonId, Status )); goto done; }
/*
* Duplicate the thinwire channel. * This is one channel that both CSR and ICASRV have open. */ Status = IcaChannelOpen( pWinStation->hIca, Channel_Virtual, VIRTUAL_THINWIRE, &pWinStation->hIcaThinwireChannel );
if ( !NT_SUCCESS( Status ) ) { ReleaseWinStation( pWinStation ); KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WinStationWaitForConnect, LogonId=%d, IcaChannelOpen 0x%x\n", pWinStation->LogonId, Status )); goto done; }
Status = NtDuplicateObject( NtCurrentProcess(), pWinStation->hIcaThinwireChannel, pWinStation->WindowsSubSysProcess, &WMsg.u.DoConnect.hIcaThinwireChannel, 0, 0, DUPLICATE_SAME_ACCESS );
if ( !NT_SUCCESS( Status ) ) { ReleaseWinStation( pWinStation ); KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WinStationWaitForConnect, LogonId=%d, NtDuplicateObject 0x%x\n", pWinStation->LogonId, Status )); goto done; }
Status = IcaChannelIoControl( pWinStation->hIcaThinwireChannel, IOCTL_ICA_CHANNEL_ENABLE_SHADOW, NULL, 0, NULL, 0, NULL ); ASSERT( NT_SUCCESS( Status ) );
/*
* Video channel */ Status = WinStationOpenChannel( pWinStation->hIca, pWinStation->WindowsSubSysProcess, Channel_Video, NULL, &WMsg.u.DoConnect.hIcaVideoChannel ); if ( !NT_SUCCESS( Status ) ) { ReleaseWinStation( pWinStation ); KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WinStationOpenChannel, LogonId=%d, NtDuplicateObject 0x%x\n", pWinStation->LogonId, Status )); goto done; }
/*
* Keyboard channel */ Status = WinStationOpenChannel( pWinStation->hIca, pWinStation->WindowsSubSysProcess, Channel_Keyboard, NULL, &WMsg.u.DoConnect.hIcaKeyboardChannel ); if ( !NT_SUCCESS( Status ) ) { ReleaseWinStation( pWinStation ); KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WinStationOpenChannel, LogonId=%d, NtDuplicateObject 0x%x\n", pWinStation->LogonId, Status )); goto done; }
/*
* Mouse channel */ Status = WinStationOpenChannel( pWinStation->hIca, pWinStation->WindowsSubSysProcess, Channel_Mouse, NULL, &WMsg.u.DoConnect.hIcaMouseChannel ); if ( !NT_SUCCESS( Status ) ) { ReleaseWinStation( pWinStation ); KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WinStationOpenChannel, LogonId=%d, NtDuplicateObject 0x%x\n", pWinStation->LogonId, Status )); goto done; }
/*
* Command channel */ Status = WinStationOpenChannel( pWinStation->hIca, pWinStation->WindowsSubSysProcess, Channel_Command, NULL, &WMsg.u.DoConnect.hIcaCommandChannel ); if ( !NT_SUCCESS( Status ) ) { ReleaseWinStation( pWinStation ); KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WinStationOpenChannel, LogonId=%d, NtDuplicateObject 0x%x\n", pWinStation->LogonId, Status )); goto done; }
/*
* Secure any virtual channels */ VirtualChannelSecurity( pWinStation );
// HACK? Yes int the sense that a tmp session is getting some attribs of session0 but no
// in the sense that the purpose of the tmp session is to finally connect to session0 given our current design.
//
// Its possible that we are dealing with a tmp session here, due to the fact that user has
// selected /CONSOLE and we will login into a tmp session and then reconnect to session0 after
// we pass creds to session zero's winlogon.
// So we have a prlblem here where login is talking place inside a temp session but the target is
// session0.
// If TSCC was setup to use a specific creds for all remote session, we don't want to use that cred for the
// tmp session since we really are tryint to get to session0, and TSCC's config for rdp sessions should not hold.
// AraBern 09/13/2002
if (pWinStation->bRequestedSessionIDFieldValid && ( pWinStation->RequestedSessionID == 0 ) ) { // we are dealing with a tmp session and we intend to connect to console session assuming
// good login
PWINSTATION pWinStation_0;
if ( pWinStation_0 = FindWinStationById( 0, FALSE ) ) { pWinStation->Config.Config.User.fInheritAutoLogon = pWinStation_0->Config.Config.User.fInheritAutoLogon ;
pWinStation->Config.Config.User.fPromptForPassword = pWinStation_0->Config.Config.User.fPromptForPassword ;
ReleaseWinStation( pWinStation_0 ); } }
/*
* Client specific connection extension completion */ if ( pWinStation->pWsx && pWinStation->pWsx->pWsxInitializeClientData ) { Status = pWinStation->pWsx->pWsxInitializeClientData( pWinStation->pWsxContext, pWinStation->hStack, pWinStation->hIca, pWinStation->hIcaThinwireChannel, pWinStation->VideoModuleName, sizeof(pWinStation->VideoModuleName), &pWinStation->Config.Config.User, &pWinStation->Client.HRes, &pWinStation->Client.VRes, &pWinStation->Client.ColorDepth, &WMsg.u.DoConnect ); if ( !NT_SUCCESS( Status ) ) { ReleaseWinStation( pWinStation ); goto done; }
if (pWinStation->LogonId == 0 || g_bPersonalTS) { if (pWinStation->hWinmmConsoleAudioEvent) { if (pWinStation->Client.fRemoteConsoleAudio) { // Set the console audio event - means console audio can be remoted
SetEvent(pWinStation->hWinmmConsoleAudioEvent); } else { // Set the console audio event - means console audio can't be remoted
ResetEvent(pWinStation->hWinmmConsoleAudioEvent); } } } }
/* Get long UserNames and Password now */ /* Do this only if Client autologon credentials are needed */ /* If Server logon settings are going to Override Client logon settings, no need to do this at all */
if ( pWinStation->pWsx && pWinStation->pWsx->pWsxEscape && pWinStation->Config.Config.User.fInheritAutoLogon ) {
pWinStation->pNewClientCredentials = MemAlloc( sizeof(ExtendedClientCredentials) ); if (pWinStation->pNewClientCredentials == NULL) { ReleaseWinStation( pWinStation ); Status = STATUS_NO_MEMORY; goto done; } Status = pWinStation->pWsx->pWsxEscape( pWinStation->pWsxContext, GET_LONG_USERNAME, NULL, 0, pWinStation->pNewClientCredentials, sizeof(ExtendedClientCredentials), &BytesGot) ;
if (NT_SUCCESS(Status)) {
// WsxEscape for GET_LONG_USERNAME succeeded
// Check if u need the ExtendedClientCredentials - the common case is short UserName and
// short password - so optimize the common case
if ( (wcslen(pWinStation->pNewClientCredentials->UserName) <= USERNAME_LENGTH) && (wcslen(pWinStation->pNewClientCredentials->Password) <= PASSWORD_LENGTH) && (wcslen(pWinStation->pNewClientCredentials->Domain) <= DOMAIN_LENGTH) ) {
// We can use the old credentials itself
MemFree(pWinStation->pNewClientCredentials); pWinStation->pNewClientCredentials = NULL ; } // Winlogon does not allow > 126 chars for Password and > 255 chars for UserName and Domain in some code paths
// So we have to use the old truncated credentials in case the extended credentials exceed these limits
if (pWinStation->pNewClientCredentials != NULL) { if (wcslen(pWinStation->pNewClientCredentials->UserName) > MAX_ALLOWED_USERNAME_LEN) { wcscpy(pWinStation->pNewClientCredentials->UserName, pWinStation->Config.Config.User.UserName); } if (wcslen(pWinStation->pNewClientCredentials->Password) > MAX_ALLOWED_PASSWORD_LEN) { wcscpy(pWinStation->pNewClientCredentials->Password, pWinStation->Config.Config.User.Password); } if (wcslen(pWinStation->pNewClientCredentials->Domain) > MAX_ALLOWED_DOMAIN_LEN) { wcscpy(pWinStation->pNewClientCredentials->Domain, pWinStation->Config.Config.User.Domain); } } } else { // WsxEscape for GET_LONG_USERNAME failed
MemFree(pWinStation->pNewClientCredentials); pWinStation->pNewClientCredentials = NULL ; }
}
/*
* Store WinStation name in connect msg */ RtlCopyMemory( WMsg.u.DoConnect.WinStationName, pWinStation->WinStationName, sizeof(WINSTATIONNAME) );
/*
* KLUDGE ALERT!! * The Wsx initializes AudioDriverName in the DoConnect struct. * However, we need to save it for later use during reconnect, * so we now copy it into the WinStation->Client struct. * (This field was NOT not initialized during the earlier * IOCTL_ICA_STACK_QUERY_CLIENT call.) */ RtlCopyMemory( pWinStation->Client.AudioDriverName, WMsg.u.DoConnect.AudioDriverName, sizeof( pWinStation->Client.AudioDriverName ) );
/*
* Store protocol and Display driver name in WINSTATION since we may need them later for reconnect. */
memset(pWinStation->ProtocolName, 0, sizeof(pWinStation->ProtocolName)); memcpy(pWinStation->ProtocolName, WMsg.u.DoConnect.ProtocolName, sizeof(pWinStation->ProtocolName) - sizeof(WCHAR));
memset(pWinStation->DisplayDriverName, 0, sizeof(pWinStation->DisplayDriverName)); memcpy(pWinStation->DisplayDriverName, WMsg.u.DoConnect.DisplayDriverName, sizeof(pWinStation->DisplayDriverName) - sizeof(WCHAR));
/*
* Save protocol type, screen resolution, and color depth */ WMsg.u.DoConnect.HRes = pWinStation->Client.HRes; WMsg.u.DoConnect.VRes = pWinStation->Client.VRes; WMsg.u.DoConnect.ProtocolType = pWinStation->Client.ProtocolType;
/*
* Translate the color to the format excpected in winsrv */
switch(pWinStation->Client.ColorDepth){ case 1: WMsg.u.DoConnect.ColorDepth=4 ; // 16 colors
break; case 2: WMsg.u.DoConnect.ColorDepth=8 ; // 256
break; case 4: WMsg.u.DoConnect.ColorDepth= 16;// 64K
break; case 8: WMsg.u.DoConnect.ColorDepth= 24;// 16M
break; #define DC_HICOLOR
#ifdef DC_HICOLOR
case 16: WMsg.u.DoConnect.ColorDepth= 15;// 32K
break; #endif
default: WMsg.u.DoConnect.ColorDepth=8 ; break; }
WMsg.u.DoConnect.KeyboardType = pWinStation->Client.KeyboardType; WMsg.u.DoConnect.KeyboardSubType = pWinStation->Client.KeyboardSubType; WMsg.u.DoConnect.KeyboardFunctionKey = pWinStation->Client.KeyboardFunctionKey;
/*
* Tell Win32 about the connection */
WMsg.ApiNumber = SMWinStationDoConnect;
Status = SendWinStationCommand( pWinStation, &WMsg, 600 );
TRACE((hTrace,TC_ICASRV,TT_API1,"TERMSRV: SMWinStationDoConnect %d Status=0x%x\n", pWinStation->LogonId, Status));
if ( !NT_SUCCESS( Status ) ) { ReleaseWinStation( pWinStation ); goto done; } else { pWinStation->StateFlags |= WSF_ST_CONNECTED_TO_CSRSS;
}
//
//Set session time zone information.
//
if(pWinStation->LogonId != 0 && !pWinStation->fOwnsConsoleTerminal && RegIsTimeZoneRedirectionEnabled()) { WINSTATION_APIMSG TimezoneMsg; memset( &TimezoneMsg, 0, sizeof(TimezoneMsg) );
TimezoneMsg.ApiNumber = SMWinStationSetTimeZone; memcpy(&(TimezoneMsg.u.SetTimeZone.TimeZone),&(pWinStation->Client.ClientTimeZone), sizeof(TS_TIME_ZONE_INFORMATION));
SendWinStationCommand( pWinStation, &TimezoneMsg, 600 );
}
/*
* Indicate we're now connected. Only after succesful connection to Win32/CSR. */ pWinStation->NeverConnected = FALSE;
/*
* Check if we received a broken connection indication while connecting to to Win32/CSR. */
if (pWinStation->StateFlags & WSF_ST_BROKEN_CONNECTION) { QueueWinStationReset(pWinStation->LogonId); Status = STATUS_CTX_CLOSE_PENDING; ReleaseWinStation( pWinStation ); goto done; }
/*
* Set connect time and start disconnect timer */ NtQuerySystemTime( &pWinStation->ConnectTime );
/*
* Attempt to connect to the CdmRedirector * for Client Drive Mapping * * NOTE: We still init the WinStation even if Client Drive * mapping does not connect. */ if ( pWinStation->pWsx && pWinStation->pWsx->pWsxCdmConnect ) { Status = pWinStation->pWsx->pWsxCdmConnect( pWinStation->pWsxContext, pWinStation->LogonId, pWinStation->hIca ); }
TRACE((hTrace,TC_ICASRV,TT_API1,"TERMSRV: CdmConnect %d Status=0x%x\n", pWinStation->LogonId, Status));
Status = STATUS_SUCCESS;
pWinStation->State = State_Connected; NotifySystemEvent( WEVENT_CONNECT | WEVENT_STATECHANGE );
Status = NotifyConnect(pWinStation, fOwnsConsoleTerminal); if ( !NT_SUCCESS(Status) ) { DBGPRINT(( "TERMSRV: NotifyConsoleConnect failed Status= 0x%x\n", Status)); }
/*
* Release WinStation */ ReleaseWinStation( pWinStation );
done:
/*
* Failure here will cause Winlogon to terminate the session. If we are failing * the console session, let wake up the IdleControlThread, he may have to create * a new console session. */ if (!NT_SUCCESS( Status ) && fOwnsConsoleTerminal) { NtSetEvent(WinStationIdleControlEvent, NULL); }
return( Status ); }
// Since the physical console does not have a real client, init data to some defaults
void InitializeConsoleClientData( PWINSTATIONCLIENTW pWC ) { pWC->fTextOnly = FALSE; pWC->fDisableCtrlAltDel = FALSE; pWC->fMouse = TRUE; pWC->fDoubleClickDetect = FALSE; pWC->fINetClient = FALSE; pWC->fPromptForPassword = FALSE; pWC->fMaximizeShell = TRUE; pWC->fEnableWindowsKey = TRUE; pWC->fRemoteConsoleAudio= FALSE; wcscpy( pWC->ClientName , L""); wcscpy( pWC->Domain , L""); wcscpy( pWC->UserName , L""); wcscpy( pWC->Password , L""); wcscpy( pWC->WorkDirectory , L""); wcscpy( pWC->InitialProgram , L""); pWC->SerialNumber = 0; // client computer unique serial number
pWC->EncryptionLevel = 3; // security level of encryption pd
pWC->ClientAddressFamily = 0; wcscpy( pWC->ClientAddress , L""); pWC->HRes = 640; pWC->VRes = 480; pWC->ColorDepth = 0x2; pWC->ProtocolType = PROTOCOL_CONSOLE ; pWC->KeyboardLayout = 0; pWC->KeyboardType = 0; pWC->KeyboardSubType = 0; pWC->KeyboardFunctionKey = 0; wcscpy( pWC->imeFileName , L""); wcscpy( pWC->ClientDirectory, L""); wcscpy( pWC->ClientLicense , L""); wcscpy( pWC->ClientModem , L""); pWC->ClientBuildNumber = 0; pWC->ClientHardwareId = 0; // client software serial number
pWC->ClientProductId = 0; // client software product id
pWC->OutBufCountHost = 0; // number of outbufs on host
pWC->OutBufCountClient = 0; // number of outbufs on client
pWC->OutBufLength = 0; // length of outbufs in bytes
wcscpy( pWC->AudioDriverName, L"" );
pWC->ClientSessionId = LOGONID_NONE; { //This time zone information is invalid
//using it we set BaseSrvpStaticServerData->TermsrvClientTimeZoneId to
//TIME_ZONE_ID_INVALID!
TS_TIME_ZONE_INFORMATION InvalidTZ={0,L"", {0,10,0,6/*this number makes it invalid; day numbers >5 not allowed*/,0,0,0,0},0,L"", {0,4,0,6/*this number makes it invalid*/,0,0,0,0},0};
memcpy(&(pWC->ClientTimeZone), &InvalidTZ, sizeof(TS_TIME_ZONE_INFORMATION)); }
pWC->clientDigProductId[0] = 0; }
BOOLEAN gConsoleNeverConnected = TRUE;
NTSTATUS WaitForConsoleConnectWorker( PWINSTATION pWinStation ) { OBJECT_ATTRIBUTES ObjA; ULONG ReturnLength; BYTE version; ULONG Offset; ICA_STACK_LAST_ERROR tdlasterror; WINSTATION_APIMSG WMsg; BOOLEAN rc; NTSTATUS Status;
#define MODULE_SIZE 1024
TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WaitForConnectWorker, LogonId=%d\n", pWinStation->LogonId ));
KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_INFO_LEVEL, "TERMSRV: WaitForConsoleConnectWorker, LogonId=%d\n", pWinStation->LogonId ));
if (pWinStation->LogonId == 0) { /*
* We need to acquire console lock. UnLock winstation first to avoid deadlock. */
UnlockWinStation( pWinStation ); ENTERCRIT( &ConsoleLock ); if (!RelockWinStation( pWinStation )) { LEAVECRIT( &ConsoleLock ); return STATUS_CTX_WINSTATION_NOT_FOUND; }
/*
* You only go through this API once for console session. */ if (!gConsoleNeverConnected) { LEAVECRIT( &ConsoleLock ); return STATUS_SUCCESS; } }
if (!pWinStation->pSecurityDescriptor && pWinStation->LogonId) { RtlAcquireResourceShared(&WinStationSecurityLock, TRUE); Status = RtlCopySecurityDescriptor(DefaultConsoleSecurityDescriptor, &(pWinStation->pSecurityDescriptor)); RtlReleaseResource(&WinStationSecurityLock); }
// Read console config,
// For the session 0, this was already initalized in WinStationCreateWorker()
if (pWinStation->LogonId != 0) {
pWinStation->Config = gConsoleConfig;
// initalize client data, since there isn't any real rdp client sending anythhing to us
InitializeConsoleClientData( & pWinStation->Client ); }
/*
* We are going to wait for a connect (Idle) */ memset( &WMsg, 0, sizeof(WMsg) ); pWinStation->State = State_ConnectQuery; NotifySystemEvent( WEVENT_STATECHANGE );
/*
* Initialize connect event to wait on */ InitializeObjectAttributes( &ObjA, NULL, 0, NULL, NULL ); if (pWinStation->ConnectEvent == NULL) { Status = NtCreateEvent( &pWinStation->ConnectEvent, EVENT_ALL_ACCESS, &ObjA, NotificationEvent, FALSE ); if ( !NT_SUCCESS( Status ) ) { KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WaitForConsoleConnectWorker, LogonId=%d, NtCreateEvent 0x%x\n", pWinStation->LogonId, Status )); goto done; }
}
/*
* Duplicate the beep channel. * This is one channel that both CSR and ICASRV have open. */ if (pWinStation->hIcaBeepChannel == NULL) { Status = IcaChannelOpen( pWinStation->hIca, Channel_Beep, NULL, &pWinStation->hIcaBeepChannel );
if ( !NT_SUCCESS( Status ) ) { KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WaitForConsoleConnectWorker, LogonId=%d, IcaChannelOpen 0x%x\n", pWinStation->LogonId, Status )); goto done; } }
Status = NtDuplicateObject( NtCurrentProcess(), pWinStation->hIcaBeepChannel, pWinStation->WindowsSubSysProcess, &WMsg.u.DoConnect.hIcaBeepChannel, 0, 0, DUPLICATE_SAME_ACCESS );
if ( !NT_SUCCESS( Status ) ) { KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WaitForConsoleConnectWorker, LogonId=%d, NtDuplicateObject 0x%x\n", pWinStation->LogonId, Status )); goto done; }
/*
* Duplicate the thinwire channel. * This is one channel that both CSR and ICASRV have open. */ if (pWinStation->hIcaThinwireChannel == NULL) { Status = IcaChannelOpen( pWinStation->hIca, Channel_Virtual, VIRTUAL_THINWIRE, &pWinStation->hIcaThinwireChannel );
if ( !NT_SUCCESS( Status ) ) { KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WaitForConsoleConnectWorker, LogonId=%d, IcaChannelOpen 0x%x\n", pWinStation->LogonId, Status )); goto done; } }
Status = NtDuplicateObject( NtCurrentProcess(), pWinStation->hIcaThinwireChannel, pWinStation->WindowsSubSysProcess, &WMsg.u.DoConnect.hIcaThinwireChannel, 0, 0, DUPLICATE_SAME_ACCESS );
if ( !NT_SUCCESS( Status ) ) { KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WaitForConsoleConnectWorker, LogonId=%d, NtDuplicateObject 0x%x\n", pWinStation->LogonId, Status )); goto done; }
Status = IcaChannelIoControl( pWinStation->hIcaThinwireChannel, IOCTL_ICA_CHANNEL_ENABLE_SHADOW, NULL, 0, NULL, 0, NULL ); ASSERT( NT_SUCCESS( Status ) );
/*
* Video channel */ Status = WinStationOpenChannel( pWinStation->hIca, pWinStation->WindowsSubSysProcess, Channel_Video, NULL, &WMsg.u.DoConnect.hIcaVideoChannel ); if ( !NT_SUCCESS( Status ) ) { KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WaitForConsoleConnectWorker, LogonId=%d, NtDuplicateObject 0x%x\n", pWinStation->LogonId, Status )); goto done; }
/*
* Keyboard channel */ Status = WinStationOpenChannel( pWinStation->hIca, pWinStation->WindowsSubSysProcess, Channel_Keyboard, NULL, &WMsg.u.DoConnect.hIcaKeyboardChannel ); if ( !NT_SUCCESS( Status ) ) { KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WaitForConsoleConnectWorker, LogonId=%d, NtDuplicateObject 0x%x\n", pWinStation->LogonId, Status )); goto done; }
/*
* Mouse channel */ Status = WinStationOpenChannel( pWinStation->hIca, pWinStation->WindowsSubSysProcess, Channel_Mouse, NULL, &WMsg.u.DoConnect.hIcaMouseChannel ); if ( !NT_SUCCESS( Status ) ) { KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WaitForConsoleConnectWorker, LogonId=%d, NtDuplicateObject 0x%x\n", pWinStation->LogonId, Status )); goto done; }
/*
* Command channel */ Status = WinStationOpenChannel( pWinStation->hIca, pWinStation->WindowsSubSysProcess, Channel_Command, NULL, &WMsg.u.DoConnect.hIcaCommandChannel ); if ( !NT_SUCCESS( Status ) ) { KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WaitForConsoleConnectWorker, LogonId=%d, NtDuplicateObject 0x%x\n", pWinStation->LogonId, Status )); goto done; }
if (!pWinStation->LogonId) { goto SkipClientData; } /*
* Secure any virtual channels */ VirtualChannelSecurity( pWinStation );
/*
* Tell Win32 about the connection */
WMsg.u.DoConnect.fEnableWindowsKey = (BOOLEAN) pWinStation->Client.fEnableWindowsKey; SkipClientData: WMsg.ApiNumber = SMWinStationDoConnect;
Status = SendWinStationCommand( pWinStation, &WMsg, 600 );
TRACE((hTrace,TC_ICASRV,TT_API1,"TERMSRV: SMWinStationDoConnect %d Status=0x%x\n", pWinStation->LogonId, Status));
if ( !NT_SUCCESS( Status ) ) { KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WaitForConsoleConnectWorker SMWinStationDoConnect failed Status= 0x%x\n", Status)); goto done; } else { KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_INFO_LEVEL, "TERMSRV: WaitForConsoleConnectWorker SMWinStationDoConnect OK\n")); pWinStation->StateFlags |= WSF_ST_CONNECTED_TO_CSRSS; if (pWinStation->LogonId == 0) { gConsoleNeverConnected=FALSE; }
}
/*
* Indicate we're now connected. Only after succesful connection to Win32/CSR. */ pWinStation->NeverConnected = FALSE;
/*
* Check if we received a broken connection indication while connecting to to Win32/CSR. */
if (pWinStation->StateFlags & WSF_ST_BROKEN_CONNECTION) { QueueWinStationReset(pWinStation->LogonId); Status = STATUS_CTX_CLOSE_PENDING; goto done; }
/*
* Set connect time and start disconnect timer */ NtQuerySystemTime( &pWinStation->ConnectTime );
/*
* Attempt to connect to the CdmRedirector * for Client Drive Mapping * * NOTE: We still init the WinStation even if Client Drive * mapping does not connect. */ if ( pWinStation->pWsx && pWinStation->pWsx->pWsxCdmConnect ) { Status = pWinStation->pWsx->pWsxCdmConnect( pWinStation->pWsxContext, pWinStation->LogonId, pWinStation->hIca ); }
TRACE((hTrace,TC_ICASRV,TT_API1,"TERMSRV: CdmConnect %d Status=0x%x\n", pWinStation->LogonId, Status));
Status = STATUS_SUCCESS;
/*
* Start logon timers */ StartLogonTimers( pWinStation );
pWinStation->State = State_Connected; NotifySystemEvent( WEVENT_CONNECT | WEVENT_STATECHANGE );
Status = NotifyConnect(pWinStation, pWinStation->fOwnsConsoleTerminal); if ( !NT_SUCCESS(Status) ) { DBGPRINT(( "TERMSRV: NotifyConsoleConnect failed Status= 0x%x\n", Status)); }
done: //
// Set the licensing policy for the console session. This must be done
// to prevent a weird state when a console session goes remote. This must
// Done weither wi faill or succeed. Licensing code assumes the policy is
// set.
//
if (pWinStation->LogonId == 0) { LEAVECRIT( &ConsoleLock ); } LCAssignPolicy(pWinStation);
return( Status ); }
|