Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

477 lines
12 KiB

/**********************************************************************/
/** Microsoft Windows NT **/
/** Copyright(c) Microsoft Corp., 1994 **/
/**********************************************************************/
/*
connect.cxx
This module contains the connection accept routine called by the connection
thread.
FILE HISTORY:
Johnl 08-Aug-1994 Lifted from FTP server
*/
#include "w3p.hxx"
//
// Private constants.
//
//
// Private globals.
//
LONG fLicenseExceededWarning = FALSE;
//
// Private prototypes.
//
BOOL CreateClient( PATQ_CONTEXT patqContext,
SOCKET sNew,
PVOID pvBuff,
DWORD cbBuff,
SOCKADDR * psockaddrLocal,
SOCKADDR * psockaddrRemote );
BOOL CheckSiteAccess( SOCKET sNew,
SOCKADDR_IN * psockaddrHost,
BOOL * pfGranted );
BOOL
SendError(
SOCKET socket,
DWORD ids
);
//
// Public functions.
//
//
// Private functions.
//
inline
VOID
LogLicenseExceededWarning(
VOID
)
{
//
// Make sure we only log one event in the event log
//
if ( !InterlockedExchange( &fLicenseExceededWarning, TRUE ))
{
g_pTsvcInfo->LogEvent( W3_EVENT_LICENSES_EXCEEDED,
0,
(WCHAR **) NULL,
NO_ERROR );
}
}
/*******************************************************************
NAME: W3OnConnect
SYNOPSIS: Handles the incoming connection indication from the
connection thread
ENTRY: sNew - New client socket
HISTORY:
KeithMo 09-Mar-1993 Created.
Johnl 02-Aug-1994 Reworked from FTP server
********************************************************************/
VOID W3OnConnect( SOCKET sNew,
SOCKADDR_IN * psockaddr )
{
BOOL fAllowConnection = FALSE;
TCP_ASSERT( sNew != INVALID_SOCKET );
INCREMENT_COUNTER( ConnectionAttempts );
IF_DEBUG( SOCKETS )
{
TCP_PRINT(( DBG_CONTEXT,
"connect received from %s, socket = %d\n",
inet_ntoa( psockaddr->sin_addr ),
sNew ));
}
#if PDC_96
if( cConnectedUsers >= 6 )
{
TCP_PRINT((DBG_CONTEXT,
"[W3OnConnect] Too many connected users (%d), refusing connection\n",
cConnectedUsers ));
SendError( sNew, IDS_TOO_MANY_USERS );
}
else
#endif
if( cConnectedUsers >= g_pTsvcInfo->QueryMaxConnections() )
{
TCP_PRINT((DBG_CONTEXT,
"[W3OnConnect] Too many connected users (%d), refusing connection\n",
cConnectedUsers ));
SendError( sNew, IDS_TOO_MANY_USERS );
}
else if ( cConnectedUsers >= g_cMaxLicenses )
{
LogLicenseExceededWarning();
SendError( sNew, IDS_OUT_OF_LICENSES );
}
else
if( g_pTsvcInfo->QueryCurrentServiceState() == SERVICE_RUNNING )
{
fAllowConnection = TRUE;
}
if( fAllowConnection )
{
//
// We've got a new connection. Add this to the work list
//
if ( !CreateClient( NULL,
sNew,
NULL,
0,
NULL,
(SOCKADDR *) psockaddr ))
{
CloseSocket( sNew );
}
}
else
CloseSocket( sNew );
}
VOID
W3OnConnectEx(
VOID * patqContext,
DWORD cbWritten,
DWORD err,
OVERLAPPED * lpo
)
{
BOOL fAllowConnection = FALSE;
PVOID pvBuff;
SOCKADDR * psockaddrLocal;
SOCKADDR * psockaddrRemote;
SOCKET sNew;
if ( err || !lpo )
{
TCP_PRINT(( DBG_CONTEXT,
"[W3OnConnectEx] Completion failed with error %d, Atq context %lx\n",
err,
patqContext ));
AtqCloseSocket( (PATQ_CONTEXT) patqContext, FALSE );
AtqFreeContext( (PATQ_CONTEXT) patqContext, TRUE );
return;
}
INCREMENT_COUNTER( ConnectionAttempts );
IF_DEBUG( SOCKETS )
{
TCP_PRINT(( DBG_CONTEXT,
"[W3OnConnectEx] connection received\n" ));
}
#if PDC_96
if( cConnectedUsers >= 6 )
{
TCP_PRINT((DBG_CONTEXT,
"[W3OnConnect] Too many connected users (%d), refusing connection\n",
cConnectedUsers ));
SendError( sNew, IDS_TOO_MANY_USERS );
}
else
#endif
if( cConnectedUsers >= g_pTsvcInfo->QueryMaxConnections() )
{
TCP_PRINT((DBG_CONTEXT,
"[W3OnConnect] Too many connected users (%d), refusing connection\n",
cConnectedUsers ));
SendError( (SOCKET) ((PATQ_CONTEXT)patqContext)->hAsyncIO,
IDS_TOO_MANY_USERS );
}
else if ( cConnectedUsers >= g_cMaxLicenses )
{
LogLicenseExceededWarning();
SendError( (SOCKET) ((PATQ_CONTEXT)patqContext)->hAsyncIO,
IDS_OUT_OF_LICENSES );
}
else
if( g_pTsvcInfo->QueryCurrentServiceState() == SERVICE_RUNNING )
{
fAllowConnection = TRUE;
}
if( fAllowConnection )
{
AtqGetAcceptExAddrs( (PATQ_CONTEXT) patqContext,
&sNew,
&pvBuff,
&psockaddrLocal,
&psockaddrRemote );
IF_DEBUG( CONNECTION )
{
TCP_PRINT(( DBG_CONTEXT,
"[W3OnConnectEx] New connection, AtqCont = %lx, buf = %lx, written = %d\n",
patqContext,
pvBuff,
cbWritten ));
}
//
// Set the timeout for future IOs on this context
//
AtqContextSetInfo( (PATQ_CONTEXT) patqContext,
ATQ_INFO_TIMEOUT,
g_pTsvcInfo->QueryConnectionTimeout() );
//
// We've got a new connection. Add this to the work list
//
if ( !CreateClient( (PATQ_CONTEXT) patqContext,
sNew,
pvBuff,
cbWritten,
psockaddrLocal,
psockaddrRemote ))
{
TCP_REQUIRE( AtqCloseSocket( (PATQ_CONTEXT) patqContext, FALSE ));
AtqFreeContext( (PATQ_CONTEXT) patqContext, TRUE );
}
}
else
{
//
// This will also close the socket
//
TCP_REQUIRE( AtqCloseSocket( (PATQ_CONTEXT) patqContext, FALSE ));
AtqFreeContext( (PATQ_CONTEXT) patqContext, TRUE );
}
}
/*******************************************************************
NAME: CreateClient
SYNOPSIS: Creates a new connection object that manages the
client requests
ENTRY: sNew - New client socket
HISTORY:
KeithMo 09-Mar-1993 Created.
Johnl 02-Aug-1994 Reworked from FTP server
********************************************************************/
BOOL CreateClient( PATQ_CONTEXT patqContext,
SOCKET sNew,
PVOID pvBuff,
DWORD cbBuff,
SOCKADDR * psockaddrLocal,
SOCKADDR * psockaddrRemote )
{
APIERR err = NO_ERROR;
CLIENT_CONN * pConn = NULL;
BOOL fGranted;
//
// Check if this site accepts connections from the client site. The
// appropriate response will be sent by the called routine
//
if ( !CheckSiteAccess( sNew,
(SOCKADDR_IN *) psockaddrRemote,
&fGranted ) ||
!fGranted )
{
//
// Close the socket with a shutdown so the access denied message
// doesn't get chopped with a reset
//
TCP_REQUIRE( AtqCloseSocket( patqContext, TRUE ));
return FALSE;
}
pConn = CLIENT_CONN::Alloc( sNew,
(SOCKADDR_IN *) psockaddrLocal,
(SOCKADDR_IN *) psockaddrRemote,
patqContext,
pvBuff,
cbBuff );
if( pConn == NULL ||
!pConn->IsValid() )
{
err = pConn ? GetLastError() : ERROR_NOT_ENOUGH_MEMORY;
}
else
{
//
// We only have a context at this point if we're using AcceptEx
//
if ( patqContext )
{
//
// Associate the Client connection object with this socket handle
// for future completions
//
AtqContextSetInfo( patqContext,
ATQ_INFO_COMPLETION_CONTEXT,
(DWORD) pConn );
IF_DEBUG( CONNECTION )
{
TCP_PRINT(( DBG_CONTEXT,
"[CreateClient] Setting Atq context %lx context to Conn object %lx\n",
patqContext,
pConn ));
}
}
//
// Kickstart the process. This will do an async read to get the
// client's header or it will start processing the receive buffer
// if AcceptEx is being used.
//
ReferenceConn( pConn );
TCP_REQUIRE( pConn->DoWork( 0,
NO_ERROR,
NULL ));
DereferenceConn( pConn );
return TRUE;
}
const CHAR * apszSubStrings[1];
apszSubStrings[0] = inet_ntoa( ((SOCKADDR_IN *)psockaddrRemote)->sin_addr );
g_pTsvcInfo->LogEvent( W3_EVENT_CANNOT_CREATE_CLIENT_CONN,
1,
apszSubStrings,
err );
TCP_PRINT(( DBG_CONTEXT,
"cannot create client object, error %lu\n",
err ));
if ( pConn )
{
CLIENT_CONN::Free( pConn );
}
return FALSE;
} // CreateClient
/*******************************************************************
NAME: CheckSiteAccess
SYNOPSIS: Determines if the specified client site has access to this
site.
ENTRY: psockaddrHost - Host socket address
HISTORY:
Johnl 02-Aug-1994 Created
********************************************************************/
BOOL CheckSiteAccess( SOCKET socket,
SOCKADDR_IN * psockaddr,
BOOL * pfGranted )
{
if ( !g_pTsvcInfo->IPAccessCheck( psockaddr,
pfGranted ))
{
return FALSE;
}
if ( *pfGranted )
return TRUE;
//
// This address was denied, send a nice response and disconnect
//
return SendError( socket,
IDS_SITE_ACCESS_DENIED );
}
BOOL
SendError(
SOCKET socket,
DWORD ids
)
{
STR strResponse;
if ( !strResponse.Resize( 512 ) ||
!HTTP_REQ_BASE::BuildExtendedStatus( &strResponse,
HT_FORBIDDEN,
NO_ERROR,
ids ))
{
TCP_PRINT((DBG_CONTEXT,
"[SendError] Failed to build status (error %d)\n",
GetLastError()));
return FALSE;
}
//
// Do a synchronous send
//
send( socket,
strResponse.QueryStr(),
strResponse.QueryCB(),
0 );
return TRUE ;
}