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.
683 lines
16 KiB
683 lines
16 KiB
/**********************************************************************/
|
|
/** Microsoft Windows NT **/
|
|
/** Copyright(c) Microsoft Corp., 1993 **/
|
|
/**********************************************************************/
|
|
|
|
/*
|
|
globals.cxx
|
|
|
|
This module contains global variable definitions shared by the
|
|
various FTPD Service components.
|
|
|
|
Functions exported by this module:
|
|
|
|
InitializeGlobals
|
|
TerminateGlobals
|
|
ClearStatistics
|
|
ReadParamsFromRegistry
|
|
WriteParamsToRegistry
|
|
|
|
|
|
FILE HISTORY:
|
|
KeithMo 07-Mar-1993 Created.
|
|
MuraliK 11-April-1995 Created new global ftp server config object
|
|
|
|
*/
|
|
|
|
|
|
#include "ftpdp.hxx"
|
|
|
|
|
|
//
|
|
// Private constants.
|
|
//
|
|
|
|
#define DEFAULT_ALLOW_ANONYMOUS TRUE
|
|
#define DEFAULT_ALLOW_GUEST_ACCESS TRUE
|
|
#define DEFAULT_ANONYMOUS_ONLY FALSE
|
|
#define DEFAULT_DEBUG_FLAGS 0
|
|
#define DEFAULT_READ_ACCESS_MASK 0
|
|
#define DEFAULT_WRITE_ACCESS_MASK 0
|
|
#define DEFAULT_EXIT_MESSAGE "Goodbye."
|
|
#define DEFAULT_MAX_CLIENTS_MSG "Maximum clients reached, service unavailable."
|
|
#define DEFAULT_GREETING_MESSAGE NULL // NULL == no special greeting.
|
|
#define DEFAULT_LOWERCASE_FILES FALSE
|
|
#define DEFAULT_LISTEN_BACKLOG 5
|
|
#define DEFAULT_ENABLE_LICENSING FALSE
|
|
#define DEFAULT_DEFAULT_LOGON_DOMAIN NULL // NULL == use primary domain
|
|
|
|
|
|
|
|
|
|
//
|
|
// Socket transfer buffer size.
|
|
//
|
|
|
|
DWORD g_SocketBufferSize;
|
|
|
|
//
|
|
// Statistics.
|
|
//
|
|
|
|
//
|
|
// FTP Statistics structure.
|
|
//
|
|
|
|
FTP_STATISTICS_0 g_FtpStatistics;
|
|
|
|
//
|
|
// Statistics structure lock.
|
|
//
|
|
|
|
CRITICAL_SECTION g_StatisticsLock;
|
|
|
|
|
|
//
|
|
// Miscellaneous data.
|
|
//
|
|
|
|
//
|
|
// The current FTP Server version number.
|
|
//
|
|
|
|
LPSTR g_FtpVersionString;
|
|
|
|
//
|
|
// For FTP server configuration information
|
|
//
|
|
|
|
LPFTP_SERVER_CONFIG g_pFtpServerConfig;
|
|
|
|
|
|
//
|
|
// key for the registry to read parameters
|
|
//
|
|
HKEY g_hkeyParams = NULL;
|
|
|
|
|
|
//
|
|
// The global variable lock.
|
|
//
|
|
|
|
CRITICAL_SECTION g_GlobalLock;
|
|
|
|
#ifdef KEEP_COMMAND_STATS
|
|
|
|
//
|
|
// Lock protecting per-command statistics.
|
|
//
|
|
|
|
CRITICAL_SECTION g_CommandStatisticsLock;
|
|
|
|
#endif // KEEP_COMMAND_STATS
|
|
|
|
|
|
#if DBG
|
|
|
|
//
|
|
// Debug-specific data.
|
|
//
|
|
|
|
//
|
|
// Debug output control flags.
|
|
//
|
|
|
|
#endif // DBG
|
|
|
|
# if DBG
|
|
VOID
|
|
PrintConfiguration( VOID);
|
|
# endif
|
|
|
|
BOOL
|
|
GenDoubleNullStringFromMultiLine( IN LPCWSTR lpsz,
|
|
IN OUT LPWSTR * ppszz,
|
|
IN OUT LPDWORD pcchLen);
|
|
|
|
extern DWORD g_dwRfcDataPort;
|
|
|
|
|
|
//
|
|
// Public functions.
|
|
//
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: InitializeGlobals
|
|
|
|
SYNOPSIS: Initializes global shared variables. Some values are
|
|
initialized with constants, others are read from the
|
|
configuration registry.
|
|
|
|
RETURNS: APIERR - NO_ERROR if successful, otherwise a Win32
|
|
error code.
|
|
|
|
NOTES: This routine may only be called by a single thread
|
|
of execution; it is not necessarily multi-thread safe.
|
|
|
|
Also, this routine is called before the event logging
|
|
routines have been initialized. Therefore, event
|
|
logging is not available.
|
|
|
|
HISTORY:
|
|
KeithMo 07-Mar-1993 Created.
|
|
MuraliK 05-April-1995 Added FTP server config object
|
|
|
|
********************************************************************/
|
|
APIERR
|
|
InitializeGlobals(
|
|
VOID
|
|
)
|
|
{
|
|
APIERR err = NO_ERROR;
|
|
DWORD dwDebugFlags;
|
|
|
|
//
|
|
// Setup the version string.
|
|
//
|
|
|
|
g_FtpVersionString = "Version 3.0";
|
|
|
|
//
|
|
// Create global locks.
|
|
//
|
|
|
|
InitializeCriticalSection( &g_GlobalLock );
|
|
InitializeCriticalSection( &g_StatisticsLock );
|
|
|
|
#ifdef KEEP_COMMAND_STATS
|
|
|
|
InitializeCriticalSection( &g_CommandStatisticsLock );
|
|
|
|
#endif // KEEP_COMMAND_STATS
|
|
|
|
|
|
//
|
|
// Create an FTP server config object and load values from registry.
|
|
//
|
|
|
|
g_pFtpServerConfig = new FTP_SERVER_CONFIG();
|
|
|
|
if ( g_pFtpServerConfig == NULL) {
|
|
|
|
SetLastError( ERROR_NOT_ENOUGH_MEMORY);
|
|
return ( ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
|
|
//
|
|
// Connect to the registry.
|
|
//
|
|
|
|
err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
FTPD_PARAMETERS_KEY,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&g_hkeyParams );
|
|
|
|
if( err != NO_ERROR )
|
|
{
|
|
TCP_PRINT(( DBG_CONTEXT,
|
|
"cannot open registry key %s, error %lu\n",
|
|
FTPD_PARAMETERS_KEY,
|
|
err ));
|
|
|
|
//
|
|
// Load Default values
|
|
//
|
|
err = NO_ERROR;
|
|
}
|
|
|
|
|
|
# if DBG
|
|
|
|
dwDebugFlags = ReadRegistryDword( g_hkeyParams,
|
|
FTPD_DEBUG_FLAGS,
|
|
DEFAULT_DEBUG_FLAGS );
|
|
SET_DEBUG_FLAGS( dwDebugFlags);
|
|
|
|
# endif // DBG
|
|
|
|
|
|
err = g_pFtpServerConfig->InitFromRegistry( g_hkeyParams, FC_FTP_ALL);
|
|
|
|
if ( err != NO_ERROR ) {
|
|
|
|
//
|
|
// Initializing configuration parameters from registry failed.
|
|
//
|
|
|
|
DBGPRINTF( ( DBG_CONTEXT,
|
|
"Initialize Config From Registry for FTP server failed.",
|
|
" Error = %lu\n",
|
|
err));
|
|
|
|
} else {
|
|
|
|
TCP_ASSERT( g_pFtpServerConfig->IsValid());
|
|
|
|
//
|
|
// Clear server statistics. This must be performed
|
|
// *after* the global lock is created.
|
|
//
|
|
|
|
ClearStatistics();
|
|
}
|
|
|
|
g_dwRfcDataPort = CONN_PORT_TO_DATA_PORT( g_pTsvcInfo->QueryPort());
|
|
|
|
|
|
return ( err);
|
|
|
|
} // InitializeGlobals()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: TerminateGlobals
|
|
|
|
SYNOPSIS: Terminate global shared variables.
|
|
|
|
NOTES: This routine may only be called by a single thread
|
|
of execution; it is not necessarily multi-thread safe.
|
|
|
|
Also, this routine is called after the event logging
|
|
routines have been terminated. Therefore, event
|
|
logging is not available.
|
|
|
|
HISTORY:
|
|
KeithMo 07-Mar-1993 Created.
|
|
|
|
********************************************************************/
|
|
VOID
|
|
TerminateGlobals(
|
|
VOID
|
|
)
|
|
{
|
|
|
|
if ( g_pFtpServerConfig != NULL) {
|
|
|
|
delete ( g_pFtpServerConfig);
|
|
g_pFtpServerConfig = NULL;
|
|
}
|
|
|
|
if ( g_hkeyParams != NULL) {
|
|
|
|
RegCloseKey( g_hkeyParams);
|
|
g_hkeyParams = NULL;
|
|
}
|
|
|
|
} // TerminateGlobals
|
|
|
|
|
|
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: ClearStatistics
|
|
|
|
SYNOPSIS: Clears server statistics.
|
|
|
|
HISTORY:
|
|
KeithMo 02-Jun-1993 Created.
|
|
|
|
********************************************************************/
|
|
VOID
|
|
ClearStatistics(
|
|
VOID
|
|
)
|
|
{
|
|
LockStatistics();
|
|
|
|
//
|
|
// Clear everything *except* CurrentAnonymousUsers and
|
|
// CurrentNonAnonymousUsers, and CurrentConnections since
|
|
// these reflect the current state of connected users
|
|
// and are not "normal" counters.
|
|
//
|
|
|
|
g_FtpStatistics.TotalBytesSent.QuadPart = 0;
|
|
g_FtpStatistics.TotalBytesReceived.QuadPart = 0;
|
|
g_FtpStatistics.TotalFilesSent = 0;
|
|
g_FtpStatistics.TotalFilesReceived = 0;
|
|
g_FtpStatistics.TotalAnonymousUsers = 0;
|
|
g_FtpStatistics.TotalNonAnonymousUsers = 0;
|
|
g_FtpStatistics.MaxAnonymousUsers = 0;
|
|
g_FtpStatistics.MaxNonAnonymousUsers = 0;
|
|
g_FtpStatistics.MaxConnections = 0;
|
|
g_FtpStatistics.ConnectionAttempts = 0;
|
|
g_FtpStatistics.LogonAttempts = 0;
|
|
#ifndef CHICAGO
|
|
g_FtpStatistics.TimeOfLastClear = GetCurrentTimeInSeconds();
|
|
#else
|
|
g_FtpStatistics.TimeOfLastClear = 0; //!!!
|
|
#endif
|
|
UnlockStatistics();
|
|
|
|
} // ClearStatistics
|
|
|
|
|
|
|
|
BOOL
|
|
WriteParamsToRegistry(
|
|
IN HKEY hkey,
|
|
LPFTP_CONFIG_INFO pConfig
|
|
)
|
|
/*++
|
|
This function writes parameters to the registry
|
|
|
|
Arguments:
|
|
hkey HKEY for registry entry of parameters of FTP server.
|
|
pConfig pointer to configuration information.
|
|
|
|
Returns:
|
|
TRUE on success and FALSE if there is any failure.
|
|
--*/
|
|
{
|
|
DWORD err = NO_ERROR;
|
|
BOOL fRet = TRUE;
|
|
|
|
if( hkey == NULL )
|
|
{
|
|
err = ERROR_INVALID_HANDLE;
|
|
SetLastError( err);
|
|
TCP_PRINT(( DBG_CONTEXT,
|
|
"Invalid Registry key given. error %lu\n",
|
|
err ));
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Write the registry data.
|
|
//
|
|
|
|
if( !err && IsFieldSet( pConfig->FieldControl, FC_FTP_ALLOW_ANONYMOUS ) )
|
|
{
|
|
err = WriteRegistryDword( hkey,
|
|
FTPD_ALLOW_ANONYMOUS,
|
|
pConfig->fAllowAnonymous );
|
|
}
|
|
|
|
if( !err && IsFieldSet( pConfig->FieldControl, FC_FTP_ALLOW_GUEST_ACCESS ) )
|
|
{
|
|
err = WriteRegistryDword( hkey,
|
|
FTPD_ALLOW_GUEST_ACCESS,
|
|
pConfig->fAllowGuestAccess );
|
|
}
|
|
|
|
if( !err && IsFieldSet( pConfig->FieldControl, FC_FTP_ANNOTATE_DIRECTORIES ) )
|
|
{
|
|
err = WriteRegistryDword( hkey,
|
|
FTPD_ANNOTATE_DIRS,
|
|
pConfig->fAnnotateDirectories );
|
|
}
|
|
|
|
if( !err && IsFieldSet( pConfig->FieldControl, FC_FTP_ANONYMOUS_ONLY ) )
|
|
{
|
|
err = WriteRegistryDword( hkey,
|
|
FTPD_ANONYMOUS_ONLY,
|
|
pConfig->fAnonymousOnly );
|
|
}
|
|
|
|
if( !err && IsFieldSet( pConfig->FieldControl, FC_FTP_LISTEN_BACKLOG ) )
|
|
{
|
|
err = WriteRegistryDword( hkey,
|
|
FTPD_LISTEN_BACKLOG,
|
|
pConfig->dwListenBacklog );
|
|
}
|
|
|
|
if( !err && IsFieldSet( pConfig->FieldControl, FC_FTP_LOWERCASE_FILES ) )
|
|
{
|
|
err = WriteRegistryDword( hkey,
|
|
FTPD_LOWERCASE_FILES,
|
|
pConfig->fLowercaseFiles );
|
|
}
|
|
|
|
if( !err && IsFieldSet( pConfig->FieldControl, FC_FTP_MSDOS_DIR_OUTPUT ) )
|
|
{
|
|
err = WriteRegistryDword( hkey,
|
|
FTPD_MSDOS_DIR_OUTPUT,
|
|
pConfig->fMsdosDirOutput );
|
|
}
|
|
|
|
|
|
if( !err && IsFieldSet( pConfig->FieldControl, FC_FTP_EXIT_MESSAGE ) )
|
|
{
|
|
err = RegSetValueExW( hkey,
|
|
FTPD_EXIT_MESSAGE_W,
|
|
0,
|
|
REG_SZ,
|
|
(BYTE *)pConfig->lpszExitMessage,
|
|
( wcslen( pConfig->lpszExitMessage ) + 1 ) *
|
|
sizeof(WCHAR) );
|
|
}
|
|
|
|
if( !err && IsFieldSet( pConfig->FieldControl, FC_FTP_GREETING_MESSAGE ) )
|
|
{
|
|
|
|
LPWSTR pszzGreetingMessage = NULL;
|
|
DWORD cchLen = 0;
|
|
|
|
if (GenDoubleNullStringFromMultiLine( pConfig->lpszGreetingMessage,
|
|
&pszzGreetingMessage,
|
|
&cchLen)
|
|
) {
|
|
|
|
DBG_ASSERT( pszzGreetingMessage != NULL);
|
|
|
|
err = RegSetValueExW( hkey,
|
|
FTPD_GREETING_MESSAGE_W,
|
|
0,
|
|
REG_MULTI_SZ,
|
|
(BYTE *) pszzGreetingMessage,
|
|
cchLen * sizeof(WCHAR));
|
|
|
|
TCP_FREE( pszzGreetingMessage);
|
|
} else {
|
|
|
|
err = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
|
|
|
|
if( !err && IsFieldSet( pConfig->FieldControl, FC_FTP_MAX_CLIENTS_MESSAGE ) )
|
|
{
|
|
err = RegSetValueExW( hkey,
|
|
FTPD_MAX_CLIENTS_MSG_W,
|
|
0,
|
|
REG_SZ,
|
|
(BYTE *)pConfig->lpszMaxClientsMessage,
|
|
( wcslen( pConfig->lpszMaxClientsMessage ) + 1 ) *
|
|
sizeof(WCHAR) );
|
|
}
|
|
|
|
if( err )
|
|
{
|
|
SetLastError( err );
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
} // WriteParamsToRegistry
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
// Private functions.
|
|
//
|
|
|
|
|
|
BOOL
|
|
GenDoubleNullStringFromMultiLine( IN LPCWSTR lpsz,
|
|
IN OUT LPWSTR * ppszz,
|
|
IN OUT LPDWORD pcchLen)
|
|
{
|
|
DWORD cchLen;
|
|
DWORD nLines;
|
|
LPWSTR pszNext;
|
|
LPCWSTR pszSrc;
|
|
|
|
DBG_ASSERT( lpsz != NULL && ppszz != NULL && pcchLen != NULL);
|
|
|
|
// Initialize
|
|
*ppszz = NULL;
|
|
*pcchLen = 0;
|
|
|
|
//
|
|
// 1. Find the length of the the complete message including new lines
|
|
// For each new line we may potentially need an extra blank char
|
|
// So allocate space = nLines + length + 2 terminating null chars.
|
|
//
|
|
|
|
cchLen = lstrlenW( lpsz);
|
|
|
|
for ( pszSrc = lpsz, nLines = 0; *pszSrc != L'\0'; pszSrc++) {
|
|
|
|
if ( *pszSrc == L'\n') { nLines++; }
|
|
} // for
|
|
|
|
|
|
// Allocate sufficient space for the string.
|
|
*ppszz = (LPWSTR ) TCP_ALLOC( (cchLen + nLines + 3) * sizeof(WCHAR));
|
|
if ( *ppszz == NULL) {
|
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return (FALSE);
|
|
}
|
|
|
|
|
|
//
|
|
// walk down the local copy and convert all the line feed characters to
|
|
// be null char
|
|
//
|
|
|
|
//
|
|
// Since the MULTI_SZ string cannot contain empty strings
|
|
// we convert empty lines (ones with just \n into " \0"
|
|
// i.e. with a blank character.
|
|
//
|
|
|
|
pszSrc = lpsz;
|
|
LPWSTR pszDst = *ppszz;
|
|
|
|
if ( *pszSrc == L'\n') {
|
|
|
|
// first line is a linefeed. insert a blank and proceed to next line.
|
|
*pszDst = L' ';
|
|
*(pszDst + 1) = L'\0';
|
|
|
|
// move forward
|
|
pszDst += 2;
|
|
pszSrc++;
|
|
}
|
|
|
|
for( ; *pszSrc != L'\0'; pszSrc++, pszDst++) {
|
|
|
|
if ( *pszSrc == L'\n') {
|
|
|
|
// we are at boundary of new line.
|
|
|
|
if ( pszSrc > lpsz && *(pszSrc - 1) == L'\n') {
|
|
|
|
// we detected an empty line. Store an additional blank.
|
|
|
|
*pszDst++ = L' ';
|
|
}
|
|
|
|
*pszDst = L'\0'; // put null char in place of line feed.
|
|
|
|
} else {
|
|
|
|
*pszDst = *pszSrc;
|
|
}
|
|
} // for
|
|
|
|
*pszDst++ = L'\0'; // terminate with 1st null chars.
|
|
*pszDst++ = L'\0'; // terminate with 2nd null chars.
|
|
|
|
*pcchLen = (pszDst - *ppszz);
|
|
|
|
DBG_ASSERT( *pcchLen <= cchLen + nLines + 3);
|
|
|
|
return ( TRUE);
|
|
} // GenDoubleNullStringFromMultiline()
|
|
|
|
|
|
|
|
|
|
# if DBG
|
|
VOID
|
|
PrintConfiguration( VOID)
|
|
{
|
|
|
|
IF_DEBUG( CONFIG )
|
|
{
|
|
TCP_PRINT(( DBG_CONTEXT,
|
|
"Configuration:\n" ));
|
|
|
|
READ_LOCK_TSVC();
|
|
|
|
TCP_PRINT(( DBG_CONTEXT,
|
|
" AnonymousUser = %s\n",
|
|
g_pTsvcInfo->QueryAnonUserName() ));
|
|
|
|
UNLOCK_TSVC();
|
|
|
|
TCP_PRINT(( DBG_CONTEXT,
|
|
" LogAnonymous = %s\n",
|
|
DisplayBool( g_pTsvcInfo->QueryLogAnonymous() ) ));
|
|
|
|
TCP_PRINT(( DBG_CONTEXT,
|
|
" LogNonAnonymous = %s\n",
|
|
DisplayBool( g_pTsvcInfo->QueryLogNonAnonymous() ) ));
|
|
|
|
TCP_PRINT(( DBG_CONTEXT,
|
|
" MaxConnections = %lu\n",
|
|
g_pTsvcInfo->QueryMaxConnections() ));
|
|
|
|
TCP_PRINT(( DBG_CONTEXT,
|
|
" ConnectionTimeout = %lu\n",
|
|
g_pTsvcInfo->QueryConnectionTimeout() ));
|
|
|
|
|
|
TCP_PRINT(( DBG_CONTEXT,
|
|
" %s = %08lX\n",
|
|
FTPD_DEBUG_FLAGS,
|
|
GET_DEBUG_FLAGS()));
|
|
|
|
READ_LOCK_TSVC();
|
|
|
|
TCP_PRINT(( DBG_CONTEXT,
|
|
" LogFileDirectory = %s\n",
|
|
g_pTsvcInfo->QueryLogFileDirectory() ));
|
|
|
|
UNLOCK_TSVC();
|
|
|
|
TCP_PRINT(( DBG_CONTEXT,
|
|
" LogFileAccess = %lu\n",
|
|
g_pTsvcInfo->QueryLogFileType() ));
|
|
|
|
if ( g_pFtpServerConfig != NULL) {
|
|
g_pFtpServerConfig->Print();
|
|
}
|
|
}
|
|
|
|
|
|
return;
|
|
} // PrintConfiguration()
|
|
|
|
|
|
|
|
# endif // DBG
|
|
|
|
/************************ End Of File ************************/
|