1407 lines
37 KiB
C++
1407 lines
37 KiB
C++
/*++
|
|
|
|
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 <isplat.h>
|
|
|
|
#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;
|
|
|
|
|
|
DWORD g_cMaxConnectionObjs = 2000;
|
|
BOOL g_CalledSrand;
|
|
DWORD g_dwIncMsgId;
|
|
|
|
//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);
|
|
void DeleteIpListFunction(PVOID IpList);
|
|
DWORD TcpRegNotifyThread( LPDWORD lpdw );
|
|
DWORD FreeLibThread( LPDWORD lpdw );
|
|
USERDELETEFUNC CTcpRegIpList::m_DeleteFunc = DeleteIpListFunction;
|
|
|
|
//
|
|
// 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";
|
|
|
|
//
|
|
// resolver globals
|
|
//
|
|
|
|
DWORD g_ResolverSockets = 10;
|
|
DWORD g_DnsSocketTimeout = 60000;
|
|
|
|
|
|
|
|
typedef struct tagVERTAG {
|
|
LPSTR pszTag;
|
|
} VERTAG, *PVERTAG, FAR *LPVERTAG;
|
|
|
|
|
|
|
|
VERTAG Tags[] = {
|
|
// { "FileDescription" },
|
|
// { "OriginalFilename" },
|
|
// { "ProductName" },
|
|
{ "ProductVersion" },
|
|
// { "LegalCopyright" },
|
|
// { "LegalCopyright" },
|
|
};
|
|
|
|
#define NUM_TAGS (sizeof( Tags ) / sizeof( VERTAG ))
|
|
|
|
|
|
//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_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;
|
|
|
|
case PtWindows95:
|
|
case PtWindows9x:
|
|
lstrcpy(szServerVersion,MAKE_VERSION_STRING(MSSMTP_VERSION_STR_W95));
|
|
lstrcpy(g_szServerType, MSSMTP_VERSION_STR_W95);
|
|
g_fIsWindows95 = TRUE;
|
|
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);
|
|
|
|
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 ) );
|
|
}
|
|
|
|
|
|
void DeleteIpListFunction(PVOID IpList)
|
|
{
|
|
PIP_ARRAY aipServers = (PIP_ARRAY) IpList;
|
|
|
|
if(aipServers != NULL)
|
|
{
|
|
DnsApiFree(aipServers);
|
|
}
|
|
}
|
|
|
|
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);
|
|
|
|
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);
|
|
break;
|
|
default:
|
|
RegCloseKey( hKey );
|
|
CloseHandle( Handles[1] );
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
RegCloseKey( hKey );
|
|
CloseHandle( Handles[1] );
|
|
|
|
return 2;
|
|
}
|