|
|
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
rpcex.cxx
Abstract:
This module defines K2 rpc support.
Author:
Johnson Apacible (JohnsonA) June-19-1996
--*/
#include "ftpdp.hxx"
#include "time.h"
#include "timer.h"
# define ASSUMED_AVERAGE_USER_NAME_LEN ( 40)
# define CONN_LEEWAY ( 3)
//
// Private functions.
//
BOOL GenDoubleNullStringFromMultiLine( IN LPCWSTR lpsz, IN OUT LPWSTR * ppszz, IN OUT LPDWORD pcchLen) { DWORD cchLen; DWORD nLines; 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 = DIFF(pszDst - *ppszz);
DBG_ASSERT( *pcchLen <= cchLen + nLines + 3);
return ( TRUE); } // GenDoubleNullStringFromMultiline()
BOOL FTP_SERVER_INSTANCE::WriteParamsToRegistry( 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;
HKEY hkey = NULL;
err = RegOpenKeyEx( HKEY_LOCAL_MACHINE, QueryRegParamKey(), 0, KEY_WRITE, &hkey );
if( hkey == NULL ) { err = ERROR_INVALID_HANDLE; SetLastError( err); DBGPRINTF(( 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_SHOW_4_DIGIT_YEAR ) ) { err = WriteRegistryDword( hkey, FTPD_SHOW_4_DIGIT_YEAR, pConfig->fFourDigitYear ); }
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_BANNER_MESSAGE ) ) {
LPWSTR pszzBannerMessage = NULL; DWORD cchLen = 0;
if (GenDoubleNullStringFromMultiLine( pConfig->lpszBannerMessage, &pszzBannerMessage, &cchLen) ) {
DBG_ASSERT( pszzBannerMessage != NULL);
err = RegSetValueExW( hkey, FTPD_BANNER_MESSAGE_W, 0, REG_MULTI_SZ, (BYTE *) pszzBannerMessage, cchLen * sizeof(WCHAR));
TCP_FREE( pszzBannerMessage); } 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) ); }
RegCloseKey( hkey);
if( err ) { SetLastError( err ); return FALSE; }
return TRUE;
} // WriteParamsToRegistry
DWORD FTP_IIS_SERVICE::GetServiceConfigInfoSize( IN DWORD dwLevel ) { switch (dwLevel) { case 1: return sizeof(FTP_CONFIG_INFO); }
return 0;
} // FTP_IIS_SERVICE::GetServerConfigInfoSize
BOOL FTP_SERVER_INSTANCE::SetServiceConfig( IN PCHAR pBuffer ) /*++
Description
Sets the common service admin information for the servers specified in dwServerMask.
Arguments:
pConfig - Admin information to set
Note:
--*/ { LPFTP_CONFIG_INFO pConfig = (LPFTP_CONFIG_INFO)pBuffer; DWORD err = NO_ERROR;
//
// If success, then Write the new info to the registry, then read it back.
//
if( WriteParamsToRegistry( pConfig )) {
err = InitFromRegistry( pConfig->FieldControl); } else {
err = GetLastError(); }
IF_DEBUG( RPC ) { DBGPRINTF(( DBG_CONTEXT, "FtpSetServiceConfig returns with %d %lu\n", err )); }
return(err == NO_ERROR);
} // FTP_SERVER_INSTANCE::SetServiceConfig
BOOL FTP_SERVER_INSTANCE::GetServiceConfig( IN PCHAR pBuffer, IN DWORD dwLevel ) /*++
Description
Retrieves the admin information
Arguments:
pBuffer - Buffer to fill up. dwLevel - info level of information to return.
Note:
--*/ {
LPFTP_CONFIG_INFO pConfig = (LPFTP_CONFIG_INFO)pBuffer; DWORD err = NO_ERROR;
ZeroMemory( pConfig, sizeof(*pConfig) );
//
// Obtain and Return the admin information.
//
err = GetConfigInformation( pConfig);
IF_DEBUG( RPC) {
DBGPRINTF(( DBG_CONTEXT, "FtprGetAdminInformation() returns Error=%u\n", err)); }
return (err == NO_ERROR);
} // FTP_SERVER_INSTANCE::GetServiceConfig
BOOL FTP_SERVER_INSTANCE::EnumerateUsers( OUT PCHAR * pBuffer, OUT PDWORD nRead ) /*++
Description
Enumerates the connected users.
Arguments:
pBuffer - Buffer to fill up. nRead - number of entries filled
--*/ { DWORD err; DWORD cbBuffer; LPIIS_USER_INFO_1 pInfo;
IF_DEBUG( RPC ) { DBGPRINTF(( DBG_CONTEXT,"Entering FtpEnumerateUsers\n")); }
//
// Determine the necessary buffer size.
//
cbBuffer = (GetCurrentConnectionsCount() + CONN_LEEWAY) * sizeof( IIS_USER_INFO_1 );
*nRead = 0;
pInfo = (LPIIS_USER_INFO_1)MIDL_user_allocate( cbBuffer);
if (pInfo == NULL) {
err = ERROR_NOT_ENOUGH_MEMORY; } else {
//
// Make a first attempt at enumerating the user info
//
err = NO_ERROR; if ( !::EnumerateUsers( (PCHAR)pInfo, &cbBuffer, nRead, this )) {
//
// Free up old buffer and allocate big one now.
// We will try once more to get the data again
// with a larger buffer.
//
if ( cbBuffer > 0) {
MIDL_user_free( pInfo ); pInfo = (LPIIS_USER_INFO_1)MIDL_user_allocate(cbBuffer);
if( pInfo == NULL ) {
err = ERROR_NOT_ENOUGH_MEMORY; } else {
//
// Since we do not lock the active connections list
// it is possible some one came in now and hence the
// buffer is insufficient to hold all people.
// Ignore this case, as we are never
// going to be accurate
//
::EnumerateUsers( (PCHAR)pInfo, &cbBuffer, nRead, this ); if ( *nRead == 0 ) { MIDL_user_free(pInfo); pInfo = NULL; } }
} // cbBuffer > 0
} // if unsuccessful at first attempt
}
if( err != NO_ERROR ) {
IF_DEBUG( RPC ) { DBGPRINTF(( DBG_CONTEXT, "I_FtprEnumerateUsers failed. Error = %lu\n", err )); } SetLastError(err); return(FALSE); }
*pBuffer = (PCHAR)pInfo;
IF_DEBUG( RPC ) { DBGPRINTF(( DBG_CONTEXT, "FtpEnumerateUsers returns %d entries, buffer [%x]\n", *nRead, *pBuffer )); } return TRUE;
} // EnumerateUsers
BOOL FTP_SERVER_INSTANCE::DisconnectUser( IN DWORD dwIdUser ) /*++
Description
Disconnect the user
Arguments:
dwIdUser - Identifies the user to disconnect. If 0, then disconnect ALL users.
--*/ { IF_DEBUG( RPC ) { DBGPRINTF(( DBG_CONTEXT, "Entering FtpDisconnectUsers with id[%d]\n", dwIdUser)); }
if ( !::DisconnectUser( dwIdUser, this ) ) {
IF_DEBUG( RPC ) { DBGPRINTF(( DBG_CONTEXT, "DisconnectUser failed with %d\n", GetLastError())); } SetLastError(NERR_UserNotFound); return(FALSE); }
return(TRUE); } // DisconnectUser
BOOL FTP_SERVER_INSTANCE::GetStatistics( IN DWORD dwLevel, OUT PCHAR* pBuffer ) /*++
Description
Disconnect Queries the server statistics
Arguments:
dwLevel - Info level. Currently only level 0 is supported.
pBuffer - Will receive a pointer to the statistics structure.
--*/ { APIERR err = NO_ERROR;
IF_DEBUG( RPC ) { DBGPRINTF(( DBG_CONTEXT, "FtpQueryStatistics2, level %lu\n", dwLevel )); }
//
// Return the proper statistics based on the infolevel.
//
switch( dwLevel ) { case 0 : {
LPFTP_STATISTICS_0 pstats0;
pstats0 = (LPFTP_STATISTICS_0) MIDL_user_allocate(sizeof(*pstats0));
if( pstats0 == NULL ) {
err = ERROR_NOT_ENOUGH_MEMORY; } else { ATQ_STATISTICS atqStat;
ZeroMemory( pstats0, sizeof( *pstats0 ) );
QueryStatsObj()->CopyToStatsBuffer( pstats0 );
//
// Get instance's bandwidth throttling statistics
//
if ( QueryBandwidthInfo() ) { if ( AtqBandwidthGetInfo( QueryBandwidthInfo(), ATQ_BW_STATISTICS, (ULONG_PTR *) &atqStat ) ) { pstats0->TotalBlockedRequests = atqStat.cBlockedRequests; pstats0->TotalRejectedRequests = atqStat.cRejectedRequests; pstats0->TotalAllowedRequests = atqStat.cAllowedRequests; pstats0->CurrentBlockedRequests = atqStat.cCurrentBlockedRequests; pstats0->MeasuredBandwidth = atqStat.MeasuredBandwidth; } }
pstats0->TimeOfLastClear = GetCurrentTimeInSeconds() - pstats0->TimeOfLastClear;
//
// Copy Global statistics counter values
//
pstats0->ConnectionAttempts = g_pFTPStats->QueryStatsObj()->ConnectionAttempts;
*pBuffer = (PCHAR)pstats0; }
}
break;
default : err = ERROR_INVALID_LEVEL; break; }
IF_DEBUG( RPC ) { DBGPRINTF(( DBG_CONTEXT, "FtpQueryStatistics2 returns Error = %lu\n", err )); }
SetLastError(err); return(err == NO_ERROR);
} // QueryStatistics
BOOL FTP_SERVER_INSTANCE::ClearStatistics( VOID ) /*++
Description
Clears the server statistics
Arguments:
None.
--*/ {
IF_DEBUG( RPC ) { DBGPRINTF(( DBG_CONTEXT, "Entering FtpClearStatistics2\n")); }
QueryStatsObj()->ClearStatistics(); return TRUE;
} // ClearStatistics
|