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.
 
 
 
 
 
 

866 lines
24 KiB

/**********************************************************************/
/** Microsoft Windows NT **/
/** Copyright(c) Microsoft Corp., 1993 **/
/**********************************************************************/
/*
globals.c
This module contains global variable definitions shared by the
various FTPD Service components.
FILE HISTORY:
KeithMo 07-Mar-1993 Created.
*/
#include "ftpdp.h"
#pragma hdrstop
BEGIN_EXTERN_C
#include "ntlsa.h"
END_EXTERN_C
//
// Private constants.
//
#define DEFAULT_ALLOW_ANONYMOUS TRUE
#define DEFAULT_ALLOW_GUEST_ACCESS TRUE
#define DEFAULT_ANONYMOUS_ONLY FALSE
#define DEFAULT_LOG_ANONYMOUS FALSE
#define DEFAULT_LOG_NONANONYMOUS FALSE
#define DEFAULT_ANONYMOUS_USER_NAME "Guest"
#define DEFAULT_DEBUG_FLAGS 0
#define DEFAULT_HOME_DIRECTORY "C:\\"
#define DEFAULT_MAX_CONNECTIONS 20
#define DEFAULT_READ_ACCESS_MASK 0
#define DEFAULT_WRITE_ACCESS_MASK 0
#define DEFAULT_CONNECTION_TIMEOUT 600
#define DEFAULT_MSDOS_DIR_OUTPUT TRUE
#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_ANNOTATE_DIRS FALSE
#define DEFAULT_LOWERCASE_FILES FALSE
#define DEFAULT_LOG_FILE_ACCESS FTPD_LOG_DISABLED
#define DEFAULT_LOG_FILE_DIRECTORY "%SystemRoot%\\System32"
#define DEFAULT_LISTEN_BACKLOG 5
#define DEFAULT_ENABLE_LICENSING FALSE
#define DEFAULT_DEFAULT_LOGON_DOMAIN NULL // NULL == use primary domain
#define DEFAULT_ENABLE_PORT_ATTACK FALSE
//
// Service related data.
//
SERVICE_STATUS svcStatus; // Current service status.
HANDLE hShutdownEvent; // Shutdown event.
BOOL fShutdownInProgress; // Shutdown in progress if !0.
//
// Security related data.
//
BOOL fAllowAnonymous; // Allow anonymous logon if !0.
BOOL fAllowGuestAccess; // Allow guest logon if !0.
BOOL fAnonymousOnly; // Allow only anonymous if !0.
BOOL fLogAnonymous; // Log anonymous logons if !0.
BOOL fLogNonAnonymous; // Log !anonymous logons if !0.
BOOL fEnableLicensing; // Enable user licensing if !0.
BOOL fEnablePortAttack; // Enable PORT attack if !0.
CHAR * pszAnonymousUser; // Anonymous user name.
CHAR * pszHomeDir; // Home directory.
CHAR szDefaultDomain[DNLEN+1]; // Default domain name.
DWORD maskReadAccess; // Read access mask.
DWORD maskWriteAccess; // Write access mask.
HANDLE hAnonymousToken; // Cached anonymous user token.
//
// Socket related data.
//
SOCKET sConnect = INVALID_SOCKET; // Main connection socket.
DWORD nConnectionTimeout; // Connection timeout (seconds).
PORT portFtpConnect; // FTP well known connect port.
PORT portFtpData; // FTP well known data port.
UINT cbReceiveBuffer; // Socket receive buffer size.
UINT cbSendBuffer; // Socket send buffer size.
INT nListenBacklog; // listen() backlog.
//
// User database related data.
//
DWORD tlsUserData = INVALID_TLS; // Tls index for per-user data.
DWORD cMaxConnectedUsers; // Maximum allowed connections.
DWORD cConnectedUsers; // Current connections.
CRITICAL_SECTION csUserLock; // User database lock.
//
// Miscellaneous data.
//
CHAR * pszHostName; // Name of local host.
BOOL fMsdosDirOutput; // Send MSDOS-like dir if !0.
BOOL fAnnotateDirs; // Annotate directories if !0.
BOOL fLowercaseFiles; // Map filenames to lowercase.
CHAR * pszGreetingMessage; // Greeting message to client.
CHAR * pszExitMessage; // Exit message to client.
CHAR * pszMaxClientsMessage; // Max clients reached msg.
HKEY hkeyFtpd; // Handle to registry data.
DWORD nLogFileAccess; // Log file access mode.
CHAR * pszLogFileDirectory; // Log file target directory.
FILE * fileLog; // File access log file.
SYSTEMTIME stPrevious; // Date/time of prev log file.
LARGE_INTEGER AllocationGranularity; // Page allocation granularity.
PTCPSVCS_GLOBAL_DATA pTcpsvcsGlobalData; // Shared TCPSVCS.EXE data.
CRITICAL_SECTION csGlobalLock; // Global variable lock.
CHAR * pszFtpVersion;
#ifdef KEEP_COMMAND_STATS
extern CRITICAL_SECTION csCommandStats;
#endif // KEEP_COMMAND_STATS
//
// Statistics.
//
FTP_STATISTICS_0 FtpStats; // Statistics.
CRITICAL_SECTION csStatisticsLock; // Statistics lock.
#if DBG
//
// Debug data.
//
DWORD FtpdDebug; // Debug output control flags.
#endif // DBG
//
// Private prototypes.
//
APIERR
GetDefaultDomainName(
CHAR * pszDomainName,
DWORD cchDomainName
);
//
// 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.
********************************************************************/
APIERR
InitializeGlobals(
VOID
)
{
APIERR err;
SYSTEM_INFO SysInfo;
WORD wVersion;
INT verLength;
CHAR * pszTmpDefaultDomain;
CHAR szVersionString[80];
//
// Create the version string.
//
wVersion = LOWORD( GetVersion() );
verLength = wsprintf( szVersionString,
#if DBG
"Version %d.%02d DEBUG",
#else
"Version %d.%02d",
#endif
LOBYTE( wVersion ),
HIBYTE( wVersion ) ) + 1; // + 1 for terminating '\0'
pszFtpVersion = (CHAR *)FTPD_ALLOC( verLength );
if( pszFtpVersion == NULL )
{
FTPD_PRINT(( "cannot allocate version string\n" ));
return ERROR_NOT_ENOUGH_MEMORY;
}
strcpy( pszFtpVersion, szVersionString );
//
// Create shutdown event.
//
hShutdownEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
if( hShutdownEvent == NULL )
{
err = GetLastError();
FTPD_PRINT(( "cannot create shutdown event, error %lu\n",
err ));
return err;
}
//
// Create global locks.
//
InitializeCriticalSection( &csGlobalLock );
InitializeCriticalSection( &csStatisticsLock );
InitializeCriticalSection( &csUserLock );
#ifdef KEEP_COMMAND_STATS
InitializeCriticalSection( &csCommandStats );
#endif // KEEP_COMMAND_STATS
//
// Alloc a thread local storage index for the per-user data area.
//
tlsUserData = TlsAlloc();
if( tlsUserData == INVALID_TLS )
{
err = GetLastError();
FTPD_PRINT(( "cannot allocate thread local storage index, error %lu\n",
err ));
return err;
}
//
// Determine the system page allocation granularity.
//
GetSystemInfo( &SysInfo );
AllocationGranularity.HighPart = 0;
AllocationGranularity.LowPart = (ULONG)SysInfo.dwAllocationGranularity;
//
// Connect to the registry.
//
err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
FTPD_PARAMETERS_KEY,
0,
KEY_ALL_ACCESS,
&hkeyFtpd );
if( err != NO_ERROR )
{
FTPD_PRINT(( "cannot open registry key, error %lu\n",
err ));
err = NO_ERROR;
}
//
// Read registry data.
//
pszAnonymousUser = ReadRegistryString( FTPD_ANONYMOUS_USERNAME,
DEFAULT_ANONYMOUS_USER_NAME,
FALSE );
pszHomeDir = ReadRegistryString( FTPD_HOME_DIRECTORY,
DEFAULT_HOME_DIRECTORY,
TRUE );
pszExitMessage = ReadRegistryString( FTPD_EXIT_MESSAGE,
DEFAULT_EXIT_MESSAGE,
FALSE );
pszLogFileDirectory = ReadRegistryString( FTPD_LOG_FILE_DIRECTORY,
DEFAULT_LOG_FILE_DIRECTORY,
TRUE );
if( ( pszAnonymousUser == NULL ) ||
( pszHomeDir == NULL ) ||
( pszExitMessage == NULL ) ||
( pszLogFileDirectory == NULL ) )
{
err = GetLastError();
FTPD_PRINT(( "cannot read registry data, error %lu\n",
err ));
return err;
}
pszGreetingMessage = ReadRegistryString( FTPD_GREETING_MESSAGE,
DEFAULT_GREETING_MESSAGE,
FALSE );
pszMaxClientsMessage = ReadRegistryString( FTPD_MAX_CLIENTS_MSG,
DEFAULT_MAX_CLIENTS_MSG,
FALSE );
fAllowAnonymous = !!ReadRegistryDword( FTPD_ALLOW_ANONYMOUS,
DEFAULT_ALLOW_ANONYMOUS );
fAllowGuestAccess = !!ReadRegistryDword( FTPD_ALLOW_GUEST_ACCESS,
DEFAULT_ALLOW_GUEST_ACCESS );
fAnonymousOnly = !!ReadRegistryDword( FTPD_ANONYMOUS_ONLY,
DEFAULT_ANONYMOUS_ONLY );
fLogAnonymous = !!ReadRegistryDword( FTPD_LOG_ANONYMOUS,
DEFAULT_LOG_ANONYMOUS );
fLogNonAnonymous = !!ReadRegistryDword( FTPD_LOG_NONANONYMOUS,
DEFAULT_LOG_NONANONYMOUS );
fEnableLicensing = !!ReadRegistryDword( FTPD_ENABLE_LICENSING,
DEFAULT_ENABLE_LICENSING );
fEnablePortAttack = !!ReadRegistryDword( FTPD_ENABLE_PORT_ATTACK,
DEFAULT_ENABLE_PORT_ATTACK );
cMaxConnectedUsers = ReadRegistryDword( FTPD_MAX_CONNECTIONS,
DEFAULT_MAX_CONNECTIONS );
maskReadAccess = ReadRegistryDword( FTPD_READ_ACCESS_MASK,
DEFAULT_READ_ACCESS_MASK );
maskWriteAccess = ReadRegistryDword( FTPD_WRITE_ACCESS_MASK,
DEFAULT_WRITE_ACCESS_MASK );
nConnectionTimeout = ReadRegistryDword( FTPD_CONNECTION_TIMEOUT,
DEFAULT_CONNECTION_TIMEOUT );
fMsdosDirOutput = !!ReadRegistryDword( FTPD_MSDOS_DIR_OUTPUT,
DEFAULT_MSDOS_DIR_OUTPUT );
fAnnotateDirs = !!ReadRegistryDword( FTPD_ANNOTATE_DIRS,
DEFAULT_ANNOTATE_DIRS );
fLowercaseFiles = !!ReadRegistryDword( FTPD_LOWERCASE_FILES,
DEFAULT_LOWERCASE_FILES );
nLogFileAccess = ReadRegistryDword( FTPD_LOG_FILE_ACCESS,
DEFAULT_LOG_FILE_ACCESS );
if( nLogFileAccess > FTPD_LOG_DAILY )
{
nLogFileAccess = DEFAULT_LOG_FILE_ACCESS;
}
nListenBacklog = ReadRegistryDword( FTPD_LISTEN_BACKLOG,
DEFAULT_LISTEN_BACKLOG );
//
// Determine the default domain name.
//
pszTmpDefaultDomain = ReadRegistryString( FTPD_DEFAULT_LOGON_DOMAIN,
DEFAULT_DEFAULT_LOGON_DOMAIN,
FALSE );
if( ( pszTmpDefaultDomain != NULL ) &&
( strlen( pszTmpDefaultDomain ) >= sizeof(szDefaultDomain) ) )
{
FTPD_PRINT(( "default logon domain from registry (%s) too long...\n",
pszTmpDefaultDomain ));
FTPD_PRINT(( "...using local machine's primary logon domain instead\n" ));
FTPD_FREE( pszTmpDefaultDomain );
pszTmpDefaultDomain = NULL;
}
if( pszTmpDefaultDomain != NULL )
{
strcpy( szDefaultDomain, pszTmpDefaultDomain );
FTPD_FREE( pszTmpDefaultDomain );
pszTmpDefaultDomain = NULL;
}
else
{
err = GetDefaultDomainName( szDefaultDomain,
sizeof(szDefaultDomain) );
if( err != 0 )
{
FTPD_PRINT(( "cannot get default domain name, error %d\n",
err ));
return err;
}
}
//
// Open the log file.
//
fileLog = OpenLogFile();
if( fileLog != NULL )
{
time_t now;
time( &now );
fprintf( fileLog,
"************** FTP SERVER SERVICE STARTING %s",
asctime( localtime( &now ) ) );
fflush( fileLog );
}
#if DBG
FtpdDebug = ReadRegistryDword( FTPD_DEBUG_FLAGS,
DEFAULT_DEBUG_FLAGS );
IF_DEBUG( CONFIG )
{
FTPD_PRINT(( "Configuration:\n" ));
FTPD_PRINT(( " %s = %s\n",
FTPD_ANONYMOUS_USERNAME,
pszAnonymousUser ));
FTPD_PRINT(( " %s = %s\n",
FTPD_HOME_DIRECTORY,
pszHomeDir ));
FTPD_PRINT(( " %s = %s\n",
FTPD_ALLOW_ANONYMOUS,
DisplayBool( fAllowAnonymous ) ));
FTPD_PRINT(( " %s = %s\n",
FTPD_ALLOW_GUEST_ACCESS,
DisplayBool( fAllowGuestAccess ) ));
FTPD_PRINT(( " %s = %s\n",
FTPD_ANONYMOUS_ONLY,
DisplayBool( fAnonymousOnly ) ));
FTPD_PRINT(( " %s = %s\n",
FTPD_LOG_ANONYMOUS,
DisplayBool( fLogAnonymous ) ));
FTPD_PRINT(( " %s = %s\n",
FTPD_LOG_NONANONYMOUS,
DisplayBool( fLogNonAnonymous ) ));
FTPD_PRINT(( " %s = %s\n",
FTPD_ENABLE_LICENSING,
DisplayBool( fEnableLicensing ) ));
FTPD_PRINT(( " %s = %s\n",
FTPD_ENABLE_PORT_ATTACK,
DisplayBool( fEnablePortAttack ) ));
FTPD_PRINT(( " %s = %lu\n",
FTPD_MAX_CONNECTIONS,
cMaxConnectedUsers ));
FTPD_PRINT(( " %s = %08lX\n",
FTPD_READ_ACCESS_MASK,
maskReadAccess ));
FTPD_PRINT(( " %s = %08lX\n",
FTPD_WRITE_ACCESS_MASK,
maskWriteAccess ));
FTPD_PRINT(( " %s = %lu\n",
FTPD_CONNECTION_TIMEOUT,
nConnectionTimeout ));
FTPD_PRINT(( " %s = %s\n",
FTPD_MSDOS_DIR_OUTPUT,
DisplayBool( fMsdosDirOutput ) ));
FTPD_PRINT(( " %s = %s\n",
FTPD_ANNOTATE_DIRS,
DisplayBool( fAnnotateDirs ) ));
FTPD_PRINT(( " %s = %08lX\n",
FTPD_DEBUG_FLAGS,
FtpdDebug ));
FTPD_PRINT(( " %s = %s\n",
FTPD_LOG_FILE_DIRECTORY,
pszLogFileDirectory ));
FTPD_PRINT(( " %s = %lu\n",
FTPD_LOG_FILE_ACCESS,
nLogFileAccess ));
FTPD_PRINT(( " %s = %d\n",
FTPD_LISTEN_BACKLOG,
nListenBacklog ));
FTPD_PRINT(( " szDefaultDomain = %s\n",
szDefaultDomain ));
}
#endif // DBG
//
// Update access masks to reflect current drive configuration.
//
UpdateAccessMasks();
IF_DEBUG( CONFIG )
{
FTPD_PRINT(( "After adjusting access masks:\n" ));
FTPD_PRINT(( " %s = %08lX\n",
FTPD_READ_ACCESS_MASK,
maskReadAccess ));
FTPD_PRINT(( " %s = %08lX\n",
FTPD_WRITE_ACCESS_MASK,
maskWriteAccess ));
}
//
// Clear server statistics. This must be performed
// *after* the global lock is created.
//
ClearStatistics();
//
// Success!
//
return NO_ERROR;
} // 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
)
{
//
// Close the registry.
//
if( hkeyFtpd != NULL )
{
RegCloseKey( hkeyFtpd );
hkeyFtpd = NULL;
}
//
// Free the registry strings.
//
if( pszAnonymousUser != NULL )
{
FTPD_FREE( pszAnonymousUser );
pszAnonymousUser = NULL;
}
if( pszHomeDir != NULL )
{
FTPD_FREE( pszHomeDir );
pszHomeDir = NULL;
}
if( pszExitMessage != NULL )
{
FTPD_FREE( pszExitMessage );
pszExitMessage = NULL;
}
if( pszGreetingMessage != NULL )
{
FTPD_FREE( pszGreetingMessage );
pszGreetingMessage = NULL;
}
if( pszMaxClientsMessage != NULL )
{
FTPD_FREE( pszMaxClientsMessage );
pszMaxClientsMessage = NULL;
}
//
// Destroy the shutdown event.
//
if( hShutdownEvent != NULL )
{
CloseHandle( hShutdownEvent );
hShutdownEvent = NULL;
}
//
// Close the log file.
//
if( fileLog != NULL )
{
time_t now;
time( &now );
fprintf( fileLog,
"************** FTP SERVER SERVICE STOPPING %s",
asctime( localtime( &now ) ) );
fclose( fileLog );
fileLog = NULL;
}
//
// Free the version string.
//
if( pszFtpVersion != NULL )
{
FTPD_FREE( pszFtpVersion );
pszFtpVersion = NULL;
}
//
// Dump heap residue.
//
FTPD_DUMP_RESIDUE();
} // 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.
//
FtpStats.TotalBytesSent.QuadPart = 0;
FtpStats.TotalBytesReceived.QuadPart = 0;
FtpStats.TotalFilesSent = 0;
FtpStats.TotalFilesReceived = 0;
FtpStats.TotalAnonymousUsers = 0;
FtpStats.TotalNonAnonymousUsers = 0;
FtpStats.MaxAnonymousUsers = 0;
FtpStats.MaxNonAnonymousUsers = 0;
FtpStats.MaxConnections = 0;
FtpStats.ConnectionAttempts = 0;
FtpStats.LogonAttempts = 0;
FtpStats.TimeOfLastClear = GetFtpTime();
UnlockStatistics();
} // ClearStatistics
//
// Private functions.
//
/*******************************************************************
NAME: GetDefaultDomainName
SYNOPSIS: Fills in the given array with the name of the default
domain to use for logon validation.
ENTRY: pszDomainName - Pointer to a buffer that will receive
the default domain name.
cchDomainName - The size (in charactesr) of the domain
name buffer.
RETURNS: APIERR - 0 if successful, !0 if not.
HISTORY:
KeithMo 05-Dec-1994 Created.
********************************************************************/
APIERR
GetDefaultDomainName(
CHAR * pszDomainName,
DWORD cchDomainName
)
{
OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS NtStatus;
INT Result;
APIERR err = 0;
LSA_HANDLE LsaPolicyHandle = NULL;
PPOLICY_ACCOUNT_DOMAIN_INFO DomainInfo = NULL;
//
// Open a handle to the local machine's LSA policy object.
//
InitializeObjectAttributes( &ObjectAttributes, // object attributes
NULL, // name
0L, // attributes
NULL, // root directory
NULL ); // security descriptor
NtStatus = LsaOpenPolicy( NULL, // system name
&ObjectAttributes, // object attributes
POLICY_EXECUTE, // access mask
&LsaPolicyHandle ); // policy handle
if( !NT_SUCCESS( NtStatus ) )
{
FTPD_PRINT(( "cannot open lsa policy, error %08lX\n",
NtStatus ));
err = RtlNtStatusToDosError( NtStatus );
goto Cleanup;
}
//
// Query the domain information from the policy object.
//
NtStatus = LsaQueryInformationPolicy( LsaPolicyHandle,
PolicyAccountDomainInformation,
(PVOID *)&DomainInfo );
if( !NT_SUCCESS( NtStatus ) )
{
FTPD_PRINT(( "cannot query lsa policy info, error %08lX\n",
NtStatus ));
err = RtlNtStatusToDosError( NtStatus );
goto Cleanup;
}
//
// Convert the name from UNICODE to ANSI.
//
Result = WideCharToMultiByte( CP_ACP,
0, // flags
(LPCWSTR)DomainInfo->DomainName.Buffer,
DomainInfo->DomainName.Length / sizeof(WCHAR),
pszDomainName,
cchDomainName - 1, // save room for '\0'
NULL,
NULL );
if( Result <= 0 )
{
err = GetLastError();
FTPD_PRINT(( "cannot convert domain name to ANSI, error %d\n",
err ));
goto Cleanup;
}
//
// Ensure the ANSI string is zero terminated.
//
FTPD_ASSERT( (DWORD)Result < cchDomainName );
pszDomainName[Result] = '\0';
//
// Success!
//
FTPD_ASSERT( err == 0 );
IF_DEBUG( CONFIG )
{
FTPD_PRINT(( "GetDefaultDomainName: default domain = %s\n",
pszDomainName ));
}
Cleanup:
if( DomainInfo != NULL )
{
LsaFreeMemory( (PVOID)DomainInfo );
}
if( LsaPolicyHandle != NULL )
{
LsaClose( LsaPolicyHandle );
}
return err;
} // GetDefaultDomainName