mirror of https://github.com/lianthony/NT4.0
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
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 ;
|
|
}
|
|
|
|
|