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.
2444 lines
81 KiB
2444 lines
81 KiB
// TelnSrv.cpp : This file contains the
|
|
// Created: Jan '98
|
|
// Author : a-rakeba
|
|
// History:
|
|
// Copyright (C) 1998 Microsoft Corporation
|
|
// All rights reserved.
|
|
// Microsoft Confidential
|
|
|
|
#include <StdAfx.h>
|
|
|
|
#include <TChar.h>
|
|
|
|
#include <Debug.h>
|
|
#include <MsgFile.h>
|
|
#include <RegUtil.h>
|
|
#include <TelnetD.h>
|
|
#include <TlntUtils.h>
|
|
#include <TlntDynamicArray.h>
|
|
#include <TelntSrv.h>
|
|
#include <Ipc.h>
|
|
#include <Resource.h>
|
|
|
|
#include <wincrypt.h>
|
|
|
|
#pragma warning( disable: 4706 )
|
|
|
|
using namespace _Utils;
|
|
using CDebugLevel::TRACE_DEBUGGING;
|
|
using CDebugLevel::TRACE_HANDLE;
|
|
using CDebugLevel::TRACE_SOCKET;
|
|
|
|
extern TCHAR g_szMaxConnectionsReached[ MAX_STRING_LENGTH ];
|
|
extern HINSTANCE g_hInstRes;
|
|
extern LPWSTR g_pszTelnetInstallPath;
|
|
extern HANDLE *g_phLogFile;
|
|
extern LPWSTR g_pszLogFile;
|
|
extern LONG g_lMaxFileSize;
|
|
extern bool g_fLogToFile;
|
|
extern HANDLE g_hSyncCloseHandle;
|
|
extern CTelnetService* g_pTelnetService;
|
|
extern HCRYPTPROV g_hProv;
|
|
|
|
#define WINSTA_ALL (WINSTA_ACCESSCLIPBOARD | WINSTA_ACCESSGLOBALATOMS | \
|
|
WINSTA_CREATEDESKTOP | WINSTA_ENUMDESKTOPS | \
|
|
WINSTA_ENUMERATE | WINSTA_EXITWINDOWS | \
|
|
WINSTA_READATTRIBUTES | WINSTA_READSCREEN | \
|
|
WINSTA_WRITEATTRIBUTES | DELETE | \
|
|
READ_CONTROL | WRITE_DAC | \
|
|
WRITE_OWNER)
|
|
|
|
|
|
bool SetWinstaSecurity()
|
|
{
|
|
bool bStatus = FALSE;
|
|
BOOL bRetVal = FALSE;
|
|
DWORD dwErrCode = 0;
|
|
PSID pSidAdministrators = NULL, pSidLocalSystem = NULL, pSidLocalService = NULL, pSidNetworkService = NULL, pSidTelnetClients = NULL;
|
|
PACL newACL = NULL;
|
|
SECURITY_DESCRIPTOR sd = { 0 };
|
|
HWINSTA window_station = NULL;
|
|
SECURITY_ATTRIBUTES sa = { 0 };
|
|
SECURITY_INFORMATION sec_i = DACL_SECURITY_INFORMATION;
|
|
DWORD aclSize;
|
|
SID_IDENTIFIER_AUTHORITY local_system_authority = SECURITY_NT_AUTHORITY;
|
|
SID_IDENTIFIER_AUTHORITY worldAuthority = SECURITY_WORLD_SID_AUTHORITY;
|
|
ACCESS_ALLOWED_ACE *pace = NULL;
|
|
|
|
|
|
//Build administrators alias sid
|
|
if (! AllocateAndInitializeSid(
|
|
&local_system_authority,
|
|
2, /* there are only two sub-authorities */
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
DOMAIN_ALIAS_RID_ADMINS,
|
|
0,0,0,0,0,0, /* Don't care about the rest */
|
|
&pSidAdministrators
|
|
))
|
|
{
|
|
goto ExitOnError;
|
|
}
|
|
|
|
//Build LocalSystem sid
|
|
if (! AllocateAndInitializeSid(
|
|
&local_system_authority,
|
|
1, /* there is only one sub-authority */
|
|
SECURITY_LOCAL_SYSTEM_RID,
|
|
0,0,0,0,0,0,0, /* Don't care about the rest */
|
|
&pSidLocalSystem
|
|
))
|
|
{
|
|
goto ExitOnError;
|
|
}
|
|
#ifndef SECURITY_LOCAL_SERVICE_RID
|
|
|
|
#define SECURITY_LOCAL_SERVICE_RID (0x00000013L)
|
|
#define SECURITY_NETWORK_SERVICE_RID (0x00000014L)
|
|
|
|
#endif
|
|
|
|
//Build LocalLocal sid
|
|
if ( ! AllocateAndInitializeSid(
|
|
&local_system_authority,
|
|
1, /* there is only one sub-authority */
|
|
SECURITY_LOCAL_SERVICE_RID,
|
|
0,0,0,0,0,0,0, /* Don't care about the rest */
|
|
&pSidLocalService
|
|
) )
|
|
{
|
|
goto ExitOnError;
|
|
}
|
|
/*
|
|
//Build LocalSystem sid
|
|
if ( ! AllocateAndInitializeSid(
|
|
&local_system_authority,
|
|
1, /* there is only one sub-authority /
|
|
SECURITY_NETWORK_SERVICE_RID,
|
|
0,0,0,0,0,0,0, /* Don't care about the rest /
|
|
&pSidNetworkService
|
|
) )
|
|
{
|
|
goto ExitOnError;
|
|
}
|
|
*/
|
|
{
|
|
DWORD needed_length = 0;
|
|
DWORD dwErr = 0, dwDomainLen = 0;
|
|
SID_NAME_USE sidNameUse;
|
|
TCHAR szDomain[ MAX_PATH + 1 ];
|
|
BOOL success = FALSE;
|
|
TCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1 + 14] = { 0 }; //+14 for '\TelnetClients'
|
|
DWORD dwNameLen = MAX_COMPUTERNAME_LENGTH + 1;
|
|
success = GetComputerName(szComputerName, &dwNameLen);
|
|
if(success)
|
|
{
|
|
_sntprintf(szComputerName+dwNameLen,(MAX_COMPUTERNAME_LENGTH + 14) - dwNameLen,_T("\\%s"),TELNETCLIENTS_GROUP_NAME);
|
|
}
|
|
LookupAccountName( NULL, szComputerName, pSidTelnetClients, &needed_length,
|
|
szDomain, &dwDomainLen, &sidNameUse );
|
|
pSidTelnetClients = ( PSID ) new UCHAR[ needed_length ];
|
|
|
|
//Even if if allocation fails just go ahead.
|
|
success = LookupAccountName( NULL, szComputerName, pSidTelnetClients, &needed_length,
|
|
szDomain, &dwDomainLen, &sidNameUse );
|
|
if( !success )
|
|
{
|
|
if (pSidTelnetClients)
|
|
{
|
|
delete pSidTelnetClients;
|
|
pSidTelnetClients = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
if(pSidTelnetClients == NULL)
|
|
{ //Allocate size for 4 ACEs.
|
|
aclSize = sizeof(ACL) +
|
|
(3* sizeof(ACCESS_ALLOWED_ACE)) +
|
|
GetLengthSid(pSidAdministrators) +
|
|
GetLengthSid(pSidLocalSystem) +
|
|
GetLengthSid(pSidLocalService) +
|
|
//GetLengthSid(pSidNetworkService) -
|
|
(3*sizeof(DWORD));
|
|
}
|
|
else
|
|
{ //Allocate size for 5 ACEs. TelnetClients group is present and we should provide access to
|
|
//members of telnetclients group
|
|
aclSize = sizeof(ACL) +
|
|
(4* sizeof(ACCESS_ALLOWED_ACE)) +
|
|
GetLengthSid(pSidAdministrators) +
|
|
GetLengthSid(pSidLocalSystem) +
|
|
GetLengthSid(pSidLocalService) +
|
|
//GetLengthSid(pSidNetworkService) +
|
|
GetLengthSid(pSidTelnetClients) -
|
|
(4*sizeof(DWORD));
|
|
}
|
|
newACL = (PACL) new BYTE[aclSize];
|
|
if (newACL == NULL)
|
|
{
|
|
goto ExitOnError;
|
|
}
|
|
|
|
|
|
if (!InitializeAcl(newACL, aclSize, ACL_REVISION))
|
|
{
|
|
goto ExitOnError;
|
|
}
|
|
if(pSidTelnetClients != NULL)
|
|
{
|
|
pace = (ACCESS_ALLOWED_ACE *)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pSidTelnetClients) -sizeof(DWORD));
|
|
if (pace == NULL)
|
|
{
|
|
goto ExitOnError;
|
|
}
|
|
pace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
|
|
pace->Header.AceFlags = CONTAINER_INHERIT_ACE |
|
|
OBJECT_INHERIT_ACE;
|
|
pace->Header.AceSize = sizeof(ACCESS_ALLOWED_ACE) +
|
|
(WORD)GetLengthSid(pSidTelnetClients) - sizeof(DWORD);
|
|
pace->Mask = WINSTA_ALL &
|
|
~(WRITE_DAC |
|
|
WRITE_OWNER |
|
|
WINSTA_CREATEDESKTOP |
|
|
DELETE);
|
|
if (!CopySid(GetLengthSid(pSidTelnetClients), &pace->SidStart, pSidTelnetClients))
|
|
{
|
|
goto ExitOnError;
|
|
}
|
|
if (!AddAce(newACL,ACL_REVISION,MAXDWORD,(LPVOID)pace,pace->Header.AceSize))
|
|
{
|
|
goto ExitOnError;
|
|
}
|
|
}
|
|
if (!AddAccessAllowedAce(newACL, ACL_REVISION, GENERIC_ALL , pSidAdministrators))
|
|
{
|
|
goto ExitOnError;
|
|
}
|
|
if (!AddAccessAllowedAce(newACL, ACL_REVISION, GENERIC_ALL, pSidLocalSystem))
|
|
{
|
|
goto ExitOnError;
|
|
}
|
|
if (!AddAccessAllowedAce(newACL, ACL_REVISION, GENERIC_ALL , pSidLocalService))
|
|
{
|
|
goto ExitOnError;
|
|
}
|
|
/*
|
|
if (!AddAccessAllowedAce(newACL, ACL_REVISION, GENERIC_ALL , pSidNetworkService))
|
|
{
|
|
goto ExitOnError;
|
|
}
|
|
*/
|
|
if ( !InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION ) )
|
|
{
|
|
goto ExitOnError;
|
|
}
|
|
|
|
if ( !SetSecurityDescriptorDacl(&sd, TRUE, newACL, FALSE) )
|
|
{
|
|
goto ExitOnError;
|
|
}
|
|
|
|
window_station = GetProcessWindowStation(); // Will this always have WRITE_DAC, we're the owner
|
|
|
|
if (NULL == window_station)
|
|
{
|
|
goto ExitOnError;
|
|
}
|
|
|
|
if (! SetUserObjectSecurity(window_station, &sec_i, &sd))
|
|
{
|
|
goto ExitOnError;
|
|
}
|
|
|
|
|
|
bStatus = TRUE;
|
|
goto Done;
|
|
|
|
ExitOnError:
|
|
|
|
dwErrCode = GetLastError();
|
|
_TRACE(TRACE_DEBUGGING,L"Creation and setting of windowstation/desktop failed with %d",dwErrCode);
|
|
LogFormattedGetLastError(EVENTLOG_ERROR_TYPE, TELNET_MSG_ERROR_CREATE_DESKTOP_FAILURE, dwErrCode);
|
|
|
|
Done:
|
|
if (window_station)
|
|
{
|
|
CloseWindowStation(window_station);
|
|
}
|
|
|
|
if ( pSidAdministrators != NULL )
|
|
{
|
|
FreeSid (pSidAdministrators );
|
|
}
|
|
if ( pSidLocalSystem!= NULL )
|
|
{
|
|
FreeSid (pSidLocalSystem);
|
|
}
|
|
if ( pSidLocalService!= NULL )
|
|
{
|
|
FreeSid (pSidLocalService);
|
|
}
|
|
if ( pSidNetworkService!= NULL )
|
|
{
|
|
FreeSid (pSidNetworkService);
|
|
}
|
|
if(pace)
|
|
HeapFree(GetProcessHeap(), 0, (LPVOID)pace);
|
|
if (pSidTelnetClients)
|
|
{
|
|
delete pSidTelnetClients;
|
|
pSidTelnetClients = NULL;
|
|
}
|
|
|
|
if (newACL)
|
|
delete [] newACL;
|
|
|
|
return( bStatus );
|
|
}
|
|
|
|
CTelnetService* CTelnetService::s_instance = NULL;
|
|
|
|
CTelnetService*
|
|
CTelnetService::Instance()
|
|
{
|
|
if ( s_instance == NULL )
|
|
{
|
|
s_instance = new CTelnetService();
|
|
_chASSERT( s_instance != NULL );
|
|
}
|
|
|
|
return( s_instance );
|
|
}
|
|
|
|
void
|
|
CTelnetService::InitializeOverlappedStruct( LPOVERLAPPED poObject )
|
|
{
|
|
_chASSERT( poObject != NULL );
|
|
if ( !poObject )
|
|
{
|
|
return;
|
|
}
|
|
|
|
poObject->Internal = 0;
|
|
poObject->InternalHigh = 0;
|
|
poObject->Offset = 0;
|
|
poObject->OffsetHigh = 0;
|
|
poObject->hEvent = NULL;
|
|
return;
|
|
}
|
|
|
|
CTelnetService::CTelnetService()
|
|
{
|
|
m_dwTelnetPort = DEFAULT_TELNET_PORT;
|
|
m_dwMaxConnections = 0;
|
|
m_pszIpAddrToListenOn = NULL;
|
|
m_hReadConfigKey = NULL;
|
|
|
|
m_dwNumOfActiveConnections = 0;
|
|
m_lServerState = SERVER_RUNNING;
|
|
|
|
SfuZeroMemory(m_sFamily, sizeof(m_sFamily));
|
|
m_sFamily[IPV4_FAMILY].iFamily = AF_INET;
|
|
m_sFamily[IPV4_FAMILY].iSocklen = sizeof(SOCKADDR_IN);
|
|
m_sFamily[IPV4_FAMILY].sListenSocket = INVALID_SOCKET;
|
|
m_sFamily[IPV6_FAMILY].iFamily = AF_INET6;
|
|
m_sFamily[IPV6_FAMILY].iSocklen = sizeof(SOCKADDR_IN6);
|
|
m_sFamily[IPV6_FAMILY].sListenSocket = INVALID_SOCKET;
|
|
m_hCompletionPort = INVALID_HANDLE_VALUE;
|
|
m_hIPCThread = NULL;
|
|
|
|
InitializeOverlappedStruct( &m_oReadFromPipe );
|
|
InitializeOverlappedStruct( &m_oWriteToPipe );
|
|
InitializeOverlappedStruct( &m_oPostedMessage );
|
|
|
|
client_list_mutex = TnCreateMutex(NULL, FALSE, NULL);
|
|
CQList = new CQueue;
|
|
_chASSERT( client_list_mutex );
|
|
|
|
_chVERIFY2( m_hSyncAllClientObjAccess = TnCreateMutex( NULL, FALSE, NULL ) );
|
|
// DebugBreak();
|
|
_chVERIFY2( m_hSocketCloseEvent = CreateEvent( NULL, TRUE, FALSE, NULL ) );
|
|
_chVERIFY2( m_hRegChangeEvent = CreateEvent( NULL, TRUE, FALSE, NULL ) );
|
|
_chVERIFY2( g_hSyncCloseHandle = TnCreateMutex(NULL,FALSE,NULL));
|
|
|
|
m_bIsWorkStation = false;;
|
|
m_pssWorkstationList = NULL;
|
|
m_dwNoOfWorkstations = 0;
|
|
}
|
|
|
|
CTelnetService::~CTelnetService()
|
|
{
|
|
delete[] m_pszIpAddrToListenOn;
|
|
delete[] m_pssWorkstationList;
|
|
TELNET_CLOSE_HANDLE(g_hSyncCloseHandle);
|
|
TELNET_CLOSE_HANDLE(client_list_mutex);
|
|
|
|
//All the cleanup is happening in Shutdown()
|
|
}
|
|
|
|
bool
|
|
CTelnetService::WatchRegistryKeys()
|
|
{
|
|
DWORD dwStatus = 0;
|
|
DWORD dwDisp = 0;
|
|
if ( dwStatus = TnSecureRegCreateKeyEx( HKEY_LOCAL_MACHINE, READ_CONFIG_KEY, NULL, NULL,
|
|
REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED , NULL,
|
|
&m_hReadConfigKey, &dwDisp, 0 ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
if ( !RegisterForNotification() )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
return( TRUE );
|
|
}
|
|
|
|
bool
|
|
CTelnetService::RegisterForNotification()
|
|
{
|
|
DWORD dwStatus = 0;
|
|
if ( dwStatus = RegNotifyChangeKeyValue( m_hReadConfigKey, TRUE,
|
|
REG_NOTIFY_CHANGE_LAST_SET|REG_NOTIFY_CHANGE_NAME,
|
|
m_hRegChangeEvent, TRUE ) != ERROR_SUCCESS )
|
|
{
|
|
LogFormattedGetLastError( EVENTLOG_ERROR_TYPE, MSG_ERR_REGNOTIFY, dwStatus );
|
|
return( FALSE );
|
|
}
|
|
return( TRUE );
|
|
}
|
|
|
|
bool
|
|
CTelnetService::Init( void )
|
|
{
|
|
if ( !m_hSyncAllClientObjAccess || !m_hSocketCloseEvent || !m_hRegChangeEvent )
|
|
{
|
|
return( FALSE);
|
|
}
|
|
|
|
if ( !GetRegistryValues() )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if ( !WatchRegistryKeys() )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if ( !InitTCPIP() )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if( !SetWinstaSecurity())
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
|
|
m_szDomainName[0] = L'\0';
|
|
if ( !GetDomainHostedByThisMc( m_szDomainName ) )
|
|
{
|
|
m_szDomainName[0] = 0;
|
|
}
|
|
|
|
LPWSTR szProductType = NULL;
|
|
if ( !GetProductType( &szProductType ) )
|
|
{
|
|
return( FALSE);
|
|
}
|
|
|
|
m_bIsWorkStation = ( _wcsicmp(szProductType, TEXT("WinNT")) == 0 );
|
|
delete[] szProductType;
|
|
|
|
if ( m_bIsWorkStation )
|
|
{
|
|
m_pssWorkstationList = new SOCKADDR_STORAGE[ DEFAULT_LICENSES_FOR_NTWKSTA ];
|
|
if ( !m_pssWorkstationList )
|
|
{
|
|
return( FALSE);
|
|
}
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
bool
|
|
CTelnetService::Pause( void )
|
|
{
|
|
|
|
InterlockedExchange( &m_lServerState, SERVER_PAUSED );
|
|
return( TRUE );
|
|
}
|
|
|
|
bool
|
|
CTelnetService::Resume( void )
|
|
{
|
|
InterlockedExchange( &m_lServerState, SERVER_RUNNING );
|
|
return( TRUE );
|
|
}
|
|
|
|
void
|
|
CTelnetService::SystemShutdown( void )
|
|
{
|
|
//We have just 20 secs left to finish this routine
|
|
if(m_hCompletionPort && m_hCompletionPort != INVALID_HANDLE_VALUE)
|
|
PostQueuedCompletionStatus( m_hCompletionPort, 0, TLNTSVR_SHUTDOWN,
|
|
&m_oPostedMessage ); //This should lead to IPC thread exit if
|
|
//it is present.
|
|
|
|
if (TlntSynchronizeOn(m_hSyncAllClientObjAccess))
|
|
{
|
|
DWORD dwCount = client_list_Count();
|
|
|
|
while ( dwCount-- > 0 )
|
|
{
|
|
CClientInfo *pClient = (CClientInfo *)client_list_Get( dwCount );
|
|
if ( pClient )
|
|
{
|
|
WriteToPipe( pClient->hWritingPipe, SYSTEM_SHUTDOWN,
|
|
&( m_oWriteToPipe ) );
|
|
}
|
|
}
|
|
|
|
ReleaseMutex( m_hSyncAllClientObjAccess );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
bool
|
|
CTelnetService::AskSessionToShutdown( HANDLE hWritingPipe, UCHAR ucMsgType )
|
|
{
|
|
if ( !WriteToPipe( hWritingPipe, ucMsgType, &( m_oWriteToPipe ) ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
return( TRUE );
|
|
}
|
|
|
|
bool
|
|
CTelnetService::Shutdown( void )
|
|
{
|
|
shutdown( m_sFamily[IPV4_FAMILY].sListenSocket, SD_BOTH ); //NO more data on socket
|
|
shutdown( m_sFamily[IPV6_FAMILY].sListenSocket, SD_BOTH ); //NO more data on socket
|
|
if(m_hCompletionPort && m_hCompletionPort != INVALID_HANDLE_VALUE)
|
|
PostQueuedCompletionStatus( m_hCompletionPort, 0, TLNTSVR_SHUTDOWN,
|
|
&m_oPostedMessage );
|
|
if (TlntSynchronizeOn(m_hSyncAllClientObjAccess))
|
|
{
|
|
_Module.SetServiceStatus( SERVICE_STOP_PENDING );
|
|
|
|
while ( client_list_Count() > 0 )
|
|
{
|
|
CClientInfo *pClient = (CClientInfo *)client_list_Get( 0 );
|
|
if ( !pClient )
|
|
{
|
|
break;
|
|
}
|
|
AskSessionToShutdown( pClient->hWritingPipe, TLNTSVR_SHUTDOWN );
|
|
StopServicingClient( pClient, (BOOL)TRUE );
|
|
}
|
|
ReleaseMutex( m_hSyncAllClientObjAccess );
|
|
}
|
|
|
|
_Module.SetServiceStatus( SERVICE_STOP_PENDING );
|
|
TELNET_SYNC_CLOSE_HANDLE( m_hSyncAllClientObjAccess );
|
|
|
|
if ((NULL != m_hIPCThread) && (INVALID_HANDLE_VALUE != m_hIPCThread))
|
|
{
|
|
// WaitForSingleObject(m_hIPCThread, INFINITE);
|
|
TerminateThread(m_hIPCThread, 0);
|
|
TELNET_CLOSE_HANDLE( m_hIPCThread );
|
|
}
|
|
SetEvent( m_hSocketCloseEvent );//This should lead to listener thread exit
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
bool
|
|
CTelnetService::GetInAddr( INT iFamIdx, SOCKADDR_STORAGE *ssS_addr, socklen_t *iSslen )
|
|
{
|
|
bool bContinue = false;
|
|
if ( wcscmp( m_pszIpAddrToListenOn, DEFAULT_IP_ADDR ) == 0 )
|
|
{
|
|
// Bind to "any"
|
|
_TRACE(TRACE_DEBUGGING,"Into GetInAddr, bind to ANY");
|
|
*iSslen = m_sFamily[iFamIdx].iSocklen;
|
|
SfuZeroMemory(ssS_addr, *iSslen);
|
|
ssS_addr->ss_family = (short)m_sFamily[iFamIdx].iFamily;
|
|
bContinue = true;
|
|
}
|
|
else
|
|
{
|
|
DWORD dwSize = 0, dwResult;
|
|
PCHAR szIpAddr = NULL;
|
|
|
|
struct addrinfo *ai, hints;
|
|
|
|
dwSize = WideCharToMultiByte( GetOEMCP(), 0, m_pszIpAddrToListenOn, -1, NULL, 0, NULL, NULL );
|
|
_TRACE(TRACE_DEBUGGING,L"m_pszIpAddr : %s",m_pszIpAddrToListenOn);
|
|
szIpAddr = new CHAR[ dwSize ];
|
|
if ( !szIpAddr )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
WideCharToMultiByte( GetOEMCP(), 0, m_pszIpAddrToListenOn, -1, szIpAddr, dwSize, NULL, NULL );
|
|
_TRACE(TRACE_DEBUGGING,"szIpAddr : %s",szIpAddr);
|
|
SfuZeroMemory(&hints, sizeof(hints));
|
|
hints.ai_flags = AI_NUMERICHOST;
|
|
dwResult = getaddrinfo(szIpAddr, NULL, &hints, &ai);
|
|
if ( dwResult != NO_ERROR )
|
|
{
|
|
//Log error
|
|
LogEvent( EVENTLOG_ERROR_TYPE, MSG_FAILEDTO_BIND, m_pszIpAddrToListenOn );
|
|
_TRACE(TRACE_DEBUGGING,"getaddrinfo failed : %d ",dwResult);
|
|
delete[] szIpAddr;
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
switch ( ai->ai_family)
|
|
{
|
|
case AF_INET:
|
|
if (iFamIdx == IPV4_FAMILY)
|
|
{
|
|
_TRACE(TRACE_DEBUGGING,"IPV4 family and IPV4 address");
|
|
bContinue = true;
|
|
}
|
|
else
|
|
{
|
|
_TRACE(TRACE_DEBUGGING,"IPV4 family and IPV6 address...continue");
|
|
SetLastError(ERROR_SUCCESS);
|
|
}
|
|
break;
|
|
case AF_INET6:
|
|
if (iFamIdx == IPV6_FAMILY)
|
|
{
|
|
_TRACE(TRACE_DEBUGGING,"IPV6 family and IPV6 address");
|
|
bContinue = true;
|
|
}
|
|
else
|
|
{
|
|
_TRACE(TRACE_DEBUGGING,"IPV6 family and IPV4 address...continue");
|
|
SetLastError(ERROR_SUCCESS);
|
|
}
|
|
break;
|
|
default:
|
|
_TRACE(TRACE_DEBUGGING,"none of the two ??");
|
|
break;
|
|
}
|
|
if (bContinue)
|
|
{
|
|
*iSslen = ai->ai_addrlen;
|
|
CopyMemory(ssS_addr, ai->ai_addr, ai->ai_addrlen);
|
|
}
|
|
}
|
|
delete[] szIpAddr;
|
|
}
|
|
return( bContinue ? TRUE : FALSE );
|
|
}
|
|
|
|
bool
|
|
CTelnetService::CreateSocket( INT iFamIdx )
|
|
{
|
|
INT iSize = 1, iSslen;
|
|
DWORD dwCode = 0;
|
|
struct sockaddr_storage ss;
|
|
|
|
_chVERIFY2( SetHandleInformation( ( HANDLE ) m_sFamily[iFamIdx].SocketAcceptEvent,
|
|
HANDLE_FLAG_INHERIT, 0 ) );
|
|
_TRACE(TRACE_DEBUGGING,"Into CreateSocket");
|
|
|
|
if ( !GetInAddr(iFamIdx, &ss, &iSslen ) )
|
|
{
|
|
_TRACE(TRACE_DEBUGGING,"GetInAddr failed");
|
|
goto ExitOnError;
|
|
}
|
|
|
|
SS_PORT(&ss) = htons( ( u_short ) m_dwTelnetPort );
|
|
|
|
m_sFamily[iFamIdx].sListenSocket = socket( m_sFamily[iFamIdx].iFamily, SOCK_STREAM, 0 );
|
|
if ( INVALID_SOCKET == m_sFamily[iFamIdx].sListenSocket )
|
|
{
|
|
_TRACE(TRACE_DEBUGGING,"socket failed");
|
|
goto ExitOnError;
|
|
}
|
|
|
|
{
|
|
BOOL value_to_set = TRUE;
|
|
|
|
if (SOCKET_ERROR == setsockopt(
|
|
m_sFamily[iFamIdx].sListenSocket,
|
|
SOL_SOCKET,
|
|
SO_DONTLINGER,
|
|
( char * )&value_to_set,
|
|
sizeof( value_to_set )
|
|
)
|
|
)
|
|
{
|
|
goto CloseAndExitOnError;
|
|
}
|
|
if(SOCKET_ERROR == SafeSetSocketOptions(m_sFamily[iFamIdx].sListenSocket))
|
|
{
|
|
goto CloseAndExitOnError;
|
|
}
|
|
}
|
|
_TRACE(TRACE_DEBUGGING,"Scope id is : %ul",((sockaddr_in6 *)&ss)->sin6_scope_id);
|
|
if ( bind( m_sFamily[iFamIdx].sListenSocket, ( struct sockaddr * ) &ss, iSslen ) == SOCKET_ERROR )
|
|
{
|
|
_TRACE(TRACE_DEBUGGING,"bind failed");
|
|
goto CloseAndExitOnError;
|
|
}
|
|
|
|
if ( listen( m_sFamily[iFamIdx].sListenSocket, SOMAXCONN ) == SOCKET_ERROR )
|
|
{
|
|
_TRACE(TRACE_DEBUGGING,"listen failed");
|
|
goto CloseAndExitOnError;
|
|
}
|
|
|
|
//We are making it non-inheritable here
|
|
_chVERIFY2( SetHandleInformation( ( HANDLE ) m_sFamily[iFamIdx].sListenSocket,
|
|
HANDLE_FLAG_INHERIT, 0 ) );
|
|
|
|
if ( ( WSAEventSelect( m_sFamily[iFamIdx].sListenSocket, m_sFamily[iFamIdx].SocketAcceptEvent, FD_ACCEPT )
|
|
== SOCKET_ERROR ) )
|
|
{
|
|
_TRACE(TRACE_DEBUGGING,"eventselect failed");
|
|
goto CloseAndExitOnError;
|
|
}
|
|
|
|
return( TRUE );
|
|
|
|
CloseAndExitOnError:
|
|
_TRACE(TRACE_DEBUGGING,"closing listen socket");
|
|
closesocket( m_sFamily[iFamIdx].sListenSocket );
|
|
m_sFamily[iFamIdx].sListenSocket = INVALID_SOCKET;
|
|
ExitOnError:
|
|
dwCode = WSAGetLastError();
|
|
if (dwCode != ERROR_SUCCESS )
|
|
{
|
|
_TRACE(TRACE_DEBUGGING,L"Error in CreateSocket : %d ",dwCode);
|
|
DecodeWSAErrorCodes( dwCode , m_dwTelnetPort );
|
|
}
|
|
return( FALSE );
|
|
}
|
|
|
|
bool
|
|
CTelnetService::InitTCPIP( void )
|
|
{
|
|
WSADATA WSAData;
|
|
DWORD dwStatus;
|
|
WORD wVersionReqd;
|
|
bool bOkay4 = false, bOkay6 = false;
|
|
|
|
DWORD dwSize = 0, dwResult;
|
|
PCHAR szIpAddr = NULL;
|
|
struct addrinfo *ai, hints;
|
|
char buff[MAX_STRING_LENGTH];
|
|
|
|
wVersionReqd = MAKEWORD( 2, 0 );
|
|
dwStatus = WSAStartup( wVersionReqd, &WSAData );
|
|
if ( dwStatus )
|
|
{
|
|
DecodeSocketStartupErrorCodes( dwStatus ); //It does tracing and loggin
|
|
return FALSE;
|
|
}
|
|
|
|
if ( ( m_sFamily[IPV4_FAMILY].SocketAcceptEvent = WSACreateEvent() ) == WSA_INVALID_EVENT )
|
|
{
|
|
goto ExitOnError;
|
|
}
|
|
|
|
if ( ( m_sFamily[IPV6_FAMILY].SocketAcceptEvent = WSACreateEvent() ) == WSA_INVALID_EVENT )
|
|
{
|
|
goto ExitOnError;
|
|
}
|
|
|
|
SfuZeroMemory(&hints, sizeof(hints));
|
|
hints.ai_flags = AI_PASSIVE;
|
|
_ltoa(m_dwTelnetPort,buff,10);
|
|
dwResult = getaddrinfo(NULL,buff , &hints, &ai);
|
|
if (dwResult)
|
|
{
|
|
_TRACE(TRACE_DEBUGGING,L"Error in getaddrinfo() : %d",dwResult);
|
|
goto ExitOnError;
|
|
}
|
|
while (ai)
|
|
{
|
|
switch (ai->ai_family)
|
|
{
|
|
case AF_INET:
|
|
if (!bOkay4)
|
|
{
|
|
bOkay4 = CreateSocket(IPV4_FAMILY);
|
|
_TRACE(TRACE_DEBUGGING,L"Creating IPV4 socket. bOkay4 = %d ",(int)bOkay4);
|
|
}
|
|
break;
|
|
case AF_INET6:
|
|
if (!bOkay6)
|
|
{
|
|
bOkay6 = CreateSocket(IPV6_FAMILY);
|
|
_TRACE(TRACE_DEBUGGING,L"Creating IPV6 socketb. bOkay6 = %d ",(int)bOkay6);
|
|
}
|
|
break;
|
|
default:
|
|
_TRACE(TRACE_DEBUGGING,L"Error : Returned none of the families");
|
|
break;
|
|
}
|
|
ai= ai->ai_next;
|
|
}
|
|
if ( !bOkay4 && !bOkay6 )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
|
|
ExitOnError:
|
|
DecodeWSAErrorCodes( WSAGetLastError() );
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
bool
|
|
CTelnetService::CreateNewIoCompletionPort( DWORD cSimultaneousClients )
|
|
{
|
|
_chVERIFY2( m_hCompletionPort = CreateIoCompletionPort(
|
|
INVALID_HANDLE_VALUE, NULL, 1, cSimultaneousClients ) );
|
|
return( m_hCompletionPort != NULL );
|
|
}
|
|
|
|
bool
|
|
CTelnetService::AssociateDeviceWithCompletionPort ( HANDLE hCompPort,
|
|
HANDLE hDevice,
|
|
DWORD_PTR dwCompKey
|
|
)
|
|
{
|
|
|
|
_chASSERT( hCompPort != NULL );
|
|
_chASSERT( hDevice != NULL );
|
|
if ( ( hCompPort == NULL ) || ( hDevice == NULL ) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
HANDLE h = NULL;
|
|
_chVERIFY2( h = CreateIoCompletionPort( hDevice, hCompPort, dwCompKey, 1 ));
|
|
|
|
if ( h != hCompPort)
|
|
{
|
|
DWORD dwErr = GetLastError();
|
|
_TRACE( TRACE_DEBUGGING, "AssociateDeviceWithCompletionPort() -- 0x%1x", dwErr );
|
|
LogFormattedGetLastError( EVENTLOG_ERROR_TYPE, MSG_FAILASSOCIATEPORT, dwErr );
|
|
}
|
|
|
|
return( h == hCompPort );
|
|
}
|
|
|
|
bool
|
|
CTelnetService::StartThreads( void )
|
|
{
|
|
DWORD dwThreadId;
|
|
|
|
if ( !CreateNewIoCompletionPort( 1 ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// if( m_hIPCThread != NULL )
|
|
// {
|
|
// TELNET_SYNC_CLOSE_HANDLE( m_hIPCThread );
|
|
// m_hIPCThread = NULL;
|
|
// }
|
|
|
|
_chVERIFY2( m_hIPCThread = CreateThread( NULL, 0, DoIPCWithClients, ( LPVOID ) g_pTelnetService, 0, &dwThreadId ) );
|
|
if ( !m_hIPCThread )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
bool
|
|
CTelnetService::GetRegistryValues( void )
|
|
{
|
|
HKEY hk = NULL;
|
|
DWORD dwDisp = 0;
|
|
|
|
if ( TnSecureRegCreateKeyEx( HKEY_LOCAL_MACHINE, REG_PARAMS_KEY, NULL, NULL,
|
|
REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED , NULL, &hk, &dwDisp, 0 ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if ( !GetRegistryDW( hk, NULL, L"MaxConnections", &m_dwMaxConnections,
|
|
DEFAULT_MAX_CONNECTIONS,FALSE ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
else
|
|
{
|
|
CQList->m_dwMaxUnauthenticatedConnections = m_dwMaxConnections;
|
|
}
|
|
|
|
if ( !GetRegistryDW( hk, NULL, L"TelnetPort", &m_dwTelnetPort,
|
|
DEFAULT_TELNET_PORT,FALSE ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if ( !GetRegistryString( hk, NULL, L"ListenToSpecificIpAddr", &m_pszIpAddrToListenOn,
|
|
DEFAULT_IP_ADDR,FALSE ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
RegCloseKey( hk );
|
|
return( TRUE );
|
|
}
|
|
|
|
bool
|
|
CTelnetService::HandleChangeInRegKeys( )
|
|
{
|
|
HKEY hk = NULL;
|
|
DWORD dwNewTelnetPort = 0;
|
|
DWORD dwNewMaxConnections = 0;
|
|
DWORD dwMaxFileSize = 0;
|
|
DWORD dwLogToFile = 0;
|
|
LPWSTR pszNewLogFile = NULL;
|
|
LPWSTR pszNewIpAddr = NULL;
|
|
DWORD dwDisp = 0;
|
|
|
|
if ( TnSecureRegCreateKeyEx( HKEY_LOCAL_MACHINE, REG_PARAMS_KEY, NULL, NULL,
|
|
REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED , NULL, &hk, &dwDisp, 0 ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if ( !GetRegistryDW( hk, NULL, L"TelnetPort", &dwNewTelnetPort,
|
|
DEFAULT_TELNET_PORT,FALSE ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if ( !GetRegistryDW( hk, NULL, L"MaxConnections", &dwNewMaxConnections,
|
|
DEFAULT_MAX_CONNECTIONS,FALSE ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
if ( !GetRegistryDW( hk, NULL, LOGFILESIZE, &dwMaxFileSize, DEFAULT_LOGFILESIZE,FALSE ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if ( !GetRegistryDW( hk, NULL, L"LogToFile", &dwLogToFile, DEFAULT_LOGTOFILE,FALSE ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if ( !GetRegistryString( hk, NULL, L"LogFile", &pszNewLogFile, DEFAULT_LOGFILE,FALSE ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if ( !GetRegistryString( hk, NULL, L"ListenToSpecificIpAddr", &pszNewIpAddr,
|
|
DEFAULT_IP_ADDR,FALSE ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
SetNewRegKeyValues( dwNewTelnetPort, dwNewMaxConnections,
|
|
dwMaxFileSize, pszNewLogFile, pszNewIpAddr, dwLogToFile );
|
|
|
|
RegCloseKey( hk );
|
|
return( TRUE );
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//this is the thread which waits on the telnet port for any new connections
|
|
//and also for any change in the reg keys
|
|
//------------------------------------------------------------------------------
|
|
|
|
bool
|
|
CTelnetService::ListenerThread( )
|
|
{
|
|
BOOL bContinue = true;
|
|
HANDLE eventArray[ 4 ];
|
|
DWORD dwWaitRet = 0;
|
|
SOCKET sSocket = INVALID_SOCKET;
|
|
INT iFamIdx =IPV4_FAMILY;
|
|
|
|
//DebugBreak();
|
|
/*++
|
|
MSRC issue 567.
|
|
To generate random numbers, use Crypt...() functions. Acquire a crypt context at the beginning of
|
|
ListenerThread and release the context at the end of the thread. If acquiring the context fails,
|
|
the service fails to start since we do not want to continue with weak pipe names.
|
|
initialize the random number generator
|
|
--*/
|
|
if (!CryptAcquireContext(&g_hProv,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT))
|
|
{
|
|
_TRACE(TRACE_DEBUGGING,L"Acquiring crypt context failed with error %d",GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
if ( !Init() )
|
|
{
|
|
LogEvent( EVENTLOG_ERROR_TYPE, MSG_FAILEDTOINITIALIZE, _T("") );
|
|
return FALSE;
|
|
}
|
|
// BaskarK: Set the error mode for this process to "do not disturb" so that all our children will inherit and will
|
|
// not stop the stresss, dead on its tracks...
|
|
|
|
SetErrorMode(
|
|
SEM_FAILCRITICALERRORS |
|
|
SEM_NOGPFAULTERRORBOX |
|
|
SEM_NOALIGNMENTFAULTEXCEPT |
|
|
SEM_NOOPENFILEERRORBOX);
|
|
|
|
eventArray[ SOCKET_CLOSE_EVENT ] = g_pTelnetService->m_hSocketCloseEvent;
|
|
eventArray[ FD_ACCEPT_EVENT_0 ] = g_pTelnetService->m_sFamily[IPV4_FAMILY].SocketAcceptEvent;
|
|
eventArray[ REG_CHANGE_EVENT ] = g_pTelnetService->m_hRegChangeEvent;
|
|
eventArray[ FD_ACCEPT_EVENT_1 ] = g_pTelnetService->m_sFamily[IPV6_FAMILY].SocketAcceptEvent;
|
|
|
|
_Module.SetServiceStatus(SERVICE_RUNNING);
|
|
_TRACE( TRACE_DEBUGGING, "ListenerThread() -- Enter" );
|
|
|
|
while ( bContinue )
|
|
{
|
|
//Refer to doc on select for FD_ZERO, FD_SET etc.
|
|
iFamIdx = IPV4_FAMILY;
|
|
dwWaitRet = WaitForMultipleObjects ( 4, eventArray, FALSE, INFINITE );
|
|
|
|
switch (dwWaitRet)
|
|
{
|
|
case FD_ACCEPT_EVENT_1:
|
|
iFamIdx = IPV6_FAMILY;
|
|
// fall through
|
|
|
|
case FD_ACCEPT_EVENT_0:
|
|
|
|
|
|
// NOTE: ***********************************************
|
|
|
|
// The only exit point out of this case statement should be
|
|
// through FD_ACCEPT_EVENT_CLEANUP only. Otherwise, you will
|
|
// cause serious leak of sockets inthe tlntsvr - BaskarK
|
|
|
|
{
|
|
INT iSize;
|
|
struct sockaddr_storage ss;
|
|
WSANETWORKEVENTS wsaNetEvents;
|
|
bool bSendMessage = false;
|
|
struct sockaddr_storage saddrPeer;
|
|
char szIPAddr[ SMALL_STRING ];
|
|
DWORD dwPid = 0;
|
|
HANDLE hWritePipe = NULL;
|
|
|
|
// _TRACE( TRACE_DEBUGGING, " FD_ACCEPT_EVENT " );
|
|
|
|
wsaNetEvents.lNetworkEvents = 0;
|
|
if ( WSAEnumNetworkEvents( g_pTelnetService->m_sFamily[iFamIdx].sListenSocket, g_pTelnetService->m_sFamily[iFamIdx].SocketAcceptEvent,
|
|
&wsaNetEvents ) == SOCKET_ERROR )
|
|
{
|
|
DWORD dwErr = WSAGetLastError();
|
|
_TRACE( TRACE_DEBUGGING, " Error -- WSAEnumNetworkEvents-- 0x%x ", dwErr);
|
|
DecodeWSAErrorCodes( dwErr );
|
|
goto FD_ACCEPT_EVENT_CLEANUP;
|
|
}
|
|
|
|
if ( wsaNetEvents.lNetworkEvents & FD_ACCEPT )
|
|
{
|
|
if (sSocket != INVALID_SOCKET)
|
|
{
|
|
// shutdown(sSocket, SD_BOTH);
|
|
closesocket(sSocket);
|
|
sSocket = INVALID_SOCKET;
|
|
}
|
|
|
|
iSize = sizeof(ss);
|
|
__try
|
|
{
|
|
sSocket = accept( g_pTelnetService->m_sFamily[iFamIdx].sListenSocket,(struct sockaddr*) &ss, &iSize );
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
sSocket = INVALID_SOCKET;
|
|
WSASetLastError(WSAEFAULT);
|
|
}
|
|
|
|
if (sSocket == INVALID_SOCKET)
|
|
{
|
|
DWORD dwErr = WSAGetLastError();
|
|
_TRACE( TRACE_DEBUGGING, " Error -- accept -- %d ", dwErr);
|
|
|
|
switch (dwErr)
|
|
{
|
|
case WSAEWOULDBLOCK: // non blocking socket so just loop back to the wait again
|
|
|
|
WSASetEvent( g_pTelnetService->m_sFamily[iFamIdx].SocketAcceptEvent );
|
|
break;
|
|
|
|
default:
|
|
// DebugBreak();
|
|
DecodeWSAErrorCodes( dwErr );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CClientInfo *new_client = NULL;
|
|
|
|
_TRACE( TRACE_DEBUGGING, "accept succeded... sSocket = %d",(DWORD)sSocket );
|
|
|
|
// Set the option to don't linger around
|
|
// Similarly, not to reuse address;
|
|
{
|
|
int value_to_set = FALSE;
|
|
|
|
setsockopt(
|
|
sSocket,
|
|
SOL_SOCKET,
|
|
SO_LINGER,
|
|
( char * )&value_to_set,
|
|
sizeof( value_to_set )
|
|
);
|
|
|
|
value_to_set = TRUE;
|
|
|
|
setsockopt(
|
|
sSocket,
|
|
SOL_SOCKET,
|
|
SO_EXCLUSIVEADDRUSE,
|
|
( char * )&value_to_set,
|
|
sizeof( value_to_set )
|
|
);
|
|
}
|
|
if (g_pTelnetService->m_sFamily[iFamIdx].SocketAcceptEvent == WSA_INVALID_EVENT)
|
|
{
|
|
goto FD_ACCEPT_EVENT_CLEANUP;
|
|
}
|
|
//Disassociate the default association to the event
|
|
_chVERIFY2( WSAEventSelect( sSocket,
|
|
g_pTelnetService->m_sFamily[iFamIdx].SocketAcceptEvent, 0 ) != SOCKET_ERROR );
|
|
LONG lSrvStat = SERVER_RUNNING;
|
|
lSrvStat = InterlockedCompareExchange( &g_pTelnetService->m_lServerState,
|
|
SERVER_PAUSED, SERVER_PAUSED );
|
|
if ( lSrvStat == SERVER_PAUSED )
|
|
{
|
|
CHAR szMessageBuffer[ MAX_STRING_LENGTH + 1 ];
|
|
|
|
if (LoadStringA( g_hInstRes, IDS_SERVICE_PAUSED, szMessageBuffer, MAX_STRING_LENGTH))
|
|
{
|
|
InformTheClient( sSocket, szMessageBuffer );
|
|
}
|
|
|
|
shutdown( sSocket, SD_BOTH );
|
|
goto FD_ACCEPT_EVENT_CLEANUP;
|
|
}
|
|
else
|
|
{
|
|
/*++
|
|
Get IP address of the client which requested the connection. This will
|
|
also be stored in a queue entry. We put a limit on maximum number
|
|
of unauthenticated connections that can be created from one IP address.
|
|
--*/
|
|
iSize = sizeof( saddrPeer );
|
|
SfuZeroMemory( &saddrPeer, iSize );
|
|
if ( getpeername( sSocket, ( struct sockaddr * ) &saddrPeer, &iSize ) == SOCKET_ERROR )
|
|
{
|
|
_TRACE(TRACE_DEBUGGING, "getpeername error : %d",GetLastError());
|
|
goto FD_ACCEPT_EVENT_CLEANUP;
|
|
}
|
|
getnameinfo((SOCKADDR*)&saddrPeer, iSize, szIPAddr, SMALL_STRING,
|
|
NULL, 0, NI_NUMERICHOST);
|
|
_TRACE(TRACE_DEBUGGING, "getpeername : %s",szIPAddr);
|
|
|
|
if (! CQList->OkToProceedWithThisClient(szIPAddr))
|
|
{
|
|
CHAR szMessageBuffer[ MAX_STRING_LENGTH + 1 ];
|
|
|
|
//Denying connection due to limit on maximum number of
|
|
//unauthenticated connections per IP
|
|
_TRACE( TRACE_DEBUGGING, "Max Unauthenticated connections reached" );
|
|
_TRACE(TRACE_DEBUGGING, "%s, %d cannot be added",szIPAddr, dwPid);
|
|
if (LoadStringA( g_hInstRes, IDS_MAX_IPLIMIT_REACHED, szMessageBuffer, MAX_STRING_LENGTH ))
|
|
{
|
|
InformTheClient( sSocket, szMessageBuffer ); // Don't care about its success, continue
|
|
_TRACE(TRACE_DEBUGGING, "shutting down socket for pid %d, socket %d", dwPid,(DWORD)sSocket);
|
|
}
|
|
|
|
shutdown(sSocket, SD_BOTH);
|
|
|
|
goto FD_ACCEPT_EVENT_CLEANUP;
|
|
}
|
|
|
|
/*++
|
|
CreateClient will return pid and pipehandle of the session
|
|
process that is created. this will be used by the queue object,
|
|
which stores information about all the sessions that are in
|
|
unauthenticated state.
|
|
Whenever a new session is created, it's info will be stored as
|
|
a queue entry in CQList.
|
|
--*/
|
|
if ( !CreateClient( sSocket, &dwPid, &hWritePipe, &new_client) )
|
|
{
|
|
CHAR szMessageBuffer[ MAX_STRING_LENGTH + 1 ];
|
|
|
|
_TRACE( TRACE_DEBUGGING, "new Telnet Client failed" );
|
|
|
|
if (LoadStringA( g_hInstRes, IDS_ERR_NEW_SESS_INIT, szMessageBuffer, MAX_STRING_LENGTH ))
|
|
{
|
|
InformTheClient( sSocket, szMessageBuffer ); // Don't care if this fails, we have to continue
|
|
}
|
|
|
|
goto FD_ACCEPT_EVENT_CLEANUP;
|
|
}
|
|
else
|
|
{
|
|
sSocket = INVALID_SOCKET; // From now onwards, we will reference this through the new_client class.
|
|
}
|
|
|
|
// hWritePipe will be NULL if IssueReadFromPipe fails in the CreateClient
|
|
// and hence we do StopServicingClient, so don't need to add the entry in a
|
|
// queue.
|
|
|
|
if (!hWritePipe)
|
|
goto FD_ACCEPT_EVENT_CLEANUP;
|
|
|
|
_TRACE( TRACE_DEBUGGING, "CreateClient success : %d",dwPid);
|
|
|
|
/*++
|
|
Add the session's information to the queue. CanIAdd will return FALSE
|
|
when the number of unauthenticated connections from the IP address
|
|
have already reached the limit, or when the queue is full.
|
|
In these cases, we notify the requesting client
|
|
that no more connections can be added. Otherwise, the new connection request
|
|
entry is added into the queue and CanIAdd returns TRUE.
|
|
In case of IPLimitReached or QueueFull,
|
|
we send the PipeHandle for that session back here so that we
|
|
can notify that session and tell that session to terminate itself. In these cases,
|
|
the flag bSendFlag is set to TRUE.
|
|
--*/
|
|
|
|
if (!CQList->WasTheClientAdded(dwPid,szIPAddr, &hWritePipe, &bSendMessage))
|
|
{
|
|
//Denying connection due to limit on maximum number of
|
|
//unauthenticated connections per IP
|
|
CHAR szMessageBuffer[ MAX_STRING_LENGTH + 1 ];
|
|
_TRACE( TRACE_DEBUGGING, "Max Unauthenticated connections reached" );
|
|
_TRACE(TRACE_DEBUGGING, "%s, %d cannot be added",szIPAddr, dwPid);
|
|
if (LoadStringA( g_hInstRes, IDS_MAX_IPLIMIT_REACHED, szMessageBuffer, MAX_STRING_LENGTH ))
|
|
{
|
|
InformTheClient( new_client->sSocket, szMessageBuffer ); // Don't care about its success, continue
|
|
_TRACE(TRACE_DEBUGGING, "shutting down socket for pid %d, socket %d", dwPid,(DWORD)new_client->sSocket);
|
|
}
|
|
}
|
|
|
|
if (bSendMessage)
|
|
{
|
|
//send message to session telling it to terminate itself
|
|
bSendMessage = false;
|
|
_TRACE(TRACE_DEBUGGING, "Asking the session %d to shutdown on socket %d",dwPid, (DWORD)sSocket);
|
|
CQList->FreeEntry(dwPid);
|
|
AskSessionToShutdown(hWritePipe, GO_DOWN);
|
|
|
|
// shutdown(sSocket, SD_BOTH);
|
|
}
|
|
|
|
// FALL back to FD_ACCEPT_EVENT_CLEANUP will clean/close the socket..
|
|
|
|
TELNET_CLOSE_HANDLE(hWritePipe);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
FD_ACCEPT_EVENT_CLEANUP: ;
|
|
|
|
if (sSocket != INVALID_SOCKET)
|
|
{
|
|
// shutdown(sSocket, SD_BOTH);
|
|
closesocket(sSocket);
|
|
sSocket = INVALID_SOCKET;
|
|
}
|
|
break;
|
|
case SOCKET_CLOSE_EVENT:
|
|
_TRACE( TRACE_DEBUGGING, " SOCKET_CLOSE_EVENT " );
|
|
bContinue = false;
|
|
break;
|
|
case REG_CHANGE_EVENT:
|
|
_TRACE( TRACE_DEBUGGING, " REG_CHANGE_EVENT " );
|
|
HandleChangeInRegKeys( );
|
|
ResetEvent( g_pTelnetService->m_hRegChangeEvent );
|
|
RegisterForNotification();
|
|
break;
|
|
default:
|
|
_TRACE( TRACE_DEBUGGING, " Error -- WaitForMultipleObjects " );
|
|
// DebugBreak();
|
|
if ( dwWaitRet == WAIT_FAILED )
|
|
{
|
|
LogFormattedGetLastError( EVENTLOG_ERROR_TYPE, 0, GetLastError() );
|
|
}
|
|
// bContinue = false; don't breakout of the loop,
|
|
// reject invalid requests (due to DOS attacks) keep continuing -- BaskarK
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (g_pTelnetService->m_hReadConfigKey)
|
|
RegCloseKey( g_pTelnetService->m_hReadConfigKey );
|
|
TELNET_CLOSE_HANDLE( g_pTelnetService->m_hRegChangeEvent );
|
|
//Socket related clean up
|
|
if (g_pTelnetService->m_sFamily[IPV4_FAMILY].sListenSocket != INVALID_SOCKET)
|
|
{
|
|
closesocket( g_pTelnetService->m_sFamily[IPV4_FAMILY].sListenSocket );
|
|
g_pTelnetService->m_sFamily[IPV4_FAMILY].sListenSocket = INVALID_SOCKET;
|
|
}
|
|
if (g_pTelnetService->m_sFamily[IPV6_FAMILY].sListenSocket != INVALID_SOCKET)
|
|
{
|
|
closesocket( g_pTelnetService->m_sFamily[IPV6_FAMILY].sListenSocket );
|
|
g_pTelnetService->m_sFamily[IPV6_FAMILY].sListenSocket = INVALID_SOCKET;
|
|
}
|
|
TELNET_CLOSE_HANDLE( g_pTelnetService->m_hSocketCloseEvent );
|
|
if (m_sFamily[IPV4_FAMILY].SocketAcceptEvent)
|
|
{
|
|
WSACloseEvent( m_sFamily[IPV4_FAMILY].SocketAcceptEvent );
|
|
}
|
|
if (m_sFamily[IPV6_FAMILY].SocketAcceptEvent)
|
|
{
|
|
WSACloseEvent( m_sFamily[IPV6_FAMILY].SocketAcceptEvent );
|
|
}
|
|
if(g_hProv)
|
|
{
|
|
CryptReleaseContext(g_hProv,0);
|
|
g_hProv = NULL;
|
|
}
|
|
WSACleanup();
|
|
return( TRUE );
|
|
}
|
|
|
|
bool
|
|
CTelnetService::IssueLicense( bool bIsIssued, CClientInfo *pClient )
|
|
{
|
|
UCHAR ucMsg = LICENSE_NOT_AVAILABLE;
|
|
|
|
if ( bIsIssued )
|
|
{
|
|
ucMsg = LICENSE_AVAILABLE;
|
|
}
|
|
if ( !WriteToPipe( pClient->hWritingPipe, ucMsg, &( m_oWriteToPipe ) ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
bool
|
|
CTelnetService::GetLicenseForWorkStation( SOCKET sSocket )
|
|
{
|
|
DWORD dwIndex = 0;
|
|
bool bRetVal = FALSE;
|
|
struct sockaddr_storage saddrPeer;
|
|
socklen_t slSize = sizeof( saddrPeer );
|
|
SfuZeroMemory( &saddrPeer, slSize );
|
|
if ( getpeername( sSocket, ( struct sockaddr * ) &saddrPeer, &slSize ) == SOCKET_ERROR )
|
|
{
|
|
goto GetLicenseForWorkStationAbort;
|
|
}
|
|
|
|
// Don't compare ports
|
|
SS_PORT(&saddrPeer) = 0;
|
|
|
|
for ( dwIndex = 0; dwIndex < m_dwNoOfWorkstations; dwIndex++ )
|
|
{
|
|
if ( !memcmp(&m_pssWorkstationList[ dwIndex ], &saddrPeer, slSize ))
|
|
{
|
|
bRetVal = TRUE;
|
|
goto GetLicenseForWorkStationAbort;
|
|
}
|
|
}
|
|
|
|
if ( m_dwNoOfWorkstations < DEFAULT_LICENSES_FOR_NTWKSTA )
|
|
{
|
|
m_pssWorkstationList[ m_dwNoOfWorkstations++ ] = saddrPeer;
|
|
bRetVal = TRUE;
|
|
}
|
|
GetLicenseForWorkStationAbort:
|
|
return( bRetVal );
|
|
}
|
|
|
|
bool
|
|
CTelnetService::CheckLicense( bool *bIsIssued, CClientInfo *pClient )
|
|
{
|
|
#if DBG
|
|
|
|
CHAR szDebug[MAX_STRING_LENGTH * 3];
|
|
|
|
#endif
|
|
|
|
bool bSuccess = false;
|
|
|
|
*bIsIssued = false; //Not issued
|
|
|
|
if ( !pClient )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
_TRACE(TRACE_DEBUGGING,L"In CheckLicense");
|
|
|
|
if ( m_dwNumOfActiveConnections >= m_dwMaxConnections )
|
|
{
|
|
static CHAR ansi_g_szMaxConnectionsReached[ MAX_STRING_LENGTH ] = { 0};
|
|
|
|
if ('\0' == ansi_g_szMaxConnectionsReached[0])
|
|
{
|
|
wsprintfA( ansi_g_szMaxConnectionsReached, "%lS", g_szMaxConnectionsReached ); // NO over flow here, Baskar
|
|
}
|
|
|
|
LogEvent( EVENTLOG_INFORMATION_TYPE, MSG_MAXCONNECTIONS, _T(" ") );
|
|
|
|
_TRACE(TRACE_DEBUGGING,L"CheckLicense : Max Conn reached. Freeing entry for %d",pClient->dwPid);
|
|
|
|
if ( InformTheClient( pClient->sSocket, ansi_g_szMaxConnectionsReached ) )
|
|
{
|
|
bSuccess = true;
|
|
}
|
|
|
|
goto FREE_ENTRY_AND_GET_OUT;
|
|
}
|
|
|
|
//if it is an NT Workstation
|
|
if ( m_bIsWorkStation )
|
|
{
|
|
_TRACE(TRACE_DEBUGGING,L"CheckLicense : Getting license for workstation");
|
|
|
|
if ( !GetLicenseForWorkStation( pClient->sSocket ) )
|
|
{
|
|
static CHAR wksta_error_msg[ sizeof(NTWKSTA_LICENSE_LIMIT) + sizeof(TERMINATE) + 1] = { 0};
|
|
|
|
if ('\0' == wksta_error_msg[0])
|
|
{
|
|
wsprintfA( wksta_error_msg, "%s%s", NTWKSTA_LICENSE_LIMIT, TERMINATE); // NO over flow here, Baskar
|
|
}
|
|
|
|
if ( InformTheClient( pClient->sSocket, wksta_error_msg ) )
|
|
{
|
|
bSuccess = true;
|
|
}
|
|
|
|
goto FREE_ENTRY_AND_GET_OUT;
|
|
}
|
|
else
|
|
{
|
|
bSuccess=true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NT_LS_DATA NtLSData = { 0};
|
|
CHAR usrnam[2*MAX_PATH + 1+ 1] = { 0}; // User + domain + \ + NULL
|
|
LS_STATUS_CODE Status = { 0};
|
|
|
|
|
|
_TRACE(TRACE_DEBUGGING,L"CheckLicense : License for server");
|
|
|
|
_snprintf(usrnam, 2*MAX_PATH + 1, "%s\\%s", pClient->szDomain, pClient->szUserName);
|
|
|
|
_TRACE(TRACE_DEBUGGING,L"CheckLicense : user name is %s",usrnam);
|
|
|
|
NtLSData.DataType = NT_LS_USER_NAME;
|
|
NtLSData.Data = usrnam;
|
|
NtLSData.IsAdmin = FALSE;
|
|
|
|
{
|
|
static CHAR szVersion[16] = { 0};
|
|
{
|
|
static OSVERSIONINFO osVersionInfo = { 0};
|
|
|
|
osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
if (0 == szVersion[0])
|
|
{
|
|
if ( !GetVersionEx( &osVersionInfo ) )
|
|
{
|
|
_TRACE( TRACE_DEBUGGING, "Error: GetVersionEx()" );
|
|
}
|
|
|
|
_snprintf( szVersion, (sizeof(szVersion) - 1), "%d.%d", osVersionInfo.dwMajorVersion,
|
|
osVersionInfo.dwMinorVersion );
|
|
}
|
|
}
|
|
|
|
Status = NtLicenseRequestA( "SMBServer", szVersion, &( pClient->m_hLicense), &NtLSData);
|
|
}
|
|
|
|
#if DBG
|
|
sprintf(szDebug,"License is %d. Status is %d \n",(DWORD)pClient->m_hLicense,Status);
|
|
OutputDebugStringA(szDebug);
|
|
#endif
|
|
|
|
switch ( Status)
|
|
{
|
|
case LS_SUCCESS :
|
|
// go ahead and do what you want
|
|
_TRACE(TRACE_DEBUGGING,L"CheckLicense : acquired license %d",(DWORD)pClient->m_hLicense);
|
|
bSuccess = true;
|
|
break;
|
|
|
|
// case LS_INSUFFICIENT_UNITS :
|
|
// case LS_RESOURCES_UNAVAILABLE:
|
|
default :
|
|
|
|
pClient->m_hLicense = INVALID_LICENSE_HANDLE;
|
|
|
|
{
|
|
static CHAR server_error_msg[ sizeof(NTSVR_LICENSE_LIMIT) + sizeof(TERMINATE) + 1] = { 0};
|
|
|
|
if ('\0' == server_error_msg[0])
|
|
{
|
|
wsprintfA( server_error_msg, "%s%s", NTSVR_LICENSE_LIMIT, TERMINATE); // NO over flow here, Baskar
|
|
}
|
|
|
|
_TRACE(TRACE_DEBUGGING,L"Error in acquiring a license");
|
|
|
|
if (InformTheClient( pClient->sSocket, server_error_msg ) )
|
|
{
|
|
bSuccess = true;
|
|
}
|
|
}
|
|
|
|
goto FREE_ENTRY_AND_GET_OUT;
|
|
}
|
|
}
|
|
|
|
if (bSuccess)
|
|
{
|
|
*bIsIssued = true;
|
|
|
|
//An active session is allowed now
|
|
|
|
m_dwNumOfActiveConnections++ ;
|
|
|
|
pClient->bLicenseIssued = true;
|
|
}
|
|
|
|
FREE_ENTRY_AND_GET_OUT:
|
|
|
|
CQList->FreeEntry(pClient->dwPid); // this client shoudl no longer be in the unauth list.
|
|
|
|
_TRACE(TRACE_DEBUGGING,L"CheckLicense : Freeing entry for %d",pClient->dwPid);
|
|
|
|
return( bSuccess );
|
|
}
|
|
|
|
void
|
|
CTelnetService::GetPathOfTheExecutable( LPTSTR *szCmdBuf )
|
|
{
|
|
DWORD length_required = wcslen( g_pszTelnetInstallPath ) + wcslen( DEFAULT_SCRAPER_PATH ) + 2; // One for \ and one more for NULL termination
|
|
LPTSTR lpszDefaultScraperFullPathName = new TCHAR[ length_required ];
|
|
|
|
*szCmdBuf = NULL; // First init this to NULL, so upon a failure the caller can check on this ptr != NULL; this function is a void returnee
|
|
|
|
if ( !lpszDefaultScraperFullPathName )
|
|
return;
|
|
|
|
_snwprintf(lpszDefaultScraperFullPathName, length_required - 1, L"%s\\%s", g_pszTelnetInstallPath, DEFAULT_SCRAPER_PATH);
|
|
lpszDefaultScraperFullPathName[length_required-1] = 0; // When the buffer is full snwprintf could return non-null terminated string
|
|
|
|
AllocateNExpandEnvStrings( lpszDefaultScraperFullPathName, szCmdBuf );
|
|
|
|
delete [] lpszDefaultScraperFullPathName;
|
|
|
|
return;
|
|
}
|
|
|
|
bool
|
|
CTelnetService::CreateSessionProcess( HANDLE hStdinPipe, HANDLE hStdoutPipe,
|
|
DWORD *dwProcessId, HANDLE *hProcess,
|
|
HWINSTA *window_station, HDESK *desktop)
|
|
{
|
|
PROCESS_INFORMATION pi = { 0};
|
|
STARTUPINFO si = { 0};
|
|
LPWSTR szCmdBuf = NULL;
|
|
BOOL fStatus = FALSE;
|
|
bool bRetVal = false;
|
|
|
|
*hProcess = INVALID_HANDLE_VALUE;
|
|
*dwProcessId = MAXDWORD;
|
|
|
|
si.cb = sizeof(si);
|
|
|
|
GetPathOfTheExecutable( &szCmdBuf );
|
|
|
|
if (szCmdBuf) // => GetPathXxx succeeded.
|
|
{
|
|
//Let the tlntsess.exe get created on Default desktop. We will create the new desktops
|
|
//in the session
|
|
FillProcessStartupInfo( &si, hStdinPipe, hStdoutPipe, hStdoutPipe, NULL);
|
|
|
|
fStatus = CreateProcess(
|
|
NULL,
|
|
szCmdBuf,
|
|
NULL,
|
|
NULL,
|
|
TRUE,
|
|
CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE,
|
|
NULL,
|
|
NULL,
|
|
&si,
|
|
&pi
|
|
);
|
|
|
|
_chVERIFY2(fStatus) ;
|
|
|
|
if ( !fStatus )
|
|
{
|
|
#if DBG
|
|
OutputDebugStringA("BASKAR: CreateProcess fails for TlntSess.exe\n");
|
|
#endif
|
|
LogFormattedGetLastError( EVENTLOG_ERROR_TYPE, MSG_ERR_CREATEPROCESS,
|
|
GetLastError() );
|
|
|
|
goto Done;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#if DBG
|
|
OutputDebugStringA("BASKAR: GetPathOfTheExecutable, tlntsess.exe failed\n");
|
|
#endif
|
|
LogFormattedGetLastError( EVENTLOG_ERROR_TYPE, MSG_ERR_CREATEPROCESS,
|
|
ERROR_NOT_ENOUGH_MEMORY );
|
|
|
|
goto Done;
|
|
}
|
|
|
|
*hProcess = pi.hProcess;
|
|
*dwProcessId = pi.dwProcessId;
|
|
bRetVal = true;
|
|
Done:
|
|
|
|
TELNET_CLOSE_HANDLE( pi.hThread );
|
|
if(szCmdBuf)
|
|
delete [] szCmdBuf; // no longer needed
|
|
|
|
return( bRetVal);
|
|
}
|
|
|
|
bool
|
|
CTelnetService::CreateClient(
|
|
SOCKET sSocket ,
|
|
DWORD *pdwPid,
|
|
HANDLE *phWritePipe,
|
|
CClientInfo **newClientInfo
|
|
)
|
|
{
|
|
HANDLE hProcess = INVALID_HANDLE_VALUE;
|
|
bool bRetVal = FALSE;
|
|
DWORD dwErr = 0;
|
|
DWORD dwProcessId;
|
|
|
|
HANDLE hStdinPipe = NULL;
|
|
HANDLE hStdoutPipe = NULL;
|
|
HANDLE hPipeRead = NULL;
|
|
HANDLE hPipeWrite = NULL;
|
|
HWINSTA window_station = NULL;
|
|
HDESK desktop = NULL;
|
|
bool bSuccess = false;
|
|
DWORD dwExitCode = 0;
|
|
bool release_mutex = false;
|
|
PSECURITY_DESCRIPTOR psd = NULL;
|
|
|
|
*newClientInfo = NULL;
|
|
|
|
_chASSERT( sSocket );
|
|
if ( sSocket == NULL )
|
|
{
|
|
goto Done;
|
|
}
|
|
|
|
|
|
*phWritePipe = NULL;
|
|
if(!TnCreateDefaultSecDesc(&psd, GENERIC_ALL &
|
|
~(WRITE_DAC | WRITE_OWNER | DELETE)))
|
|
{
|
|
goto Done;
|
|
}
|
|
if ( !CreateReadOrWritePipe( &hPipeRead, &hStdoutPipe, (SECURITY_DESCRIPTOR *)psd, READ_PIPE ) ||
|
|
!CreateReadOrWritePipe( &hStdinPipe, &hPipeWrite, (SECURITY_DESCRIPTOR *)psd, WRITE_PIPE ) )
|
|
{
|
|
goto ExitOnError;
|
|
}
|
|
|
|
if ( !( CreateSessionProcess( hStdinPipe, hStdoutPipe, &dwProcessId,
|
|
&hProcess, &window_station, &desktop ) ) )
|
|
{
|
|
InformTheClient( sSocket, CREATE_TLNTSESS_FAIL_MSG );
|
|
goto ExitOnError;
|
|
}
|
|
|
|
*pdwPid = dwProcessId;
|
|
_TRACE( TRACE_DEBUGGING, "new Telnet Client -- socket : %d , pid : %d", ( DWORD ) sSocket , dwProcessId);
|
|
|
|
//Make the following handles non-inheritable
|
|
_chVERIFY2( SetHandleInformation( hStdinPipe, HANDLE_FLAG_INHERIT, 0 ) );
|
|
_chVERIFY2( SetHandleInformation( hStdoutPipe, HANDLE_FLAG_INHERIT, 0 ) );
|
|
_chVERIFY2( SetHandleInformation( ( HANDLE ) sSocket, HANDLE_FLAG_INHERIT, 0 ) );
|
|
|
|
if ( !SendSocketToClient( hPipeWrite, sSocket, dwProcessId ) )
|
|
{
|
|
// Fix for HANDLE LEAK - close all handles
|
|
goto ExitOnError;
|
|
}
|
|
|
|
//The following is needed so that Count() and add() operations happen atomically
|
|
|
|
//HANDLE LEAK - maintain a bool to see if you acquired mutex - release at the end of the function???
|
|
dwErr = WaitForSingleObject( m_hSyncAllClientObjAccess, WAIT_TIME );
|
|
if ( dwErr != WAIT_OBJECT_0 )
|
|
{
|
|
//fix for HANDLE LEAK close all handles
|
|
if ( dwErr == WAIT_FAILED )
|
|
{
|
|
dwErr = GetLastError();
|
|
}
|
|
_TRACE(TRACE_DEBUGGING, "Error: WaitForSingleObject - 0x%1x", dwErr );
|
|
goto ExitOnError;
|
|
}
|
|
|
|
release_mutex = true;
|
|
|
|
_TRACE(TRACE_DEBUGGING, "Count of the ClientArray - %d, Count of sessions - %d", client_list_Count() , CQList->m_dwNumOfUnauthenticatedConnections + m_dwNumOfActiveConnections);
|
|
|
|
if ((NULL == m_hIPCThread) || (INVALID_HANDLE_VALUE == m_hIPCThread))
|
|
{
|
|
if (! StartThreads())
|
|
{
|
|
_TRACE(TRACE_DEBUGGING, "IPC Thread startup failed ? ");
|
|
goto ExitOnError;
|
|
}
|
|
}
|
|
|
|
*newClientInfo = new CClientInfo( hPipeRead, hPipeWrite,
|
|
hStdinPipe, hStdoutPipe,
|
|
sSocket, dwProcessId,
|
|
window_station, desktop);
|
|
if ( !*newClientInfo )
|
|
{
|
|
_TRACE(TRACE_DEBUGGING, "Failed to allocate memory for new client ");
|
|
goto ExitOnError;
|
|
}
|
|
|
|
// Once the handles are given to newClientInfo, its destructor will close them
|
|
|
|
hPipeRead = hPipeWrite = hStdinPipe = hStdoutPipe = INVALID_HANDLE_VALUE; // So we don't close these...
|
|
|
|
if ( !AssociateDeviceWithCompletionPort(
|
|
m_hCompletionPort, (*newClientInfo)->hReadingPipe, ( DWORD_PTR ) *newClientInfo ) )
|
|
{
|
|
goto ExitOnError;
|
|
}
|
|
|
|
if ( !client_list_Add( (PVOID)*newClientInfo ) )
|
|
{
|
|
_TRACE(TRACE_DEBUGGING, "Failed to add a new CClientInfo object ");
|
|
goto ExitOnError;
|
|
}
|
|
//We have succeeded.. if the IssueReadFromPipe() call fails, we clean up the clientinfo array and return SUCCESS
|
|
//if it succeeds, ONLY then we need to add this entry in the queue of unauthenticated connections. This check is
|
|
//made in the caller function ListenerThread(), where if pipehandle = NULL, we do not add the entry in the queue.
|
|
bRetVal=TRUE;
|
|
if ( IssueReadFromPipe( *newClientInfo ) )
|
|
{
|
|
if ( !DuplicateHandle( GetCurrentProcess(),(*newClientInfo)->hWritingPipe,
|
|
GetCurrentProcess(), phWritePipe,0,
|
|
FALSE, DUPLICATE_SAME_ACCESS) )
|
|
{
|
|
goto ExitOnError;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
StopServicingClient( *newClientInfo, (BOOL)FALSE );
|
|
goto ExitOnError; // cleanup everything but the socket passed. by falling through
|
|
}
|
|
goto Done;
|
|
|
|
ExitOnError:
|
|
|
|
if (*newClientInfo)
|
|
{
|
|
(*newClientInfo)->sSocket = INVALID_SOCKET; // So that the destructor below doesn't close this and cause accept to blow-up in listener thread - VadimE's dll found this, Baskar
|
|
delete *newClientInfo;
|
|
*newClientInfo = NULL;
|
|
}
|
|
else
|
|
{
|
|
TELNET_SYNC_CLOSE_HANDLE(hStdinPipe);
|
|
TELNET_SYNC_CLOSE_HANDLE(hStdoutPipe);
|
|
TELNET_SYNC_CLOSE_HANDLE(hPipeRead);
|
|
TELNET_SYNC_CLOSE_HANDLE(hPipeWrite);
|
|
}
|
|
|
|
Done:
|
|
if (release_mutex)
|
|
{
|
|
ReleaseMutex( m_hSyncAllClientObjAccess );
|
|
}
|
|
if(psd)
|
|
{
|
|
free(psd);
|
|
}
|
|
|
|
TELNET_CLOSE_HANDLE( hProcess );
|
|
return(bRetVal);
|
|
}
|
|
|
|
bool
|
|
CTelnetService::IssueReadAgain( CClientInfo *pClientInfo )
|
|
{
|
|
if (!pClientInfo->m_ReadFromPipeBuffer)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
UCHAR *pucReadBuffer = pClientInfo->m_ReadFromPipeBuffer;
|
|
|
|
if ( !pucReadBuffer )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
pucReadBuffer++; //Move past the message type
|
|
//Extract Size of rest of the meesage
|
|
memcpy( &( pClientInfo->m_dwRequestedSize ), pucReadBuffer,
|
|
sizeof( DWORD ) ); // NO overflow, Baskar
|
|
|
|
pucReadBuffer = new UCHAR[ pClientInfo->m_dwRequestedSize
|
|
+ IPC_HEADER_SIZE ];
|
|
if ( !pucReadBuffer )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
memcpy( pucReadBuffer, ( pClientInfo->m_ReadFromPipeBuffer ),
|
|
IPC_HEADER_SIZE ); // No overflow, Baskar
|
|
|
|
delete[] ( pClientInfo->m_ReadFromPipeBuffer );
|
|
pClientInfo->m_ReadFromPipeBuffer = NULL;
|
|
|
|
pClientInfo->m_ReadFromPipeBuffer = pucReadBuffer;
|
|
//position the pointer so that rest of the message is read in to
|
|
//proper place
|
|
pClientInfo->m_dwPosition = IPC_HEADER_SIZE;
|
|
|
|
return( IssueReadFromPipe( pClientInfo ) );
|
|
}
|
|
|
|
|
|
//Even if Read file finishes synchronously, we are intimated through the IO
|
|
// completion port. So no need to handle that case
|
|
|
|
bool
|
|
CTelnetService::IssueReadFromPipe( CClientInfo *pClientInfo )
|
|
{
|
|
|
|
bool bRetVal = TRUE;
|
|
DWORD dwReceivedDataSize;
|
|
|
|
if ( !pClientInfo->hReadingPipe || !pClientInfo->m_ReadFromPipeBuffer )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
UCHAR *pucReadBuffer = pClientInfo->m_ReadFromPipeBuffer +
|
|
pClientInfo->m_dwPosition;
|
|
|
|
if ( !ReadFile( pClientInfo->hReadingPipe, pucReadBuffer,
|
|
pClientInfo->m_dwRequestedSize, &dwReceivedDataSize,
|
|
&m_oReadFromPipe ) )
|
|
{
|
|
DWORD dwError = 0;
|
|
dwError = GetLastError( );
|
|
if ( dwError == ERROR_MORE_DATA )
|
|
{
|
|
//We reach here just in case it synchronously finishes
|
|
//with this error.
|
|
}
|
|
else if ( dwError != ERROR_IO_PENDING )
|
|
{
|
|
_TRACE( TRACE_DEBUGGING, " Error: ReadFile -- 0x%1x ", dwError );
|
|
bRetVal = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Read is completed synchronously by chance. It was actually
|
|
//an async call. All synchronously completed calls are also reported
|
|
//through the IO completion port
|
|
}
|
|
return bRetVal;
|
|
}
|
|
|
|
bool
|
|
CTelnetService::SendSocketToClient( HANDLE hPipeWrite,
|
|
SOCKET sSocket, DWORD dwPId )
|
|
{
|
|
_chASSERT( sSocket );
|
|
_chASSERT( hPipeWrite );
|
|
if ( !sSocket || !hPipeWrite )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
WSAPROTOCOL_INFO protocolInfo;
|
|
if ( WSADuplicateSocket( sSocket, dwPId, &protocolInfo ) )
|
|
{
|
|
DecodeWSAErrorCodes( WSAGetLastError() );
|
|
return( FALSE );
|
|
}
|
|
if ( !WriteToPipe( hPipeWrite, &protocolInfo, sizeof( WSAPROTOCOL_INFO ),
|
|
&( m_oWriteToPipe ) ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
bool
|
|
CTelnetService::InformTheClient( SOCKET sSocket, LPSTR pszMsg )
|
|
{
|
|
_chASSERT( pszMsg );
|
|
_chASSERT( sSocket );
|
|
if ( !sSocket || !pszMsg )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
DWORD dwLen = strlen( pszMsg ) + 1;
|
|
OVERLAPPED m_oWriteToSock;
|
|
InitializeOverlappedStruct( &m_oWriteToSock );
|
|
if ( !WriteFile( ( HANDLE ) sSocket, pszMsg, dwLen, &dwLen, &m_oWriteToSock))
|
|
{
|
|
DWORD dwErr;
|
|
if ( ( dwErr = GetLastError( ) ) != ERROR_IO_PENDING )
|
|
{
|
|
if ( dwErr != ERROR_NETNAME_DELETED )
|
|
{
|
|
LogFormattedGetLastError( EVENTLOG_ERROR_TYPE, MSG_ERR_WRITESOCKET, dwErr );
|
|
_TRACE( TRACE_DEBUGGING, "Error: WriteFile(InformTheClient) -- 0x%1x", dwErr );
|
|
_TRACE( TRACE_DEBUGGING, "Error writing to socket %d", (DWORD)sSocket);
|
|
}
|
|
return( FALSE );
|
|
}
|
|
}
|
|
TlntSynchronizeOn(m_oWriteToSock.hEvent);
|
|
TELNET_CLOSE_HANDLE( m_oWriteToSock.hEvent );
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//this is the function which the worker threads execute.
|
|
//------------------------------------------------------------------------------
|
|
|
|
DWORD WINAPI
|
|
DoIPCWithClients( LPVOID lpContext )
|
|
{
|
|
_chASSERT( lpContext != NULL );
|
|
if ( !lpContext )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
BOOL bSuccess = FALSE;
|
|
DWORD dwIoSize = 0;
|
|
LPOVERLAPPED lpOverlapped = NULL;
|
|
CClientInfo *pClientInfo = NULL;
|
|
bool bRetVal = TRUE;
|
|
bool bContinue = true;
|
|
CTelnetService *ctService = NULL;
|
|
|
|
ctService = ( CTelnetService *)lpContext;
|
|
while ( TRUE )
|
|
{
|
|
bSuccess = GetQueuedCompletionStatus( ctService->m_hCompletionPort,
|
|
&dwIoSize, ( PULONG_PTR ) &pClientInfo, &lpOverlapped, INFINITE );
|
|
|
|
if ( bSuccess == 0 )
|
|
{
|
|
if ( lpOverlapped == NULL )
|
|
{
|
|
DWORD dwErr = GetLastError();
|
|
|
|
// This could happen during a stop service call....
|
|
_TRACE( TRACE_DEBUGGING, "Error: GetQueuedCompletionStatus -- 0x%1x", dwErr );
|
|
// LogFormattedGetLastError( EVENTLOG_ERROR_TYPE, MSG_FAILGETQ, dwErr );
|
|
// _chASSERT( lpOverlapped != NULL );
|
|
bRetVal = FALSE;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
DWORD dwErr = GetLastError();
|
|
if ( dwErr == ERROR_MORE_DATA )
|
|
{
|
|
//Some data is read and more is to be read for this Message
|
|
|
|
ctService->IssueReadAgain( pClientInfo );
|
|
}
|
|
else
|
|
{
|
|
//When a session exits abruptly, whenever
|
|
//we try to write to it, we fail. As a result, We delete
|
|
//the object. Then, the async read posted on that pipe
|
|
//gets cancelled with the error code ERRO_BROKEN_PIPE.
|
|
//We should not access already deleted object. So....
|
|
if ( dwErr != ERROR_BROKEN_PIPE )
|
|
{
|
|
ctService->StopServicingClient( pClientInfo, (BOOL)TRUE );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ctService->OnCompletionPacket( pClientInfo, lpOverlapped );
|
|
}
|
|
|
|
}
|
|
|
|
TELNET_SYNC_CLOSE_HANDLE( g_pTelnetService->m_hCompletionPort );
|
|
|
|
return( bRetVal );
|
|
}
|
|
|
|
bool
|
|
CTelnetService::StopServicingClient( CClientInfo *pClientInfo, BOOL delete_the_class )
|
|
{
|
|
_chASSERT( pClientInfo );
|
|
|
|
bool bRetVal = TRUE;
|
|
DWORD dwErr = 0;
|
|
DWORD dwRetVal = 0,dwAvail = 0, dwLeft = 0;
|
|
CHAR *szBuffer = NULL;
|
|
|
|
if (! TlntSynchronizeOn(m_hSyncAllClientObjAccess))
|
|
{
|
|
_TRACE( TRACE_DEBUGGING, "Failed to get access to mutex. Did not "
|
|
" remove the client" );
|
|
return(bRetVal);
|
|
}
|
|
if(!PeekNamedPipe(pClientInfo->hReadingPipe,szBuffer,0,&dwRetVal,&dwAvail,&dwLeft))
|
|
{
|
|
dwRetVal = GetLastError();
|
|
if(dwRetVal == ERROR_INVALID_HANDLE)
|
|
{
|
|
bRetVal = FALSE;
|
|
ReleaseMutex(m_hSyncAllClientObjAccess);
|
|
return(bRetVal);
|
|
}
|
|
}
|
|
if ( !pClientInfo )
|
|
{
|
|
if ( client_list_Count() == 0 )
|
|
{
|
|
bRetVal = FALSE;
|
|
}
|
|
ReleaseMutex(m_hSyncAllClientObjAccess);
|
|
return( bRetVal );
|
|
}
|
|
|
|
//Number of active connections decreses by one only if it was given license
|
|
if ( pClientInfo->bLicenseIssued )
|
|
{
|
|
if(m_dwNumOfActiveConnections>0)
|
|
m_dwNumOfActiveConnections--;
|
|
}
|
|
_TRACE( TRACE_DEBUGGING,"removing element from pclientinfo : pid : %d, socket : %d ", pClientInfo->dwPid,(DWORD)pClientInfo->sSocket);
|
|
if ( !client_list_RemoveElem( pClientInfo ) )
|
|
{
|
|
_TRACE( TRACE_DEBUGGING, "Could not delete the client",
|
|
pClientInfo->dwPid );
|
|
}
|
|
|
|
if (delete_the_class)
|
|
{
|
|
delete pClientInfo;
|
|
}
|
|
|
|
//If there are no more clients to service, exit the thread
|
|
if ( client_list_Count() == 0 )
|
|
{
|
|
bRetVal = FALSE;
|
|
}
|
|
ReleaseMutex( m_hSyncAllClientObjAccess );
|
|
|
|
return bRetVal;
|
|
}
|
|
|
|
bool
|
|
CTelnetService::OnCompletionPacket( CClientInfo *pClientInfo,
|
|
LPOVERLAPPED lpoObject )
|
|
{
|
|
_chASSERT( lpoObject != NULL );
|
|
_chASSERT( pClientInfo != NULL );
|
|
|
|
bool bRetVal = TRUE;
|
|
|
|
if ( !lpoObject || !pClientInfo )
|
|
{
|
|
if ( client_list_Count() == 0 )
|
|
{
|
|
bRetVal = FALSE;
|
|
}
|
|
return( bRetVal );
|
|
}
|
|
|
|
if ( lpoObject == &m_oReadFromPipe )
|
|
{
|
|
//Asynchronous read from the pipe has finished.
|
|
bRetVal = IPCDataDriver( pClientInfo );
|
|
}
|
|
else if ( lpoObject == &m_oPostedMessage )
|
|
{
|
|
//We should reach here on messages from other threads sent through
|
|
//PostQueuedCompletionStatus
|
|
|
|
bRetVal = HandleInProcMessages( TLNTSVR_SHUTDOWN );
|
|
}
|
|
else
|
|
{
|
|
_chASSERT( 0 );
|
|
}
|
|
|
|
return bRetVal;
|
|
}
|
|
|
|
bool
|
|
CTelnetService::SetNewRegKeyValues( DWORD dwNewTelnetPort,
|
|
DWORD dwNewMaxConnections,
|
|
DWORD dwNewMaxFileSize,
|
|
LPWSTR pszNewLogFile, LPWSTR pszNewIpAddr, DWORD dwLogToFile )
|
|
{
|
|
bool bIPV4 = false;
|
|
bool bIPV6 = false;
|
|
if ( wcscmp( pszNewIpAddr, m_pszIpAddrToListenOn ) || dwNewTelnetPort != m_dwTelnetPort )
|
|
{
|
|
if (m_sFamily[IPV4_FAMILY].sListenSocket && m_sFamily[IPV4_FAMILY].sListenSocket != INVALID_SOCKET)
|
|
{
|
|
_TRACE(TRACE_DEBUGGING,"IPV4 socket closure");
|
|
closesocket( m_sFamily[IPV4_FAMILY].sListenSocket );
|
|
m_sFamily[IPV4_FAMILY].sListenSocket = INVALID_SOCKET;
|
|
bIPV4 = true;
|
|
}
|
|
if (m_sFamily[IPV6_FAMILY].sListenSocket && m_sFamily[IPV6_FAMILY].sListenSocket != INVALID_SOCKET )
|
|
{
|
|
_TRACE(TRACE_DEBUGGING,"IPV6 socket closure");
|
|
closesocket( m_sFamily[IPV6_FAMILY].sListenSocket );
|
|
m_sFamily[IPV6_FAMILY].sListenSocket = INVALID_SOCKET;
|
|
bIPV6 = true;
|
|
}
|
|
delete[] m_pszIpAddrToListenOn;
|
|
|
|
m_pszIpAddrToListenOn = pszNewIpAddr;
|
|
m_dwTelnetPort = dwNewTelnetPort;
|
|
if (bIPV4)
|
|
{
|
|
WSAResetEvent( m_sFamily[IPV4_FAMILY].SocketAcceptEvent );
|
|
_TRACE(TRACE_DEBUGGING,"IPV4 socket creation");
|
|
CreateSocket(IPV4_FAMILY);
|
|
}
|
|
if (bIPV6)
|
|
{
|
|
WSAResetEvent( m_sFamily[IPV6_FAMILY].SocketAcceptEvent );
|
|
CreateSocket(IPV6_FAMILY);
|
|
_TRACE(TRACE_DEBUGGING,"IPV6 socket creation");
|
|
}
|
|
}
|
|
|
|
if ( dwNewMaxConnections != m_dwMaxConnections )
|
|
{
|
|
/*++
|
|
If the registry value for MaxConnections get modified, we should also
|
|
modify the maximum number of unauthenticated connections allowed.
|
|
--*/
|
|
InterlockedExchange( (PLONG)&m_dwMaxConnections, dwNewMaxConnections );
|
|
InterlockedExchange( (PLONG)&(CQList->m_dwMaxUnauthenticatedConnections), dwNewMaxConnections );
|
|
}
|
|
|
|
if ( dwNewMaxFileSize != (DWORD)g_lMaxFileSize )
|
|
{
|
|
InterlockedExchange( &g_lMaxFileSize, dwNewMaxFileSize );
|
|
}
|
|
|
|
if ( wcscmp( pszNewLogFile, g_pszLogFile ) != 0 )
|
|
{
|
|
HANDLE *phNewLogFile = NULL;
|
|
HANDLE *phOldLogFile = g_phLogFile;
|
|
|
|
phNewLogFile = new HANDLE;
|
|
if ( !phNewLogFile )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
InitializeLogFile( pszNewLogFile, phNewLogFile );
|
|
InterlockedExchangePointer( ( PVOID * )&g_phLogFile, phNewLogFile );
|
|
CloseLogFile( &g_pszLogFile, phOldLogFile );
|
|
g_pszLogFile = pszNewLogFile;
|
|
//Don't delete pszNewLogFile
|
|
}
|
|
|
|
//Now onwards log to file
|
|
if ( dwLogToFile && !g_fLogToFile )
|
|
{
|
|
g_fLogToFile = true;
|
|
InitializeLogFile( g_pszLogFile, g_phLogFile );
|
|
}
|
|
else
|
|
{
|
|
//Now onwards don't log to file
|
|
if ( !dwLogToFile && g_fLogToFile )
|
|
{
|
|
g_fLogToFile = false;
|
|
TELNET_CLOSE_HANDLE( *g_phLogFile );
|
|
*g_phLogFile = NULL;
|
|
}
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
bool
|
|
CTelnetService::HandleInProcMessages( DWORD dwMsg )
|
|
{
|
|
bool bRetVal = TRUE;
|
|
|
|
if ( dwMsg == TLNTSVR_SHUTDOWN )
|
|
{
|
|
//Make the thread return
|
|
bRetVal = FALSE;
|
|
}
|
|
|
|
return bRetVal;
|
|
}
|
|
|
|
|
|
//Each IPC packet is to be decoded in the following manner:
|
|
//UCHAR Message : indicating type of message
|
|
//DWORD Size : size of the following message if any
|
|
//UCHAR *Data : data if any for the given message
|
|
//When a message indicates that it is may have variable size, The first element
|
|
//Data points is of a DWORD indicating size and then the data.
|
|
//This is not true for the initial socket handover where only protocol structure
|
|
//is sent.
|
|
|
|
bool
|
|
CTelnetService::IPCDataDriver( CClientInfo *pClientInfo )
|
|
{
|
|
_chASSERT( pClientInfo );
|
|
|
|
bool bRetVal = true;
|
|
|
|
if ( !pClientInfo )
|
|
{
|
|
if ( client_list_Count() == 0 )
|
|
{
|
|
bRetVal = false;
|
|
}
|
|
return bRetVal;
|
|
}
|
|
|
|
UCHAR *pBuff = NULL;
|
|
|
|
//Don't do a delete on pBuff by mistake
|
|
pBuff = pClientInfo->m_ReadFromPipeBuffer;
|
|
bool bStopService = false;
|
|
bool bIsLicenseIssued = false;
|
|
DWORD dwPid=0;
|
|
|
|
switch ( *pBuff++ )
|
|
{
|
|
case RESET_IDLE_TIME:
|
|
pClientInfo->m_dwIdleTime = 0;
|
|
break;
|
|
case UPDATE_IDLE_TIME:
|
|
pClientInfo->m_dwIdleTime += MAX_POLL_INTERVAL;
|
|
break;
|
|
case SESSION_EXIT:
|
|
dwPid = (DWORD)pClientInfo->dwPid;
|
|
bRetVal = ExitTheSession( pClientInfo );
|
|
_TRACE(TRACE_DEBUGGING,"Deleting session pid : %d",dwPid);
|
|
CQList->FreeEntry(dwPid);
|
|
goto FinishTheThread;
|
|
|
|
case AUDIT_CLIENT :
|
|
//The data is expected exactly in the form used
|
|
//to be written in the file
|
|
|
|
pBuff += sizeof( DWORD ); //Move past message size
|
|
|
|
if ( *g_phLogFile )
|
|
{
|
|
WriteAuditedMsgsToFile( ( CHAR * )pBuff );
|
|
}
|
|
|
|
//delete the message. Such a big amt of memory
|
|
//is no more needed
|
|
|
|
delete[] (pClientInfo->m_ReadFromPipeBuffer);
|
|
pClientInfo->m_ReadFromPipeBuffer = new UCHAR[
|
|
IPC_HEADER_SIZE ];
|
|
if (!pClientInfo->m_ReadFromPipeBuffer )
|
|
{
|
|
bStopService = true;
|
|
}
|
|
pClientInfo->m_dwRequestedSize = IPC_HEADER_SIZE;
|
|
break;
|
|
|
|
case SESSION_DETAILS:
|
|
HandleSessionDetailsMessage( pClientInfo );
|
|
_TRACE(TRACE_DEBUGGING,L"In session_details");
|
|
//delete the message. Such a big amt of memory
|
|
//is no more needed
|
|
if (pClientInfo->m_ReadFromPipeBuffer )
|
|
{
|
|
_TRACE(TRACE_DEBUGGING,L"deleting ReadFromPipeBuffer");
|
|
delete[] ( pClientInfo->m_ReadFromPipeBuffer );
|
|
pClientInfo->m_ReadFromPipeBuffer = NULL;
|
|
}
|
|
|
|
pClientInfo->m_ReadFromPipeBuffer =
|
|
new UCHAR[ IPC_HEADER_SIZE ];
|
|
if ( !pClientInfo->m_ReadFromPipeBuffer )
|
|
{
|
|
bStopService = true;
|
|
pClientInfo->m_dwRequestedSize = 0;
|
|
_TRACE(TRACE_DEBUGGING,L"new failed for ReadFromPipeBuffer");
|
|
goto ExitOnErrorInDetails;
|
|
}
|
|
else
|
|
{
|
|
pClientInfo->m_dwRequestedSize = IPC_HEADER_SIZE;
|
|
|
|
if ( !CheckLicense( &bIsLicenseIssued, pClientInfo ) )
|
|
{
|
|
bStopService = true;
|
|
_TRACE(TRACE_DEBUGGING,L"checklicense failed");
|
|
goto ExitOnErrorInDetails;
|
|
}
|
|
if ( !IssueLicense( bIsLicenseIssued, pClientInfo ) )
|
|
{
|
|
bStopService = true;
|
|
_TRACE(TRACE_DEBUGGING,L"issue license failed");
|
|
goto ExitOnErrorInDetails;
|
|
}
|
|
}
|
|
//Close the session soc handle
|
|
ExitOnErrorInDetails:
|
|
pClientInfo->CloseClientSocket() ;
|
|
|
|
|
|
break;
|
|
default:
|
|
_TRACE( TRACE_DEBUGGING, "Unknown IPC message:%uc",
|
|
pClientInfo->m_ReadFromPipeBuffer[0] );
|
|
}
|
|
|
|
//Reset where to read -- Begining of the buffer
|
|
pClientInfo->m_dwPosition = 0;
|
|
|
|
//Issue a read call again
|
|
if ( bStopService || !IssueReadFromPipe( pClientInfo ) )
|
|
{
|
|
bRetVal = StopServicingClient( pClientInfo, (BOOL)TRUE );
|
|
}
|
|
|
|
FinishTheThread:
|
|
return( bRetVal );
|
|
}
|
|
|
|
void
|
|
CTelnetService::HandleSessionDetailsMessage( CClientInfo *pClientInfo )
|
|
{
|
|
UCHAR *pBuff = NULL;
|
|
if (!pClientInfo->m_ReadFromPipeBuffer)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//Don't do a delete on pBuff by mistake
|
|
pBuff = pClientInfo->m_ReadFromPipeBuffer;
|
|
|
|
pBuff++; // Move past Message type
|
|
pBuff += sizeof( DWORD ); //Move past message size
|
|
|
|
DWORD dwStrLen = 0;
|
|
|
|
//Domain
|
|
dwStrLen = strlen( ( LPCSTR ) pBuff ) + 1;
|
|
pClientInfo->szDomain = new CHAR[ dwStrLen ];
|
|
if ( !pClientInfo->szDomain )
|
|
{
|
|
return;
|
|
}
|
|
|
|
memcpy( pClientInfo->szDomain, pBuff, dwStrLen ); // No BO in this Baskar
|
|
pBuff += dwStrLen;
|
|
|
|
//Username
|
|
dwStrLen = strlen( ( LPCSTR ) pBuff ) + 1;
|
|
pClientInfo->szUserName = new CHAR[ dwStrLen ];
|
|
if ( !pClientInfo->szUserName )
|
|
{
|
|
return;
|
|
}
|
|
memcpy( pClientInfo->szUserName, pBuff, dwStrLen ); // No BO in this Baskar
|
|
pBuff += dwStrLen;
|
|
|
|
//Remote machine
|
|
dwStrLen = strlen( ( LPCSTR ) pBuff ) + 1;
|
|
pClientInfo->szRemoteMachine = new CHAR[ dwStrLen ];
|
|
if ( !pClientInfo->szRemoteMachine )
|
|
{
|
|
return;
|
|
}
|
|
memcpy( pClientInfo->szRemoteMachine, pBuff, dwStrLen ); // No BO in this Baskar
|
|
pBuff += dwStrLen;
|
|
|
|
//Logon identifier
|
|
pClientInfo->pAuthId = new LUID;
|
|
if ( !pClientInfo->pAuthId )
|
|
{
|
|
return;
|
|
}
|
|
memcpy( pClientInfo->pAuthId, pBuff, sizeof( LUID ) ); // No BO in this Baskar
|
|
|
|
pClientInfo->lpLogonTime = new SYSTEMTIME;
|
|
if ( !pClientInfo->lpLogonTime )
|
|
{
|
|
return;
|
|
}
|
|
GetSystemTime( pClientInfo->lpLogonTime );
|
|
}
|
|
|
|
bool
|
|
CTelnetService::ExitTheSession( CClientInfo *pClientInfo )
|
|
{
|
|
bool bRetVal = TRUE;
|
|
|
|
_TRACE( TRACE_DEBUGGING, "ExitTheSession -- pid : %d, socket :%d",
|
|
pClientInfo->dwPid,( DWORD ) pClientInfo->sSocket );
|
|
bRetVal = StopServicingClient( pClientInfo, (BOOL)TRUE );
|
|
|
|
return bRetVal;
|
|
}
|
|
|