|
|
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
globals.cxx
Abstract:
This module contains global variable definitions shared by the various SMTP Service components.
Author: KeithMo 07-Mar-1993 Created.
--*/
#define INCL_INETSRV_INCS
#include "smtpinc.h"
#include "smtpcli.hxx"
#include "smtpout.hxx"
#include "dropdir.hxx"
#include "mailmsg_i.c"
#include "mailmsgi_i.c"
#include "aqueue_i.c"
#include "aqstore.hxx"
#include <dnsapi.h>
//
// Version string for this server
//
#define MSSMTP_VERSION_STR_IIS "Microsoft-IIS/K2"
#define MSSMTP_VERSION_STR_W95 "Microsoft-PWS-95/K2"
#define MSSMTP_VERSION_STR_NTW "Microsoft-PWS/K2"
//
// Set to the largest of the three
//
#define MSSMTP_VERSION_STR_MAX MSSMTP_VERSION_STR_W95
//
// Creates the version string
//
#define MAKE_VERSION_STRING( _s ) ("Server: " ##_s "\r\n")
//
// MIME version we say we support
//
#define SMTP_MIME_VERSION_STR "MIME-version: 1.0"
#define SMTP_TEMP_DIR_NAME " "
//
// Server type string
//
CHAR g_szServerType[ sizeof(MSSMTP_VERSION_STR_MAX)]; DWORD g_cbServerType = 0; CHAR szServerVersion[sizeof(MAKE_VERSION_STRING(MSSMTP_VERSION_STR_MAX))]; DWORD cbServerVersionString = 0;
DWORD g_ProductType = 5; PLATFORM_TYPE g_SmtpPlatformType = PtNtServer;
//computer name
CHAR g_ComputerName[MAX_PATH + 1]; DWORD g_ComputerNameLength;
// number of procs on system for thread mgmt.
DWORD g_NumProcessors = 1;
CHAR g_VersionString[128]; CHAR g_Password[MAX_PATH + 1]; CHAR g_UserName[MAX_PATH + 1]; CHAR g_DomainName[MAX_PATH + 1];
static char g_BoundaryChars [] = "0123456789abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
//Max Objects
DWORD g_cMaxAddressObjects; DWORD g_cMaxPropertyBagObjects; DWORD g_cMaxMailObjects; DWORD g_cMaxEtrnObjects; DWORD g_cMaxRoutingThreads;
// externs for cmmprops.lib and blockmgr.lib to control debug code
DWORD g_fValidateSignatures = 0; DWORD g_fForceCrashOnError = 0; DWORD g_fFillPropertyPages = 0;
DWORD g_cMaxConnectionObjs = 2000; BOOL g_CalledSrand; DWORD g_dwIncMsgId;
// X5 189659 instrumentation
DWORD g_fCrashOnInvalidSMTPConn = 0;
//These buffers are associated with every incoming connection - so we
//will need to have atleast those any plus a few more for use in Dir pickup
//and large SSL buffers
DWORD g_cMaxDirBuffers = 2500; //This buffer is now used primarily as WRITEBUFFER for every connection
//We have decided to go with 32K buffer
//NK** : Make this metabse readable
DWORD g_cMaxDirChangeIoSize = SMTP_WRITE_BUFFER_SIZE;
//loopback address
DWORD g_LoopBackAddr;
unsigned char GlobalIpBuffer[10000]; CShareLockNH g_GlobalLock; SOCKET g_IpListSocket = INVALID_SOCKET; WSAOVERLAPPED WsaOverLapped;
HANDLE g_ShutdownHandle = NULL; HANDLE g_TcpNotifyHandle = NULL; HANDLE g_FreeLibThreadHandle = NULL; CTcpRegIpList g_TcpRegIpList;
//
// Notification object used to watch for changes in CAPI stores
//
STORE_CHANGE_NOTIFIER *g_pCAPIStoreChangeNotifier;
//
// Miscellaneous data.
//
LARGE_INTEGER AllocationGranularity; // Page allocation granularity.
HANDLE g_hSysAccToken = NULL; TCHAR * g_pszSmtpTempDirName; // Name of temporary directory.
DWORD g_PickupWait; DWORD g_FreeLibInterval = 1; //Interval in min to wait before calling CoFreeUnusedLib
DWORD g_UseMapiDriver = 0; LONG g_MaxFindThreads;
//
// Platform type
//
PLATFORM_TYPE SmtpPlatformType = PtNtServer; BOOL g_fIsWindows95 = FALSE;
//
// Statistics.
// used to write statistics counter values to when instance is unknown
//
LPSMTP_SERVER_STATISTICS g_pSmtpStats;
//
// SEO Handle
//
IUnknown *g_punkSEOHandle;
//
// Externals for SEO
//
extern HRESULT SEOGetServiceHandle(IUnknown **);
//
// Generate the string storage space
//
#if 0
# include "strconst.h"
# define CStrM( FriendlyName, ActualString) \
const char PSZ_ ## FriendlyName[] = ActualString;
ConstantStringsForThisModule()
# undef CStrM
#endif
DWORD SmtpDebug; extern "C" { BOOL g_IsShuttingDown = FALSE; }
DWORD g_SmtpInitializeStatus = 0; TIME_ZONE_INFORMATION tzInfo;
#define MAX_CONNECTION_OBJECTS 5000;
BOOL GetMachineIpAddresses(void); DWORD TcpRegNotifyThread( LPDWORD lpdw ); DWORD FreeLibThread( LPDWORD lpdw );
//
// eventlog object
//
CEventLogWrapper g_EventLog;
//
// Header Date time cache
//
//PCACHED_DATETIME_FORMATS g_pDateTimeCache = NULL;
static TCHAR szParamPath[] = TEXT("System\\CurrentControlSet\\Services\\SmtpSvc\\Parameters"); static WCHAR szParamPathW[] = L"System\\CurrentControlSet\\Services\\SmtpSvc\\Parameters"; static TCHAR szMaxAddrObjects[] = TEXT("MaxAddressObjects"); static WCHAR szMaxAddrObjectsW[] = L"MaxAddressObjects"; static TCHAR szMaxPropertyBagObjects[] = TEXT("MaxPropertyBagObjects"); static WCHAR szMaxPropertyBagObjectsW[] = L"MaxPropertyBagObjects"; static TCHAR szMaxMailObjects[] = TEXT("MaxMailObjects"); static WCHAR szMaxMailObjectsW[] = L"MaxMailObjects"; static TCHAR szMaxEtrnObjects[] = TEXT("MaxEtrnObjects"); static WCHAR szMaxEtrnObjectsW[] = L"MaxEtrnObjects"; static TCHAR szDirBuffers[] = TEXT("MaxDirectoryBuffers"); static WCHAR szDirBuffersW[] = L"MaxDirectoryBuffers"; static TCHAR szDirBuffersSize[] = TEXT("DirectoryBuffSize"); static WCHAR szDirBuffersSizeW[] = L"DirectoryBufferSize"; static TCHAR szDirPendingIos[] = TEXT("NumDirPendingIos"); static WCHAR szDirPendingIosW[] = L"NumDirPendingIos"; static TCHAR szRoutingThreads[] = TEXT("RoutingThreads"); static WCHAR szRoutingThreadsW[] = L"RoutingThreads"; static TCHAR szProductType[] = TEXT("ProductType"); static WCHAR szProductTypeW[] = L"ProductType"; static TCHAR szResolverSockets[] = TEXT("NumDnsResolverSockets"); static WCHAR szResolverSocketsW[] = L"NumDnsResolverSockets"; static TCHAR szDnsSocketTimeout[] = TEXT("msDnsSocketTimeout"); static WCHAR szDnsSocketTimeoutW[] = L"msDnsSocketTimeout"; static TCHAR szPickupWait[] = TEXT("PickupWait"); static WCHAR szPickupWaitW[] = L"PickupWait"; static TCHAR szMaxFindThreads[] = TEXT("MaxFindThreads"); static WCHAR szMaxFindThreadsW[] = L"MaxFindThreads"; static TCHAR szFreeLibInterval[] = TEXT("FreeLibInterval"); static WCHAR szFreeLibIntervalW[] = L"FreeLibInterval"; static TCHAR szUseMapiDrv[] = TEXT("UseMapiDriver"); static WCHAR szUseMapiDrvW[] = L"UseMapiDriver"; static TCHAR szDnsErrorsBeforeFailover[] = TEXT("DnsErrorsBeforeFailover"); static WCHAR szDnsErrorsBeforeFailoverW[] = L"DnsErrorsBeforeFailover"; static TCHAR szDnsConnectsInProbation[] = TEXT("DnsConnectsInProbation"); static WCHAR szDnsConnectsInProbationW[] = L"DnsConnectsInProbation"; //
// resolver globals
//
DWORD g_ResolverSockets = 10; DWORD g_DnsSocketTimeout = 60000; DWORD g_DnsErrorsBeforeFailover = 3; DWORD g_DnsConnectsInProbation = 2;
typedef struct tagVERTAG { LPSTR pszTag; } VERTAG, *PVERTAG, FAR *LPVERTAG;
VERTAG Tags[] = { // { "FileDescription" },
// { "OriginalFilename" },
// { "ProductName" },
{ "ProductVersion" }, // { "LegalCopyright" },
// { "LegalCopyright" },
};
#define NUM_TAGS (sizeof( Tags ) / sizeof( VERTAG ))
BOOL GetRegistryDwordParameter( LPCSTR pcszParameterName, DWORD *pdwValue ) { HKEY hKey = NULL; DWORD dwRes; DWORD dwType; DWORD dwLength; DWORD dwValue; BOOL fRes = FALSE;
// Open the registry key
dwRes = (DWORD)RegOpenKeyEx( HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\Exchange\\SmtpSvc"), 0, KEY_ALL_ACCESS, &hKey); if (dwRes == ERROR_SUCCESS) { // Adjust the buffer size for character type ...
dwLength = sizeof(DWORD); dwRes = (DWORD)RegQueryValueEx( hKey, pcszParameterName, NULL, &dwType, (LPBYTE)&dwValue, &dwLength); if ((dwRes == ERROR_SUCCESS) && dwType == REG_DWORD) { *pdwValue = dwValue; fRes = TRUE; }
_VERIFY(RegCloseKey(hKey) == NO_ERROR); }
return(fRes); }
//DWORD ConfigIMCService(void);
DWORD SetVersionStrings( LPSTR lpszFile, LPSTR lpszTitle, LPSTR lpstrOut, DWORD cbOut ) { static char sz[256], szFormat[256], sz2[256]; int i; UINT uBytes; LPVOID lpMem; DWORD dw = 0, dwSize; HANDLE hMem; LPVOID lpsz; LPDWORD lpLang; DWORD dwLang2; BOOL bRC, bFileFound = FALSE;
LPSTR lpstrOrig = lpstrOut ;
//CharUpper( lpszTitle );
if ( dwSize = GetFileVersionInfoSize( lpszFile, &dw ) ) { if ( hMem = GlobalAlloc( GMEM_MOVEABLE|GMEM_ZEROINIT, (UINT)dwSize ) ) { lpMem = GlobalLock(hMem); if (GetFileVersionInfo( lpszFile, 0, dwSize, lpMem ) && VerQueryValue( lpMem, "\\VarFileInfo\\Translation", (LPVOID FAR *)&lpLang, &uBytes ) ) { dwLang2 = MAKELONG( HIWORD(lpLang[0]), LOWORD(lpLang[0]) );
for( i=0; i<NUM_TAGS; i++ ) {
lpsz = 0 ; //
// need to do the reverse because most winnt files are wrong
//
wsprintf( sz, "\\StringFileInfo\\%08lx\\%s", lpLang[0], Tags[i].pszTag ); wsprintf( sz2, "\\StringFileInfo\\%08lx\\%s", dwLang2, Tags[i].pszTag ); bRC = VerQueryValue( lpMem, sz, &lpsz, &uBytes ) || VerQueryValue( lpMem, sz2, &lpsz, &uBytes ) ;
if( lpsz != 0 ) {
if( uBytes+1 < cbOut ) { uBytes = min( (UINT)lstrlen( (char*)lpsz ), uBytes ) ; CopyMemory( lpstrOut, lpsz, uBytes ) ; lpstrOut[uBytes++] = ' ' ; lpstrOut += uBytes ; cbOut -= uBytes ; } else { GlobalUnlock( hMem ); GlobalFree( hMem ); return (DWORD)(lpstrOut - lpstrOrig) ; } }
} // version info from fixed struct
bRC = VerQueryValue(lpMem, "\\", &lpsz, &uBytes );
#define lpvs ((VS_FIXEDFILEINFO FAR *)lpsz)
static char szVersion[] = "Version: %d.%d.%d.%d" ;
if ( (cbOut > (sizeof( szVersion )*2)) && lpsz ) {
CopyMemory( szFormat, szVersion, sizeof( szVersion ) ) ; //LoadString( hInst, IDS_VERSION, szFormat, sizeof(szFormat) );
DWORD cbPrint = wsprintf( lpstrOut, szFormat, HIWORD(lpvs->dwFileVersionMS), LOWORD(lpvs->dwFileVersionMS), HIWORD(lpvs->dwFileVersionLS), LOWORD(lpvs->dwFileVersionLS) ); lpstrOut += cbPrint ;
} bFileFound = TRUE; } else {
}
GlobalUnlock( hMem ); GlobalFree( hMem ); } else {
} } else {
} DWORD dw2 = GetLastError() ;
return (DWORD)(lpstrOut - lpstrOrig) ; }
BOOL InitServerVersionString( VOID ) { BOOL fRet = TRUE ; DWORD szSize; char szServerPath[MAX_PATH + 1]; char * szOffset;
CopyMemory(szServerPath, "c:\\", sizeof( "c:\\" ) ) ;
g_VersionString [0] = '\0';
HMODULE hModule = GetModuleHandle( "smtpsvc.dll" ) ; if( hModule != 0 ) {
if( !GetModuleFileName( hModule, szServerPath, sizeof( szServerPath ) ) ) { lstrcpy( szServerPath, "c:\\") ; } else { szSize = SetVersionStrings(szServerPath, "", g_VersionString, 128 ); szOffset = strstr(g_VersionString, "Version"); if(szOffset) { //Move interesting part of string (including the
//terminating NULL) to front of g_VersionString.
MoveMemory(g_VersionString, szOffset, szSize+1 - (szOffset - g_VersionString)); }
} }
return TRUE ; }
BOOL GetGlobalRegistrySettings(void) { BOOL fRet = TRUE; HKEY hkeySmtp = NULL; HKEY hkeySub = NULL; DWORD dwErr; DWORD dwDisp;
DWORD dwMaxFindThreads;
TraceFunctEnterEx((LPARAM)NULL, "GetGlobalRegistrySettings");
dwErr = RegCreateKeyEx(HKEY_LOCAL_MACHINE, szParamPath, NULL, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeySmtp, &dwDisp); if (dwErr != ERROR_SUCCESS) { SmtpLogEventEx(SMTP_EVENT_CANNOT_OPEN_SVC_REGKEY, (const char *)SMTP_PARAMETERS_KEY, dwErr); TraceFunctLeave(); SetLastError(dwErr); return FALSE; }
g_cMaxAddressObjects = ReadRegistryDword(hkeySmtp, szMaxAddrObjects, 100000); StateTrace((LPARAM)NULL, "g_cMaxAddressObjects = %u", g_cMaxAddressObjects);
//NK ** We atleast need as many buffers as many connections we accept
//so I have now tied it to that value
//g_cMaxDirBuffers = ReadRegistryDword(hkeySmtp, szDirBuffers, 5000);
//g_cMaxDirChangeIoSize = ReadRegistryDword(hkeySmtp, szDirBuffersSize, MAX_WRITE_FILE_BLOCK);
g_ResolverSockets = ReadRegistryDword(hkeySmtp, szResolverSockets, 10); g_DnsSocketTimeout = ReadRegistryDword(hkeySmtp, szDnsSocketTimeout, 60000); g_DnsErrorsBeforeFailover = ReadRegistryDword(hkeySmtp, szDnsErrorsBeforeFailover, 3); g_DnsConnectsInProbation = ReadRegistryDword(hkeySmtp, szDnsConnectsInProbation, 2);
g_PickupWait = ReadRegistryDword(hkeySmtp, szPickupWait, 200); // don't let them make this wait more than 5 secs. that is too much.
if (g_PickupWait > 5000) { g_PickupWait = 5000; }
//In seems like after the call to unload, the dlls get physically unloaded
//11 min after that. So I am setting the interval by default to 11.
g_FreeLibInterval = ReadRegistryDword(hkeySmtp,szFreeLibInterval, 11); // don't let them make this wait more than 60 min. that is too much.
if (g_FreeLibInterval > 60) { g_FreeLibInterval = 60; }
dwMaxFindThreads = ReadRegistryDword(hkeySmtp, szMaxFindThreads, 3); // don't want this to be bigger than the routing threads, but we want at least one.
if (dwMaxFindThreads > 3) { dwMaxFindThreads = 3; } else if (dwMaxFindThreads <= 0) { dwMaxFindThreads = 1; }
g_MaxFindThreads = dwMaxFindThreads;
RegCloseKey(hkeySmtp); TraceFunctLeaveEx((LPARAM)NULL); return fRet; }
void IpAddressListCallBack (DWORD dwError, DWORD cbTransferred, LPWSAOVERLAPPED LpOverlapped, DWORD dwFlags) { DWORD wsError = 0; DWORD bytesReturned = 0;
GetMachineIpAddresses();
wsError = WSAIoctl(g_IpListSocket, SIO_ADDRESS_LIST_CHANGE, NULL, 0, NULL, 0, &bytesReturned, &WsaOverLapped, IpAddressListCallBack);
}
BOOL GetMachineIpAddresses(void) { DWORD bytesReturned = 0; DWORD wsError = 0; BOOL fRet = FALSE;
g_GlobalLock.ExclusiveLock();
ZeroMemory((void *)GlobalIpBuffer, sizeof(GlobalIpBuffer));
if(g_IpListSocket != INVALID_SOCKET) { wsError = WSAIoctl(g_IpListSocket, SIO_ADDRESS_LIST_QUERY, NULL, 0, (LPVOID) GlobalIpBuffer, sizeof(GlobalIpBuffer), &bytesReturned, NULL, NULL);
if(wsError == 0) { fRet = TRUE; } }
g_GlobalLock.ExclusiveUnlock(); return fRet; }
BOOL IsIpInGlobalList(DWORD IpAddress) { INT AddressCount = 0; SOCKET_ADDRESS_LIST * ptr = NULL; sockaddr_in * Current = NULL; char Scratch[100];
TraceFunctEnterEx((LPARAM)NULL, "IsIpInGlobalList");
g_GlobalLock.ShareLock();
Scratch[0] = '\0';
ptr = (SOCKET_ADDRESS_LIST *)GlobalIpBuffer;
for (AddressCount = 0; AddressCount < ptr->iAddressCount;AddressCount++) { Current = (sockaddr_in *) ptr->Address[AddressCount].lpSockaddr; if(Current) { DebugTrace((LPARAM)NULL," Address - %s", inet_ntoa( Current->sin_addr));
if(Current->sin_addr.s_addr == IpAddress) { InetNtoa(*(struct in_addr *) &Current->sin_addr.s_addr, Scratch);
ErrorTrace((LPARAM) NULL, "IpAddress %s is one of mine - Failing connection", Scratch); g_GlobalLock.ShareUnlock(); TraceFunctLeaveEx((LPARAM)NULL); return TRUE; } } }
g_GlobalLock.ShareUnlock();
InetNtoa(*(struct in_addr *) &IpAddress, Scratch);
DebugTrace((LPARAM) NULL, "IpAddress %s is not one of mine ", Scratch);
TraceFunctLeaveEx((LPARAM)NULL); return FALSE; }
void VerifyFQDNWithGlobalIp(DWORD InstanceId, char * szFQDomainName) { INT AddressCount = 0; SOCKET_ADDRESS_LIST * ptr = NULL; sockaddr_in * Current = NULL; char Scratch[100]; Scratch[0] = '\0'; CONST CHAR *apszMsgs[2]; CHAR achInstance[20]; CHAR achIPAddr[20]; PHOSTENT pH = NULL;
//Get the current instnace id
wsprintf( achInstance, "%lu", InstanceId ); apszMsgs[1] = achInstance;
g_GlobalLock.ShareLock(); ptr = (SOCKET_ADDRESS_LIST *)GlobalIpBuffer; for (AddressCount = 0; AddressCount < ptr->iAddressCount;AddressCount++) { Current = (sockaddr_in *) ptr->Address[AddressCount].lpSockaddr; if(Current) { ((PSMTP_IIS_SERVICE) g_pInetSvc)->StartHintFunction(); //For each IP address find the host name
pH = gethostbyaddr( (char*)(&((PSOCKADDR_IN)Current)->sin_addr), 4, PF_INET ); if(pH == NULL) { SmtpLogEvent( SMTP_EVENT_UNRESOLVED_FQDN, 0, (const CHAR **)NULL, 0 ); } else if(_strnicmp(pH->h_name,szFQDomainName,strlen(szFQDomainName))) { wsprintf( achIPAddr,"%s",inet_ntoa( Current->sin_addr)); apszMsgs[0] = achIPAddr; SmtpLogEvent( SMTP_EVENT_UNRESOLVED_FQDN,2,apszMsgs,0 ); } } } g_GlobalLock.ShareUnlock(); }
//
// Public functions.
//
APIERR InitializeGlobals( VOID )
/*++
Routine Description:
Initializes global shared variables. Some values are initialized with constants, others are read from the configuration registry.
Arguments:
None.
Return Value:
Win32
--*/ { DWORD err; DWORD MaxConnections; SYSTEM_INFO systemInfo; HRESULT hr = S_OK; DWORD wsError = 0; DWORD bytesReturned = 0; DWORD dwThreadId = 0;
TraceFunctEnter( "InitializeGlobals" );
g_CalledSrand = FALSE; g_dwIncMsgId = 0;
g_ShutdownHandle = CreateEvent( NULL, TRUE, FALSE, NULL ); if(g_ShutdownHandle == NULL) { err = GetLastError(); ErrorTrace(0, "Cannot allocate shutdown handle. err: %u", err); _ASSERT(err != NO_ERROR); if(err == NO_ERROR) SetLastError (ERROR_NOT_ENOUGH_MEMORY); goto error_exit; }
g_TcpNotifyHandle = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)TcpRegNotifyThread, NULL, 0, &dwThreadId );
if (g_TcpNotifyHandle == NULL ) { err = GetLastError(); ErrorTrace(0, "Cannot create notify thread. err: %u", err); _ASSERT(err != NO_ERROR); if(err == NO_ERROR) SetLastError (ERROR_NOT_ENOUGH_MEMORY); goto error_exit; }
hr = g_EventLog.Initialize("smtpsvc"); if (FAILED(hr)) { // do nothing
}
g_IpListSocket = socket (AF_INET, SOCK_STREAM, 0); if(g_IpListSocket != INVALID_SOCKET) { GetMachineIpAddresses(); wsError = WSAIoctl(g_IpListSocket, SIO_ADDRESS_LIST_CHANGE, NULL, 0, NULL, 0, &bytesReturned, &WsaOverLapped, IpAddressListCallBack);
if(wsError == 0) { //fRet = TRUE;
}
}
//
// read the global registry settings
//
g_SmtpPlatformType = IISGetPlatformType();
if(!GetGlobalRegistrySettings()) { FatalTrace(NULL, "Could not read global reg settings!"); TraceFunctLeave(); return ERROR_SERVICE_DISABLED; }
//thread to periodically call free ununsed libraries
//so dll's can be unloaded
g_FreeLibThreadHandle = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)FreeLibThread, NULL, 0, &dwThreadId );
if (g_FreeLibThreadHandle == NULL ) { err = GetLastError(); ErrorTrace(0, "Cannot create Free Library thread. err: %u", err); _ASSERT(err != NO_ERROR); if(err == NO_ERROR) SetLastError (ERROR_NOT_ENOUGH_MEMORY); goto error_exit; }
//
// do global SEO initialization
//
hr = SEOGetServiceHandle(&g_punkSEOHandle); if (FAILED(hr)) { ErrorTrace(0, "SEOGetServiceHandle returned %x", hr);
// we're in trouble here. we'll try and continue on, but server events
// probably won't work right
g_punkSEOHandle = NULL; //SmtpLogEventSimple(SEO_INIT_FAILED, hr);
}
//
// Initialize the server version string based on the platform type
//
InitServerVersionString();
SmtpPlatformType = IISGetPlatformType();
switch ( SmtpPlatformType ) {
case PtNtWorkstation: lstrcpy(szServerVersion,MAKE_VERSION_STRING(MSSMTP_VERSION_STR_NTW)); lstrcpy(g_szServerType, MSSMTP_VERSION_STR_NTW); break;
default:
//
// Either server or unhandled platform type!
//
DBG_ASSERT(InetIsNtServer(SmtpPlatformType)); lstrcpy(szServerVersion,MAKE_VERSION_STRING(MSSMTP_VERSION_STR_IIS)); lstrcpy(g_szServerType, MSSMTP_VERSION_STR_IIS); }
g_cbServerType = lstrlen( g_szServerType); cbServerVersionString = lstrlen(szServerVersion);
//store the computer name
g_ComputerNameLength = MAX_PATH; if (!GetComputerName(g_ComputerName, &g_ComputerNameLength)) { err = GetLastError(); ErrorTrace((LPARAM)NULL, "GetComputerName() failed with err %d", err); TraceFunctLeave(); return err; }
// number of processors on the system.
GetSystemInfo( &systemInfo ); g_NumProcessors = systemInfo.dwNumberOfProcessors;
g_LoopBackAddr = inet_addr ("127.0.0.1"); g_pSmtpStats = NULL;
//find out what the max connection paramater is
MaxConnections = MAX_CONNECTION_OBJECTS;
DebugTrace(NULL, "g_cMaxConnectionObjs = %d", g_cMaxConnectionObjs);
//allocate some SMTP_CONNECTION objects from CPOOL
if (!SMTP_CONNECTION::Pool.ReserveMemory( g_cMaxConnectionObjs, sizeof(SMTP_CONNECTION) ) ) { err = GetLastError(); ErrorTrace(0, "ReserveMemory failed for SMTP_CONNECTION. err: %u", err); _ASSERT(err != NO_ERROR); if(err == NO_ERROR) SetLastError (ERROR_NOT_ENOUGH_MEMORY); goto error_exit; }
g_SmtpInitializeStatus |= INITIALIZE_INBOUNDPOOL;
//allocate some SMTP_CONNECTION objects from CPOOL
if (!SMTP_CONNOUT::Pool.ReserveMemory(MaxConnections, sizeof(SMTP_CONNOUT) ) ) { err = GetLastError(); ErrorTrace(0, "ReserveMemory failed for SMTP_CONNOUT. err: %u", err); _ASSERT(err != NO_ERROR); if(err == NO_ERROR) SetLastError (ERROR_NOT_ENOUGH_MEMORY); goto error_exit; }
g_SmtpInitializeStatus |= INITIALIZE_OUTBOUNDPOOL;
//allocate some CAddr objects from CPOOL
if (!CAddr::Pool.ReserveMemory(1000, sizeof(CAddr) ) ) { err = GetLastError(); ErrorTrace(0, "ReserveMemory failed for CAddr. err: %u", err); _ASSERT(err != NO_ERROR); if(err == NO_ERROR) SetLastError (ERROR_NOT_ENOUGH_MEMORY); goto error_exit; }
g_SmtpInitializeStatus |= INITIALIZE_ADDRESSPOOL;
if (!CAsyncMx::Pool.ReserveMemory(3000, sizeof(CAsyncMx))) { err = GetLastError(); ErrorTrace(0, "ReserveMemory failed for CBuffer. err: %u", err); _ASSERT(err != NO_ERROR); if(err == NO_ERROR) SetLastError (ERROR_NOT_ENOUGH_MEMORY); goto error_exit; }
g_SmtpInitializeStatus |= INITIALIZE_CASYNCMX;
if (!CAsyncSmtpDns::Pool.ReserveMemory(4000, sizeof(CAsyncSmtpDns))) { err = GetLastError(); ErrorTrace(0, "ReserveMemory failed for CBuffer. err: %u", err); _ASSERT(err != NO_ERROR); if(err == NO_ERROR) SetLastError (ERROR_NOT_ENOUGH_MEMORY); goto error_exit; }
g_SmtpInitializeStatus |= INITIALIZE_CASYNCDNS;
//
// Initialize the file handle cache
//
if (!InitializeCache()) { err = GetLastError(); ErrorTrace(0, "InitializeCache failed err: %u", err); _ASSERT(err != NO_ERROR); if(err == NO_ERROR) SetLastError (ERROR_NOT_ENOUGH_MEMORY); goto error_exit; }
g_SmtpInitializeStatus |= INITIALIZE_FILEHC;
if (!CBuffer::Pool.ReserveMemory(g_cMaxDirBuffers, sizeof(CBuffer))) { err = GetLastError(); ErrorTrace(0, "ReserveMemory failed for CBuffer. err: %u", err); _ASSERT(err != NO_ERROR); if(err == NO_ERROR) SetLastError (ERROR_NOT_ENOUGH_MEMORY); goto error_exit; }
g_SmtpInitializeStatus |= INITIALIZE_CBUFFERPOOL;
if (!CIoBuffer::Pool.ReserveMemory(g_cMaxDirBuffers, g_cMaxDirChangeIoSize)) { err = GetLastError(); ErrorTrace(0, "ReserveMemory failed for CIOBuffer. err: %u", err); _ASSERT(err != NO_ERROR); if(err == NO_ERROR) SetLastError (ERROR_NOT_ENOUGH_MEMORY); goto error_exit; }
g_SmtpInitializeStatus |= INITIALIZE_CIOBUFFPOOL;
if (!CBlockMemoryAccess::m_Pool.ReserveMemory(2000, sizeof(BLOCK_HEAP_NODE))) { err = GetLastError(); ErrorTrace(0, "ReserveMemory failed for CBlockMemoryAccess. err: %u", err); _ASSERT(err != NO_ERROR); if(err == NO_ERROR) SetLastError (ERROR_NOT_ENOUGH_MEMORY); goto error_exit; } g_SmtpInitializeStatus |= INITIALIZE_CBLOCKMGR;
if (!CDropDir::m_Pool.ReserveMemory(1000, sizeof(CDropDir))) { err = GetLastError(); ErrorTrace(0, "ReserveMemory failed for CDropDir. err: %u", err); _ASSERT(err != NO_ERROR); if(err == NO_ERROR) SetLastError (ERROR_NOT_ENOUGH_MEMORY); goto error_exit; } g_SmtpInitializeStatus |= INITIALIZE_CDROPDIR;
//
// Create the CAPI store notification object
//
g_pCAPIStoreChangeNotifier = new STORE_CHANGE_NOTIFIER();
if ( g_pCAPIStoreChangeNotifier == NULL ) { err = GetLastError(); ErrorTrace(0, "Failed to create CAPIStoreChange notifier err: %u", err); _ASSERT(err != NO_ERROR); if(err == NO_ERROR) SetLastError (ERROR_NOT_ENOUGH_MEMORY); goto error_exit; }
if (!CEncryptCtx::Initialize( "SmtpSvc", (struct IMDCOM*) g_pInetSvc->QueryMDObject(), (PVOID) (&g_SmtpSMC))) { err = GetLastError(); ErrorTrace(0, "Initializing SSL Context failed. err: %u", err); _ASSERT(err != NO_ERROR); if(err == NO_ERROR) SetLastError (ERROR_NOT_ENOUGH_MEMORY); goto error_exit; }
g_SmtpInitializeStatus |= INITIALIZE_SSLCONTEXT;
if (!CSecurityCtx::Initialize(FALSE, FALSE)) { err = GetLastError(); ErrorTrace(NULL, "CSecurityCtx::Initialize failed, %u", err); if(err == NO_ERROR) SetLastError (ERROR_NOT_ENOUGH_MEMORY); goto error_exit; }
g_SmtpInitializeStatus |= INITIALIZE_CSECURITY;
GetTimeZoneInformation(&tzInfo);
// Enable/disable 189659 instrumentation
GetRegistryDwordParameter( _T("CrashOnInvalidSMTPConn"), &g_fCrashOnInvalidSMTPConn);
TraceFunctLeave(); return NO_ERROR;
error_exit:
err = GetLastError(); if(err == NO_ERROR) { SetLastError(ERROR_PATH_NOT_FOUND); err = ERROR_PATH_NOT_FOUND; }
TraceFunctLeave(); return err;
} // InitializeGlobals
VOID TerminateGlobals( VOID )
/*++
Routine Description:
Terminates global shared variables.
Arguments:
None.
Return Value:
None.
--*/ {
if(g_ShutdownHandle) { SetEvent(g_ShutdownHandle); }
if(g_SmtpInitializeStatus & INITIALIZE_INBOUNDPOOL) { //finally, release all our memory
SMTP_CONNECTION::Pool.ReleaseMemory(); }
if(g_SmtpInitializeStatus & INITIALIZE_OUTBOUNDPOOL) { SMTP_CONNOUT::Pool.ReleaseMemory(); }
if(g_SmtpInitializeStatus & INITIALIZE_ADDRESSPOOL) { CAddr::Pool.ReleaseMemory(); }
if(g_SmtpInitializeStatus & INITIALIZE_CBUFFERPOOL) { //finally, release all our memory
CBuffer::Pool.ReleaseMemory(); }
if(g_SmtpInitializeStatus & INITIALIZE_CIOBUFFPOOL) { //finally, release all our memory
CIoBuffer::Pool.ReleaseMemory(); }
if (g_SmtpInitializeStatus & INITIALIZE_CDROPDIR) { CDropDir::m_Pool.ReleaseMemory(); } if ( g_pCAPIStoreChangeNotifier ) { delete g_pCAPIStoreChangeNotifier; g_pCAPIStoreChangeNotifier = NULL; }
if (g_SmtpInitializeStatus & INITIALIZE_SSLCONTEXT) { CEncryptCtx::Terminate(); }
if (g_SmtpInitializeStatus & INITIALIZE_CSECURITY) CSecurityCtx::Terminate();
if(g_SmtpInitializeStatus & INITIALIZE_CASYNCMX) { //finally, release all our memory
CAsyncMx::Pool.ReleaseMemory(); }
if(g_SmtpInitializeStatus & INITIALIZE_CASYNCDNS) { //finally, release all our memory
CAsyncSmtpDns::Pool.ReleaseMemory(); }
if (g_SmtpInitializeStatus & INITIALIZE_FILEHC) { TerminateCache(); }
if(g_SmtpInitializeStatus & INITIALIZE_CBLOCKMGR) { //finally, release all our memory
CBlockMemoryAccess::m_Pool.ReleaseMemory(); }
if( g_pSmtpStats != NULL ) { delete g_pSmtpStats; g_pSmtpStats = NULL; }
if(g_IpListSocket != INVALID_SOCKET) { closesocket (g_IpListSocket); g_IpListSocket = INVALID_SOCKET; }
UnLoadQueueDriver();
//
// do global SEO cleanup
//
if (g_punkSEOHandle != NULL) { g_punkSEOHandle->Release(); g_punkSEOHandle = NULL; }
if(g_TcpNotifyHandle != NULL) { WaitForSingleObject(g_TcpNotifyHandle, INFINITE); CloseHandle(g_TcpNotifyHandle); g_TcpNotifyHandle = NULL; }
if(g_FreeLibThreadHandle != NULL) { WaitForSingleObject(g_FreeLibThreadHandle, INFINITE); CloseHandle(g_FreeLibThreadHandle); g_FreeLibThreadHandle = NULL; }
if(g_ShutdownHandle != NULL) { CloseHandle(g_ShutdownHandle); g_ShutdownHandle = NULL; }
} // TerminateGlobals
//
// Given a directory path, this subroutine will create the direct layer by layer
//
BOOL CreateLayerDirectory( char * str ) { BOOL fReturn = TRUE; char Tmp [MAX_PATH + 1];
do { INT index=0; INT iLength = lstrlen(str) + 1;
// first find the index for the first directory
if ( iLength > 2 ) { if ( str[1] == _T(':')) { // assume the first character is driver letter
if ( str[2] == _T('\\')) { index = 2; } else { index = 1; } } else if ( str[0] == _T('\\')) { if ( str[1] == _T('\\')) { BOOL fFound = FALSE; INT i; INT nNum = 0; // unc name
for (i = 2; i < iLength; i++ ) { if ( str[i]==_T('\\')) { // find it
nNum ++; if ( nNum == 2 ) { fFound = TRUE; break; } } } if ( fFound ) { index = i; } else { // bad name
break; } } else { index = 1; } } } else if ( str[0] == _T('\\')) { index = 0; }
// okay ... build directory
do { // find next one
do { if ( index < ( iLength - 1)) { index ++; } else { break; } } while ( str[index] != _T('\\'));
TCHAR szCurrentDir[MAX_PATH+1];
GetCurrentDirectory( MAX_PATH+1, szCurrentDir );
lstrcpyn(Tmp, str, ( index + 1 ));
if ( !SetCurrentDirectory( Tmp)) { if (( fReturn = CreateDirectory( Tmp, NULL )) != TRUE ) { break; } }
SetCurrentDirectory( szCurrentDir );
if ( index >= ( iLength - 1 )) { fReturn = TRUE; break; } } while ( TRUE ); } while (FALSE);
return(fReturn); }
void GenerateMessageId (char * Buffer, DWORD BuffLen) { //Temporary stuff
DWORD MsgIdLen = 20; if(BuffLen < MsgIdLen) MsgIdLen = BuffLen;
if( !g_CalledSrand ) { srand( GetTickCount() ); g_CalledSrand = TRUE; } lstrcpyn (Buffer, g_ComputerName, (MsgIdLen - 1));
DWORD Loop = lstrlen(Buffer); while (Loop < (MsgIdLen - 1) ) { Buffer[Loop] = g_BoundaryChars[rand() % (sizeof(g_BoundaryChars) - 1)]; Loop++; } Buffer [Loop] = '\0'; }
DWORD GetIncreasingMsgId() { return( InterlockedIncrement( (LONG*)&g_dwIncMsgId ) ); }
DWORD FreeLibThread( LPDWORD lpdw ) { DWORD dw = 0; DWORD dwWaitMillisec = g_FreeLibInterval * 1000 * 60;
TraceFunctEnterEx((LPARAM) NULL, "FreeLibThread");
for ( ;; ) { dw = WaitForSingleObject(g_ShutdownHandle, dwWaitMillisec );
switch( dw ) { //
// normal shutdown signalled
//
case WAIT_OBJECT_0:
ErrorTrace((LPARAM) NULL, "Exiting FreeLibThread for hShutdownEvent"); return 0;
//
// Timeout occured
//
case WAIT_TIMEOUT: CoFreeUnusedLibraries(); break;
default: ErrorTrace((LPARAM) NULL, "Exiting FreeLibThread for default reasons"); return 1; } }
return 2; }
#define NUM_REG_THREAD_OBJECTS 2
DWORD TcpRegNotifyThread( LPDWORD lpdw ) { HANDLE Handles[NUM_REG_THREAD_OBJECTS]; PIP_ARRAY aipServers =NULL; PLIST_ENTRY pEntry = NULL; CTcpRegIpList * pIpEntry = NULL; CTcpRegIpList *IpList = NULL; HKEY hKey = NULL; DWORD dw = 0;
TraceFunctEnterEx((LPARAM) NULL, "TcpRegNotifyThread");
Handles[0] = g_ShutdownHandle;
Handles[1] = CreateEvent( NULL, FALSE, FALSE, NULL ); if ( Handles[1] == NULL ) { return 1; }
DnsGetDnsServerList( (PIP_ARRAY *) &aipServers ); if (aipServers != NULL) { g_TcpRegIpList.Update(aipServers); DnsApiFree(aipServers); }
if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\Tcpip", 0, KEY_READ, &hKey ) != ERROR_SUCCESS ) { ErrorTrace((LPARAM) NULL, "RegNotifyThread RegOpenKeyEx failed %d", GetLastError()); CloseHandle( Handles[1] ); return 1; }
for ( ;; ) { if ( RegNotifyChangeKeyValue(hKey, TRUE, REG_NOTIFY_CHANGE_ATTRIBUTES | REG_NOTIFY_CHANGE_LAST_SET, Handles[1], TRUE ) != ERROR_SUCCESS ) { ErrorTrace((LPARAM) NULL, "RegNotifyThread RegNotifyChangeKeyValue failed %d", GetLastError()); RegCloseKey( hKey ); CloseHandle( Handles[1] ); return 1; }
dw = WaitForMultipleObjects(NUM_REG_THREAD_OBJECTS, Handles, FALSE, INFINITE );
switch( dw ) { //
// normal signalled event
//
case WAIT_OBJECT_0: //close all the handles
RegCloseKey( hKey ); CloseHandle( Handles[1] ); Handles[1] = NULL; hKey = NULL; g_TcpRegIpList.Update(NULL); ErrorTrace((LPARAM) NULL, "Exiting TcpRegNotifyThread for hShutdownEvent"); return 0; //
// signalled that our registry keys have changed
//
case WAIT_OBJECT_0+1: DnsGetDnsServerList( &aipServers ); g_TcpRegIpList.Update(aipServers);
if(aipServers) DnsApiFree(aipServers);
break; default: RegCloseKey( hKey ); CloseHandle( Handles[1] ); return 1; } }
RegCloseKey( hKey ); CloseHandle( Handles[1] );
return 2; }
|