mirror of https://github.com/tongzx/nt5src
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.
7161 lines
230 KiB
7161 lines
230 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
smtpinst.cxx
|
|
|
|
Abstract:
|
|
|
|
This module defines the SMTP_SERVER_INSTANCE class
|
|
|
|
Author:
|
|
|
|
Johnson Apacible (JohnsonA) June-04-1996
|
|
|
|
|
|
Revision History:
|
|
|
|
David Howell (dhowell) May-1997 Added Etrn Logic
|
|
Nimish Khanolkar (NimishK) Jan - 1998 - modified for CAPI store ce
|
|
|
|
|
|
--*/
|
|
|
|
#define INCL_INETSRV_INCS
|
|
#include "smtpinc.h"
|
|
#include <iis64.h>
|
|
#include "iiscnfg.h"
|
|
#include <mdmsg.h>
|
|
#include <commsg.h>
|
|
#include <imd.h>
|
|
#include <mb.hxx>
|
|
|
|
#include <nsepname.hxx>
|
|
#include "smtpcli.hxx"
|
|
#include "dirnot.hxx"
|
|
#include <smtpinet.h>
|
|
|
|
// SEO Header files
|
|
#define _ATL_NO_DEBUG_CRT
|
|
#define _ATL_STATIC_REGISTRY 1
|
|
#define _ASSERTE _ASSERT
|
|
#define _WINDLL
|
|
#include "atlbase.h"
|
|
extern CComModule _Module;
|
|
#include "atlcom.h"
|
|
#undef _WINDLL
|
|
|
|
#include "smtpsvr.h"
|
|
#include "seo.h"
|
|
#include "seolib.h"
|
|
#include "smtpdisp.h"
|
|
#include "seodisp.h"
|
|
|
|
#include "seo_i.c"
|
|
#include "tran_evntlog.h"
|
|
|
|
extern "C" {
|
|
int strcasecmp(char *s1, char *s2);
|
|
int strncasecmp(char *s1, char *s2, int n);
|
|
}
|
|
|
|
#define STORE_DRIVER_PROGID L"Exchange.NtfsDrv"
|
|
#define SMTPSERVER_PROGID L"SMTPServer.SMTPServer.1"
|
|
|
|
#if 0
|
|
extern VOID
|
|
ServerEventCompletion(
|
|
PVOID pvContext,
|
|
DWORD cbWritten,
|
|
DWORD dwCompletionStatus,
|
|
OVERLAPPED * lpo
|
|
);
|
|
#endif
|
|
|
|
//extern "C++" {
|
|
//BOOL g_IsShuttingDown = FALSE;
|
|
//}
|
|
|
|
DWORD BuildInitialQueueProc(void *lpThis);
|
|
VOID ProcessInitialQueueObjects(PVOID pvContext,
|
|
DWORD cbWritten,
|
|
DWORD dwCompletionStatus,
|
|
OVERLAPPED *lpo);
|
|
|
|
DWORD EnumAllDomains(void *ptr);
|
|
|
|
//
|
|
// Constants
|
|
//
|
|
|
|
//
|
|
// Globals
|
|
//
|
|
|
|
#define MAX_CONNECTION_OBJECTS 5000
|
|
#define DEFAULT_LOGON_METHOD LOGON32_LOGON_INTERACTIVE
|
|
#define DEFAULT_USE_SUBAUTH TRUE
|
|
#define DEFAULT_ANONYMOUS_PWD ""
|
|
|
|
PFN_SF_NOTIFY g_pSslKeysNotify = NULL;
|
|
extern STORE_CHANGE_NOTIFIER *g_pCAPIStoreChangeNotifier;
|
|
|
|
SmtpMappingSupportFunction(
|
|
PVOID pvInstance,
|
|
PVOID pData,
|
|
DWORD dwPropId);
|
|
|
|
SERVICE_MAPPING_CONTEXT g_SmtpSMC = { SmtpMappingSupportFunction};
|
|
|
|
//
|
|
// Prototypes
|
|
//
|
|
BOOL
|
|
SetSslKeysNotify(
|
|
PFN_SF_NOTIFY pFn
|
|
);
|
|
|
|
|
|
/************************************************************
|
|
* Symbolic Constants
|
|
************************************************************/
|
|
|
|
static TCHAR szServicePath[] = TEXT("System\\CurrentControlSet\\Services\\");
|
|
static TCHAR szParametersKey[] = TEXT("\\Parameters");
|
|
static TCHAR szParamPath[] = TEXT("System\\CurrentControlSet\\Services\\SmtpSvc\\Parameters");
|
|
static WCHAR szParamPathW[] = L"System\\CurrentControlSet\\Services\\SmtpSvc\\Parameters";
|
|
static TCHAR szTcpipPath[] = TEXT("System\\CurrentControlSet\\Services\\Tcpip\\Parameters");
|
|
static TCHAR szTcpipTransient[] = TEXT("Transient");
|
|
static TCHAR szMaxSmtpErrors[] = TEXT("MaxErrors");
|
|
static WCHAR szMaxSmtpErrorsW[] = L"MaxErrors";
|
|
static TCHAR szMaxRemoteTimeOut[] = TEXT("MaxRemoteTimeOut");
|
|
static WCHAR szMaxRemoteTimeOutW[] = L"MaxRemoteTimeOut";
|
|
static TCHAR szMaxMsgSize[] = TEXT("MaxMsgSize");
|
|
static WCHAR szMaxMsgSizeW[] = L"MaxMsgSize";
|
|
static TCHAR szMaxMsgSizeBeforeClose[] = TEXT("MaxMsgSizeBeforeClose");
|
|
static WCHAR szMaxMsgSizeBeforeCloseW[] = L"MaxMsgSizeBeforeClose";
|
|
static TCHAR szMaxRcpts[] = TEXT("MaxRcpts");
|
|
static WCHAR szMaxRcptsW[] = L"MaxRcpts";
|
|
static TCHAR szEnableReverseLookup[] = TEXT("EnableReverseLookup");
|
|
static WCHAR szEnableReverseLookupW[] = L"EnableReverseLookup";
|
|
static TCHAR szDomains[] = TEXT("Domains");
|
|
static WCHAR szDomainsW[] = L"Domains";
|
|
static TCHAR szNameResolution[] = TEXT("NameResolution");
|
|
static WCHAR szNameResolutionW[] = L"NameResolution";
|
|
static TCHAR szSmartHostType[] = TEXT("SmartHostUseType");
|
|
static WCHAR szSmartHostTypeW[] = L"SmartHostUseType";
|
|
static TCHAR szRetryAttempts[] = TEXT("MaxRetryAttempts");
|
|
static WCHAR szRetryAttemptsW[] = L"MaxRetryAttempts";
|
|
static TCHAR szRetryMinutes[] = TEXT("MaxRetryMinutes");
|
|
static WCHAR szRetryMinutesW[] = L"MaxRetryMinutes";
|
|
static TCHAR szShouldPipelineOut[] = TEXT("PipelineOutput");
|
|
static WCHAR szShouldPipelineOutW[] = L"PipelineOutput";
|
|
static TCHAR szShouldPipelineIn[] = TEXT("PipelineInput");
|
|
static WCHAR szShouldPipelineInW[] = L"PipelineInput";
|
|
static TCHAR szMaxHopCount[] = TEXT("MaxHopCount");
|
|
static WCHAR szMaxHopCountW[] = L"MaxHopCount";
|
|
static TCHAR szMaxOutConnections[] = TEXT("MaxOutConnections");
|
|
static WCHAR szMaxOutConnectionsW[] = L"MaxOutConnections";
|
|
static TCHAR szSendBadToAdmin[] = TEXT("SendBadToAdmin");
|
|
static WCHAR szSendBadToAdminW[] = L"SendBadToAdmin";
|
|
static TCHAR szSendNDRToAdmin[] = TEXT("SentNDRToAdmin");
|
|
static WCHAR szSendNDRToAdminW[] = L"SentNDRToAdmin";
|
|
static TCHAR szRoutingSources[] = TEXT("RoutingSources");
|
|
static WCHAR szRoutingSourcesW[] = L"RoutingSources";
|
|
static TCHAR szRoutingThreads[] = TEXT("RoutingThreads");
|
|
static WCHAR szRoutingThreadsW[] = L"RoutingThreads";
|
|
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 szBadMailDir[] = TEXT("BadMailDir");
|
|
static WCHAR szBadMailDirW[] = L"BadMailDir";
|
|
|
|
static TCHAR szMailQueueDir[] = TEXT("MailQueueDir");
|
|
static WCHAR szMailQueueDirW[] = L"MailQueueDir";
|
|
static TCHAR szShouldDeliver[] = TEXT("ShouldDeliver");
|
|
static WCHAR szShouldDeliverW[] = L"ShouldDeliver";
|
|
static TCHAR szShouldDelete[] = TEXT("ShouldDelete");
|
|
static WCHAR szShouldDeleteW[] = L"ShouldDelete";
|
|
static TCHAR szDeleteDir[] = TEXT("DeleteDir");
|
|
static WCHAR szDeleteDirW[] = L"DeleteDir";
|
|
static TCHAR szMaxAddrObjects[] = TEXT("MaxAddressObjects");
|
|
static WCHAR szMaxAddrObjectsW[] = L"MaxAddressObjects";
|
|
static TCHAR szMaxMailObjects[] = TEXT("MaxMailObjects");
|
|
static WCHAR szMaxMailObjectsW[] = L"MaxMailObjects";
|
|
static TCHAR szRoutingDll[] = TEXT("RoutingDll");
|
|
static WCHAR szRoutingDllW[] = L"RoutingDll";
|
|
static TCHAR szUseFileLinks[] = TEXT("UseFileLinks");
|
|
static WCHAR szUseFileLinksW[] = L"UseFileLinks";
|
|
static TCHAR szMsgBatchLimit[] = TEXT("BatchMsgLimit");
|
|
static WCHAR szMsgBatchLimitW[] = L"BatchMsgLimit";
|
|
static TCHAR szMailPickupDir[] = TEXT("MailPickupDir");
|
|
static WCHAR szMailPickupDirW[] = L"MailPickupDir";
|
|
static TCHAR szMailDropDir[] = TEXT("MailDropDir");
|
|
static WCHAR szMailDropDirW[] = L"MailDropDir";
|
|
static TCHAR szShouldPickupMail[] = TEXT("ShouldPickupMail");
|
|
static WCHAR szShouldPickupMailW[] = L"ShouldPickupMail";
|
|
static TCHAR szCommandLogMask[] = TEXT("CommandLogMask");
|
|
static WCHAR szCommandLogMaskW[] = L"CommandLogMask";
|
|
static TCHAR szShowEightBitMime[] = TEXT("ShowEightBitMime");
|
|
static WCHAR szShowEightBitMimeW[] = L"ShowEightBitMime";
|
|
static TCHAR szShowBinaryMime[] = TEXT("ShowBinaryMime");
|
|
static WCHAR szShowBinaryMimeW[] = L"ShowBinaryMime";
|
|
static TCHAR szShowChunking[] = TEXT("ShowChunking");
|
|
static WCHAR szShowChunkingW[] = L"ShowChunking";
|
|
static TCHAR szFlushMailFiles[] = TEXT("FlushMailFiles");
|
|
static WCHAR szFlushMailFilesW[] = L"FlushMailFiles";
|
|
static TCHAR szVirtualRoot[] = TEXT("Virtual Roots");
|
|
static WCHAR szVirtualRootW[] = L"Virtual Roots";
|
|
|
|
static TCHAR szRRetryAttempts[] = TEXT("MaxRemoteRetryAttempts");
|
|
static WCHAR szRRetryAttemptsW[] = L"MaxRemoteRetryAttempts";
|
|
static TCHAR szRRetryMinutes[] = TEXT("MaxRemoteRetryMinutes");
|
|
static WCHAR szRRetryMinutesW[] = L"MaxRemoteRetryMinutes";
|
|
|
|
static TCHAR szShareRetryMinutes[] = TEXT("MaxShareRetryMinutes");
|
|
static WCHAR szShareRetryMinutesW[] = L"MaxShareRetryMinutes";
|
|
|
|
|
|
// Always use ANSI for Internet compatibility, even if UNICODE is defined
|
|
static WCHAR szDefaultDomainW[] = L"DefaultDomain";
|
|
static TCHAR szDefaultDomain[] = TEXT("DefaultDomain");
|
|
static WCHAR szConnectResponseW[] = L"ConnectResponse";
|
|
static TCHAR szConnectResponse[] = TEXT("ConnectResponse");
|
|
static WCHAR szSmartHostNameW[] = L"SmartHost";
|
|
static TCHAR szSmartHostName[] = TEXT("SmartHost");
|
|
|
|
|
|
//
|
|
// Added by keithlau on 7/12/96
|
|
//
|
|
#define SMTP_EVENTLOG_MAX_ITEMS 10
|
|
|
|
#define SMTP_INIT_ABSORT 0x00000001
|
|
#define SMTP_INIT_CSLOCK 0x00000002
|
|
#define SMTP_INIT_OUTLOCK 0x00000004
|
|
#define SMTP_INIT_GENLOCK 0x00000008
|
|
|
|
|
|
const LPSTR pszPackagesDefault = "NTLM\0GSSAPI\0";
|
|
const DWORD ccbPackagesDefault = sizeof( "NTLM\0GSSAPI\0" );
|
|
|
|
extern AQ_INITIALIZE_EX_FUNCTION g_pfnInitializeAQ;
|
|
extern AQ_DEINITIALIZE_EX_FUNCTION g_pfnDeinitializeAQ;
|
|
|
|
extern HRESULT CallInstanceInitStoreDriver(DWORD InstanceId, IAdvQueue *pIAq, char * UserName,
|
|
char * DomainName, char * Password, char * DnToUse);
|
|
|
|
extern void CallInstanceDeInitStoreDriver(DWORD InstanceId);
|
|
|
|
//extern HRESULT HrGetGatewayDN(IN OUT DWORD *pcbBuffer,
|
|
// IN LPSTR szBuffer);
|
|
|
|
inline BOOL
|
|
ConvertToMultisz(LPSTR szMulti, DWORD *pdwCount, LPSTR szAuthPack)
|
|
{
|
|
CHAR *pcStart = szAuthPack, *pc;
|
|
DWORD dw = 0;
|
|
|
|
pc = pcStart;
|
|
if (*pc == '\0' || *pc == ',')
|
|
return FALSE;
|
|
|
|
*pdwCount = 0;
|
|
while (TRUE) {
|
|
if (*pc == '\0') {
|
|
strcpy(&szMulti[dw], pcStart);
|
|
(*pdwCount)++;
|
|
dw += lstrlen(pcStart);
|
|
szMulti[dw + 1] = '\0';
|
|
return TRUE;
|
|
} else if (*pc == ',') {
|
|
*pc = '\0';
|
|
lstrcpy(&szMulti[dw], pcStart);
|
|
(*pdwCount)++;
|
|
dw += lstrlen(pcStart);
|
|
dw++;
|
|
*pc = ',';
|
|
pcStart = ++pc;
|
|
} else {
|
|
pc++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Quick and dirty range check using inlines (KeithLau 7/28/96)
|
|
//
|
|
static inline BOOL pValidateRange(DWORD dwValue, DWORD dwLower, DWORD dwUpper)
|
|
{
|
|
// Inclusive
|
|
if ((dwValue >= dwLower) && (dwValue <= dwUpper))
|
|
return (TRUE);
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Quick and dirty string validation
|
|
//
|
|
static inline BOOL pValidateStringPtr(LPWSTR lpwszString, DWORD dwMaxLength)
|
|
{
|
|
if (IsBadStringPtr((LPCTSTR)lpwszString, dwMaxLength))
|
|
return (FALSE);
|
|
while (dwMaxLength--)
|
|
if (*lpwszString++ == 0)
|
|
return (TRUE);
|
|
return (FALSE);
|
|
}
|
|
|
|
|
|
static inline BOOL ConvertFromUnicode(LPWSTR pwsz, char * psz, DWORD cchMax)
|
|
/*++
|
|
Converts a given string into unicode string
|
|
Returns FALSE on failure. Use GetLastError() for details.
|
|
--*/
|
|
{
|
|
DWORD cch;
|
|
|
|
cch = lstrlenW(pwsz) + 1;
|
|
if (cchMax < cch) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
int iRet;
|
|
|
|
iRet = WideCharToMultiByte(CP_ACP, 0, pwsz, cch, psz, cchMax, NULL, NULL);
|
|
|
|
return (iRet != 0);
|
|
} // ConvertToUnicode()
|
|
|
|
//
|
|
// Enumeration stuff
|
|
//
|
|
DWORD WINAPI EnumBuildQProc(LPVOID pvContext)
|
|
{
|
|
SMTP_SERVER_INSTANCE *pInst = (SMTP_SERVER_INSTANCE *)pvContext;
|
|
|
|
_ASSERT(pInst);
|
|
|
|
pInst->TriggerStoreServerEvent(SMTP_STOREDRV_ENUMMESS_EVENT);
|
|
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
DWORD
|
|
InitializeInstances(
|
|
PSMTP_IIS_SERVICE pService
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reads the instances from the metabase
|
|
|
|
Arguments:
|
|
|
|
pService - Server instances added to.
|
|
|
|
Return Value:
|
|
|
|
Win32
|
|
|
|
--*/
|
|
{
|
|
DWORD i;
|
|
DWORD cInstances = 0;
|
|
MB mb( (IMDCOM*) pService->QueryMDObject() );
|
|
CHAR szKeyName[MAX_PATH+1];
|
|
DWORD err = NO_ERROR;
|
|
BUFFER buff;
|
|
BOOL fMigrateRoots = FALSE;
|
|
|
|
|
|
//
|
|
// Open the metabase for write to get an atomic snapshot
|
|
//
|
|
|
|
ReOpen:
|
|
|
|
if ( !mb.Open( "/LM/SMTPSVC/",
|
|
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE )) {
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"InitializeInstances: Cannot open path %s, error %lu\n",
|
|
"/LM/SMTPSVC/", GetLastError() ));
|
|
|
|
//
|
|
// If the web service key isn't here, just create it
|
|
//
|
|
|
|
if ( !mb.Open(METADATA_MASTER_ROOT_HANDLE,
|
|
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ) ||
|
|
!mb.AddObject( "/LM/SMTPSVC/" )) {
|
|
err = GetLastError();
|
|
return err;
|
|
}
|
|
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"/LM/SMTPSvc not found, auto-created\n" ));
|
|
|
|
mb.Close();
|
|
goto ReOpen;
|
|
}
|
|
|
|
//_VERIFY(mb.SetString("", MD_NTAUTHENTICATION_PROVIDERS, IIS_MD_UT_SERVER, "NTLM,LOGIN"));
|
|
DWORD dwVersion;
|
|
if (!mb.GetDword("", MD_SMTP_SERVICE_VERSION, IIS_MD_UT_SERVER, &dwVersion)) {
|
|
_VERIFY(mb.SetDword("", MD_SMTP_SERVICE_VERSION, IIS_MD_UT_SERVER, g_ProductType));
|
|
}
|
|
//_VERIFY(mb.SetDword("", MD_SMTP_AUTHORIZATION, IIS_MD_UT_SERVER, 7));
|
|
//_VERIFY(mb.SetDword("", MD_AUTHORIZATION, IIS_MD_UT_SERVER, 7));
|
|
|
|
|
|
|
|
//
|
|
// Loop through instance keys and build a list. We don't keep the
|
|
// metabase open because the instance instantiation code will need
|
|
// to write to the metabase
|
|
//
|
|
|
|
TryAgain:
|
|
i = 0;
|
|
while ( mb.EnumObjects( "",
|
|
szKeyName,
|
|
i++ )) {
|
|
DWORD dwInstance;
|
|
|
|
//
|
|
// Get the instance id
|
|
//
|
|
|
|
DBGPRINTF((DBG_CONTEXT,"instance key %s\n",szKeyName));
|
|
|
|
dwInstance = atoi( szKeyName );
|
|
if ( dwInstance == 0 ) {
|
|
continue;
|
|
}
|
|
|
|
if ( buff.QuerySize() < (cInstances + 1) * sizeof(DWORD) ) {
|
|
if ( !buff.Resize( (cInstances + 10) * sizeof(DWORD)) ) {
|
|
return GetLastError();
|
|
}
|
|
}
|
|
|
|
((DWORD *) buff.QueryPtr())[cInstances++] = dwInstance;
|
|
}
|
|
|
|
if ( cInstances == 0 ) {
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"No defined instances\n" ));
|
|
|
|
if ( !mb.AddObject( "1" )) {
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"Unable to create first instance, error %d\n",
|
|
GetLastError() ));
|
|
|
|
return GetLastError();
|
|
}
|
|
|
|
fMigrateRoots = TRUE; // Force reg->metabase migration of virtual directories
|
|
goto TryAgain;
|
|
}
|
|
|
|
DBG_REQUIRE( mb.Close() );
|
|
mb.Save();
|
|
|
|
for ( i = 0; i < cInstances; i++ ) {
|
|
DWORD dwInstance = ((DWORD *)buff.QueryPtr())[i];
|
|
|
|
if ( !g_pInetSvc->AddInstanceInfo( dwInstance, fMigrateRoots ) ) {
|
|
err = GetLastError();
|
|
|
|
DBGPRINTF((DBG_CONTEXT,
|
|
"InitializeInstances: cannot create instance %lu, error %lu\n",
|
|
dwInstance, err));
|
|
|
|
//break;
|
|
}
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
} // InitializeInstances
|
|
|
|
|
|
//+---------------------------------------------------------------
|
|
//
|
|
// Function: StopInstance
|
|
//
|
|
// Synopsis: Callback from IIS_SERVICE iterator
|
|
//
|
|
// Arguments: void
|
|
//
|
|
// Returns: TRUE is success, else FALSE
|
|
//
|
|
// History: HowardCu Created 23 May 1995
|
|
//
|
|
//----------------------------------------------------------------
|
|
|
|
BOOL
|
|
StopSmtpInstances(
|
|
PVOID pvContext,
|
|
PVOID pvContext1,
|
|
PIIS_SERVER_INSTANCE pInstance
|
|
)
|
|
{
|
|
PSMTP_SERVER_INSTANCE pSmtpInstance = (PSMTP_SERVER_INSTANCE)pInstance;
|
|
|
|
if ( !pSmtpInstance->Stop() ) {
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Shutdown each instance and terminate all global cpools
|
|
|
|
Arguments:
|
|
|
|
pService - Server instances added to.
|
|
|
|
Return Value:
|
|
|
|
Win32
|
|
|
|
--*/
|
|
VOID
|
|
TerminateInstances( PSMTP_IIS_SERVICE pService)
|
|
{
|
|
PFN_INSTANCE_ENUM pfnInstanceEnum = NULL;
|
|
|
|
TraceFunctEnter("TerminateInstances");
|
|
|
|
//
|
|
// Iterate over all instances
|
|
// StopInstance callback calls SMTP_SERVER_INSTANCE::Stop()
|
|
//
|
|
pfnInstanceEnum = (PFN_INSTANCE_ENUM)&StopSmtpInstances;
|
|
if ( !pService->EnumServiceInstances(
|
|
NULL,
|
|
NULL,
|
|
pfnInstanceEnum
|
|
) ) {
|
|
|
|
ErrorTrace(0,"Error enumerating instances");
|
|
}
|
|
|
|
TraceFunctLeave();
|
|
}
|
|
|
|
|
|
SMTP_SERVER_INSTANCE::SMTP_SERVER_INSTANCE(
|
|
IN PSMTP_IIS_SERVICE pService,
|
|
IN DWORD dwInstanceId,
|
|
IN USHORT Port,
|
|
IN LPCSTR lpszRegParamKey,
|
|
IN LPWSTR lpwszAnonPasswordSecretName,
|
|
IN LPWSTR lpwszVirtualRootsSecretName,
|
|
IN BOOL fMigrateRoots
|
|
)
|
|
: IIS_SERVER_INSTANCE(pService,
|
|
dwInstanceId,
|
|
Port,
|
|
lpszRegParamKey,
|
|
lpwszAnonPasswordSecretName,
|
|
lpwszVirtualRootsSecretName,
|
|
fMigrateRoots)
|
|
//m_signature (SMTP_SERVER_INSTANCE_SIGNATURE)
|
|
{
|
|
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE" );
|
|
|
|
m_pSmtpStats = NULL;
|
|
|
|
m_IsShuttingDown = FALSE;
|
|
m_QIsShuttingDown = FALSE;
|
|
m_RetryQIsShuttingDown = FALSE;
|
|
m_IsFileSystemNtfs = TRUE;
|
|
m_fShouldStartAcceptingConnections = TRUE;
|
|
m_SmtpInitializeStatus = 0;
|
|
|
|
m_cCurrentConnections = 0;
|
|
m_cMaxCurrentConnections = 0;
|
|
m_cCurrentOutConnections = 0;
|
|
m_dwNextInboundClientId = 1;
|
|
m_dwNextOutboundClientId = 1;
|
|
m_dwStopHint = 2;
|
|
m_cProcessClientThreads = 0;
|
|
m_cNumConnInObjsAlloced = 0;
|
|
m_cNumConnOutObjsAlloced = 0;
|
|
m_cNumCBufferObjsAlloced = 0;
|
|
m_cNumAsyncObjsAlloced = 0;
|
|
m_cNumAsyncDnsObjsAlloced = 0;
|
|
m_cchConnectResponse = 0;
|
|
m_cCurrentRoutingThreads = 0;
|
|
m_cMaxOutConnectionsPerDomain = 0;
|
|
m_cMaxOutConnections = 0;
|
|
m_cMaxHopCount = 0;
|
|
m_RemoteSmtpPort = 0;
|
|
m_cMaxRcpts = 0;
|
|
m_fMasquerade = FALSE;
|
|
m_fIgnoreTime = FALSE;
|
|
m_fStartRetry = FALSE;
|
|
m_fRequiresSSL = FALSE;
|
|
m_fRequires128Bits = FALSE;
|
|
m_fRequiresCertVerifySubject= FALSE;
|
|
m_fRequiresCertVerifyIssuer = FALSE;
|
|
m_pSSLInfo = NULL;
|
|
m_fLimitRemoteConnections = TRUE;
|
|
m_RDNSOptions = 0;
|
|
m_fAllowVerify = FALSE;
|
|
m_InstBooted = FALSE;
|
|
m_fStoreDrvStartEventCalled = FALSE;
|
|
m_fStoreDrvPrepShutDownEventCalled = FALSE;
|
|
m_fScheduledConnection = FALSE;
|
|
m_fIsRoutingTable = TRUE;
|
|
m_fHaveRegisteredPrincipalNames = FALSE;
|
|
|
|
m_fHelloNoValidate = FALSE;
|
|
m_fMailNoValidate = FALSE;
|
|
m_fRcptNoValidate = FALSE;
|
|
m_fEtrnNoValidate = FALSE;
|
|
m_fPickupNoValidate = FALSE;
|
|
m_ProviderPackages = NULL;
|
|
fInitializedAQ = FALSE;
|
|
fInitializedStoreDriver = FALSE;
|
|
|
|
// Raid 174038
|
|
m_fDisablePickupDotStuff = FALSE;
|
|
|
|
m_szMasqueradeName [0] = '\0';
|
|
m_szMailQueueDir[0] = '\0';
|
|
m_szMailPickupDir[0] = '\0';
|
|
m_szMailDropDir[0] = '\0';
|
|
m_szBadMailDir[0] = '\0';
|
|
m_szMyDomain[0] = '\0';
|
|
m_szDefaultDomain[0] = '\0';
|
|
m_szFQDomainName[0] = '\0';
|
|
m_szSmartHostName[0] = '\0';
|
|
m_AdminName[0] = '\0';
|
|
m_BadMailName[0] = '\0';
|
|
m_DefaultRemoteUserName[0] = '\0';
|
|
m_DefaultRemotePassword[0] = '\0';
|
|
|
|
SmtpDir = NULL;
|
|
DirPickupThreadHandle = NULL;
|
|
StopHandle = NULL;
|
|
m_hEnumDomainThreadHandle = NULL;
|
|
m_pChangeObject = NULL;
|
|
|
|
m_IAQ = NULL;
|
|
m_ICM = NULL;
|
|
m_pvAQInstanceContext = NULL;
|
|
m_pIAdvQueueConfig = NULL;
|
|
m_RemoteQ = NULL;
|
|
m_ComSmtpServer = NULL;
|
|
m_pSmtpInfo = NULL;
|
|
|
|
m_dwEventlogLevel = LOGEVENT_LEVEL_MEDIUM;
|
|
m_dwDnsFlags = 0;
|
|
|
|
InitializeCriticalSection( &m_critBoot ) ;
|
|
m_fInitAsyncCS = FALSE;
|
|
|
|
m_signature = SMTP_INSTANCE_SIGNATURE;
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return;
|
|
|
|
} // SMTP_SERVER_INSTANCE::SMTP_SERVER_INSTANCE
|
|
|
|
|
|
|
|
SMTP_SERVER_INSTANCE::~SMTP_SERVER_INSTANCE(
|
|
VOID
|
|
)
|
|
{
|
|
TraceFunctEnterEx((LPARAM)this, "~SMTP_SERVER_INSTANCE" );
|
|
|
|
EnterCriticalSection( &m_critBoot );
|
|
|
|
if ( m_InstBooted && !m_fShutdownCalled) {
|
|
InitiateShutDown();
|
|
} else
|
|
ErrorTrace((LPARAM) this, "Shutdown for instance %d was already called", QueryInstanceId());
|
|
|
|
LeaveCriticalSection( &m_critBoot );
|
|
|
|
DeleteCriticalSection( &m_critBoot ) ;
|
|
|
|
TraceFunctLeaveEx((LPARAM) this);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------
|
|
// Description:
|
|
// Called by InitiateStartup() to initialize members of SMTP_SERVER_INSTANCE when
|
|
// a VSI is started up. InitiateStartup() is called by IIS to start a VSI.
|
|
// Arguments:
|
|
// None.
|
|
// Returns:
|
|
// None.
|
|
//---------------------------------------------------------------------------------------
|
|
void SMTP_SERVER_INSTANCE::InitializeClassVariables(void)
|
|
{
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE:InitializeClassVariables" );
|
|
|
|
m_pSmtpStats = NULL;
|
|
|
|
m_IsShuttingDown = FALSE;
|
|
m_QIsShuttingDown = FALSE;
|
|
m_RetryQIsShuttingDown = FALSE;
|
|
m_fShouldStartAcceptingConnections = TRUE;
|
|
m_SmtpInitializeStatus = 0;
|
|
|
|
m_cCurrentConnections = 0;
|
|
m_cMaxCurrentConnections = 0;
|
|
m_cCurrentOutConnections = 0;
|
|
m_dwNextInboundClientId = 1;
|
|
m_dwNextOutboundClientId = 1;
|
|
m_dwStopHint = 2;
|
|
m_cProcessClientThreads = 0;
|
|
m_cNumConnInObjsAlloced = 0;
|
|
m_cNumConnOutObjsAlloced = 0;
|
|
m_cNumCBufferObjsAlloced = 0;
|
|
m_cNumAsyncObjsAlloced = 0;
|
|
m_cNumAsyncDnsObjsAlloced = 0;
|
|
m_cchConnectResponse = 0;
|
|
m_fMasquerade = FALSE;
|
|
m_fIgnoreTime = FALSE;
|
|
m_fStartRetry = FALSE;
|
|
m_fLimitRemoteConnections = TRUE;
|
|
m_fShutdownCalled = FALSE;
|
|
m_fSendNDRToAdmin = FALSE;
|
|
m_fSendBadToAdmin = FALSE;
|
|
m_fRequiresSASL = FALSE;
|
|
m_szDefaultLogonDomain[0] = '\0';
|
|
m_fStoreDrvStartEventCalled = FALSE;
|
|
m_fStoreDrvPrepShutDownEventCalled = FALSE;
|
|
|
|
//directory pickup stuff
|
|
SmtpDir = NULL;
|
|
DirPickupThreadHandle = NULL;
|
|
StopHandle = NULL;
|
|
m_hEnumDomainThreadHandle = NULL;
|
|
|
|
// Raid 174038
|
|
m_fDisablePickupDotStuff = FALSE;
|
|
|
|
m_QStopEvent = NULL;
|
|
m_hEnumBuildQ = NULL;
|
|
|
|
InitializeListHead( &m_ConnectionsList);
|
|
InitializeListHead( &m_OutConnectionsList);
|
|
InitializeListHead( &m_leVRoots);
|
|
InitializeListHead( &m_AsynConnectList);
|
|
InitializeListHead( &m_AsyncDnsList);
|
|
|
|
InitializeCriticalSection( &m_csLock);
|
|
m_SmtpInitializeStatus |= SMTP_INIT_CSLOCK;
|
|
|
|
_ASSERT(!m_fInitAsyncCS && "Doubly initialized critsec");
|
|
if(!m_fInitAsyncCS) {
|
|
InitializeCriticalSection( &m_csAsyncDns );
|
|
InitializeCriticalSection( &m_csAsyncConnect ) ;
|
|
m_fInitAsyncCS = TRUE;
|
|
}
|
|
|
|
m_szConnectResponse[0] = '\0';
|
|
|
|
// Set the logging handle
|
|
m_InstancePropertyBag.SetLogging(&m_Logging);
|
|
|
|
TraceFunctLeaveEx((LPARAM) this);
|
|
}
|
|
|
|
BOOL SMTP_SERVER_INSTANCE::AllocNewMessage(SMTP_ALLOC_PARAMS * Params)
|
|
{
|
|
TraceFunctEnterEx((LPARAM)this, "AllocNewMessage");
|
|
|
|
HRESULT hr = S_OK;
|
|
BOOL fRet = TRUE;
|
|
|
|
Params->m_InstanceId = QueryInstanceId();
|
|
Params->m_EventSmtpServer = (PVOID *) m_ComSmtpServer;
|
|
Params->m_pNotify = NULL;
|
|
|
|
hr = TriggerServerEvent(SMTP_STOREDRV_ALLOC_EVENT, (PVOID) Params);
|
|
|
|
if (FAILED(hr)) {
|
|
fRet = FALSE;
|
|
}
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return fRet;
|
|
|
|
}
|
|
|
|
HRESULT SMTP_SERVER_INSTANCE::SinkReadMetabaseDword(DWORD MetabaseId, DWORD * dwValue)
|
|
{
|
|
DWORD tmp = 0;
|
|
HRESULT hr = S_FALSE;
|
|
MB mb( (IMDCOM*)g_pInetSvc->QueryMDObject() );
|
|
|
|
if (mb.Open(QueryMDPath())) {
|
|
if ( dwValue && mb.GetDword("", MetabaseId, IIS_MD_UT_SERVER, &tmp)) {
|
|
*dwValue = tmp;
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT SMTP_SERVER_INSTANCE::SinkReadMetabaseString(DWORD MetabaseId, char * Buffer, DWORD * BufferSize, BOOL fSecure)
|
|
{
|
|
STR TempString;
|
|
HRESULT hr = S_OK;
|
|
MB mb( (IMDCOM*)g_pInetSvc->QueryMDObject() );
|
|
DWORD MetaOptions = METADATA_INHERIT;
|
|
|
|
TempString.Reset();
|
|
|
|
if (fSecure) {
|
|
MetaOptions |= METADATA_SECURE;
|
|
}
|
|
|
|
if (mb.Open(QueryMDPath())) {
|
|
if (!mb.GetStr("", MetabaseId, IIS_MD_UT_SERVER, &TempString, MetaOptions) ||
|
|
TempString.IsEmpty()) {
|
|
hr = S_FALSE;
|
|
} else {
|
|
lstrcpyn(Buffer,TempString.QueryStr(), MAX_PATH);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//---[ SMTP_SERVER_INSTANCE::SinkReadMetabaseData -----------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Reads arbitraty binary Metabase data (like an ACL)
|
|
// Parameters:
|
|
// IN MetabaseId ID to read data from
|
|
// IN OUT pBuffer Buffer to read data into
|
|
// IN OUT pcbBufferSize Size of buffer/valid data in buffer
|
|
// Returns:
|
|
// S_OK on success
|
|
// HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) if buffer size is not
|
|
// not large enough for requested data.
|
|
// History:
|
|
// 6/7/99 - MikeSwa Created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT SMTP_SERVER_INSTANCE::SinkReadMetabaseData(DWORD MetabaseId,
|
|
BYTE *pBuffer,
|
|
DWORD *pcbBufferSize)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
MB mb( (IMDCOM*)g_pInetSvc->QueryMDObject() );
|
|
|
|
if (!pcbBufferSize)
|
|
return E_INVALIDARG;
|
|
|
|
if (mb.Open(QueryMDPath())) {
|
|
if (!mb.GetData("",
|
|
MetabaseId,
|
|
IIS_MD_UT_SERVER,
|
|
BINARY_METADATA,
|
|
pBuffer,
|
|
pcbBufferSize,
|
|
METADATA_INHERIT)) {
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
} else {
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT SMTP_SERVER_INSTANCE::TriggerLocalDelivery(IMailMsgProperties *pMsg, DWORD dwRecipientCount, DWORD * pdwRecipIndexes, IMailMsgNotify *pNotify)
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
SMTP_ALLOC_PARAMS AllocParams;
|
|
|
|
AllocParams.IMsgPtr = (PVOID) pMsg;
|
|
AllocParams.m_InstanceId = QueryInstanceId();
|
|
AllocParams.m_RecipientCount = dwRecipientCount;
|
|
AllocParams.pdwRecipIndexes = pdwRecipIndexes;
|
|
AllocParams.m_EventSmtpServer = (PVOID *) m_ComSmtpServer;
|
|
AllocParams.hr = S_OK;
|
|
AllocParams.m_pNotify = (PVOID) pNotify;
|
|
|
|
_ASSERT(pMsg != NULL);
|
|
_ASSERT(pdwRecipIndexes != NULL);
|
|
_ASSERT(dwRecipientCount != 0);
|
|
|
|
ADD_COUNTER (this, NumRcptsRecvdLocal, dwRecipientCount);
|
|
ADD_COUNTER (this, NumRcptsRecvd, dwRecipientCount);
|
|
|
|
hr = TriggerServerEvent(SMTP_STOREDRV_DELIVERY_EVENT, (PVOID) &AllocParams);
|
|
|
|
//
|
|
// jstamerj 1998/08/04 17:45:15:
|
|
// If a sink returned a special error, return that to the caller of TriggerLocalDelivery
|
|
//
|
|
if (SUCCEEDED(hr) && FAILED(AllocParams.hr))
|
|
hr = AllocParams.hr;
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT SMTP_SERVER_INSTANCE::TriggerDirectoryDrop(IMailMsgProperties *pMsg, DWORD dwRecipientCount, DWORD * pdwRecipIndexes,
|
|
LPCSTR DropDirectory)
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
SMTP_ALLOC_PARAMS AllocParams;
|
|
|
|
AllocParams.IMsgPtr = (PVOID) pMsg;
|
|
AllocParams.m_InstanceId = QueryInstanceId();
|
|
AllocParams.m_RecipientCount = dwRecipientCount;
|
|
AllocParams.pdwRecipIndexes = pdwRecipIndexes;
|
|
AllocParams.m_EventSmtpServer = (PVOID *) m_ComSmtpServer;
|
|
AllocParams.m_DropDirectory = DropDirectory;
|
|
AllocParams.m_pNotify = NULL;
|
|
|
|
_ASSERT(pMsg != NULL);
|
|
_ASSERT(pdwRecipIndexes != NULL);
|
|
_ASSERT(DropDirectory != NULL);
|
|
_ASSERT(dwRecipientCount != 0);
|
|
|
|
if (DropDirectory != NULL) {
|
|
// hr = TriggerServerEvent(SMTP_MAIL_DROP_EVENT, (PVOID) &AllocParams);
|
|
|
|
} else {
|
|
hr = S_FALSE;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT SMTP_SERVER_INSTANCE::TriggerStoreServerEvent(DWORD EventType)
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
SMTP_ALLOC_PARAMS AllocParams;
|
|
|
|
AllocParams.m_InstanceId = QueryInstanceId();
|
|
AllocParams.m_EventSmtpServer = (PVOID *) m_ComSmtpServer;
|
|
AllocParams.m_dwStartupType = SMTP_INIT_VSERVER_STARTUP;
|
|
AllocParams.m_pNotify = NULL;
|
|
|
|
hr = TriggerServerEvent(EventType, (PVOID) &AllocParams);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
HRESULT SMTP_SERVER_INSTANCE::TriggerDnsResolverEvent(
|
|
LPSTR HostName,
|
|
LPSTR pszFQDN,
|
|
DWORD dwVirtualServerId,
|
|
IDnsResolverRecord **ppIDnsResolverRecord )
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
|
|
EVENTPARAMS_DNSRESOLVERRECORD params;
|
|
params.pszHostName = HostName;
|
|
params.pszFQDN = pszFQDN;
|
|
params.dwVirtualServerId = dwVirtualServerId;
|
|
params.ppIDnsResolverRecord = ppIDnsResolverRecord;
|
|
|
|
hr = TriggerServerEvent( SMTP_DNSRESOLVERRECORDSINK_EVENT, (PVOID) ¶ms);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
HRESULT SMTP_SERVER_INSTANCE::TriggerMaxMsgSizeEvent(
|
|
IUnknown *pIUnknown,
|
|
IMailMsgProperties *pIMailMsg,
|
|
BOOL *pfShouldImposeLimit )
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
|
|
EVENTPARAMS_MAXMSGSIZE params;
|
|
params.pIUnknown = pIUnknown;
|
|
params.pIMailMsg = pIMailMsg;
|
|
params.pfShouldImposeLimit = pfShouldImposeLimit;
|
|
|
|
hr = TriggerServerEvent( SMTP_MAXMSGSIZE_EVENT, (PVOID)¶ms );
|
|
|
|
return( hr );
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
void SMTP_SERVER_INSTANCE::WriteLog(
|
|
LPMSG_TRACK_INFO pMsgTrackInfo,
|
|
IMailMsgProperties *pMsgProps,
|
|
LPEVENT_LOG_INFO pEventLogInfo,
|
|
LPSTR pszProtocolLog )
|
|
{
|
|
//
|
|
// do the message tracking stuff
|
|
//
|
|
|
|
if( pMsgTrackInfo || pMsgProps )
|
|
{
|
|
EVENTPARAMS_MSGTRACKLOG msgTrackLogParams;
|
|
|
|
msgTrackLogParams.pIServer = GetInstancePropertyBag();
|
|
msgTrackLogParams.pIMailMsgProperties = pMsgProps;
|
|
msgTrackLogParams.pMsgTrackInfo = pMsgTrackInfo;
|
|
TriggerServerEvent( SMTP_MSGTRACKLOG_EVENT, (PVOID)&msgTrackLogParams );
|
|
}
|
|
|
|
//
|
|
// do the event log stuff
|
|
//
|
|
|
|
if( pEventLogInfo )
|
|
{
|
|
SmtpLogEventEx( pEventLogInfo->dwEventId, pEventLogInfo->pszEventLogMsg, pEventLogInfo->dwErrorCode );
|
|
}
|
|
|
|
//
|
|
// do protocol logging stuff
|
|
//
|
|
|
|
if( pszProtocolLog )
|
|
{
|
|
INETLOG_INFORMATION translog;
|
|
ZeroMemory( &translog, sizeof( translog ) );
|
|
translog.pszOperation = "SMTPSVC_LOG";
|
|
translog.cbOperation = strlen ("SMTPSVC_LOG");
|
|
translog.pszHTTPHeader = pszProtocolLog;
|
|
translog.cbHTTPHeaderSize = strlen( pszProtocolLog );
|
|
|
|
m_Logging.LogInformation( &translog );
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
HRESULT SMTP_SERVER_INSTANCE::TriggerLogEvent(
|
|
IN DWORD idMessage,
|
|
IN WORD idCategory,
|
|
IN WORD cSubstrings,
|
|
IN LPCSTR *rgszSubstrings,
|
|
IN WORD wType,
|
|
IN DWORD errCode,
|
|
IN WORD iDebugLevel,
|
|
IN LPCSTR szKey,
|
|
IN DWORD dwOptions,
|
|
IN DWORD iMessageString,
|
|
IN HMODULE hModule)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
EVENTPARAMS_LOG LogParms;
|
|
SMTP_LOG_EVENT_INFO LogEventInfo;
|
|
|
|
// Construct the log event info
|
|
LogEventInfo.idMessage = idMessage;
|
|
LogEventInfo.idCategory = idCategory;
|
|
LogEventInfo.cSubstrings = cSubstrings;
|
|
LogEventInfo.rgszSubstrings = rgszSubstrings;
|
|
LogEventInfo.wType = wType;
|
|
LogEventInfo.errCode = errCode;
|
|
LogEventInfo.iDebugLevel = iDebugLevel;
|
|
LogEventInfo.szKey = szKey;
|
|
LogEventInfo.dwOptions = dwOptions;
|
|
LogEventInfo.iMessageString = iMessageString;
|
|
LogEventInfo.hModule = hModule;
|
|
|
|
// Construct the event context
|
|
LogParms.pSmtpEventLogInfo = &LogEventInfo;
|
|
LogParms.pDefaultEventLogHandler = &g_EventLog;
|
|
LogParms.iSelectedDebugLevel = m_dwEventlogLevel;
|
|
TriggerServerEvent( SMTP_LOG_EVENT, (PVOID)&LogParms );
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
HRESULT SMTP_SERVER_INSTANCE::ResetLogEvent(
|
|
IN DWORD idMessage,
|
|
IN LPCSTR szKey)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = g_EventLog.ResetEvent(idMessage, szKey);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
HRESULT SMTP_SERVER_INSTANCE::HrTriggerGetAuxDomainInfoFlagsEvent(
|
|
IN LPCSTR pszDomainName,
|
|
OUT DWORD *pdwDomainInfoFlags )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
EVENTPARAMS_GET_AUX_DOMAIN_INFO_FLAGS EventParams;
|
|
DWORD dwStartTicks, dwStopTicks;
|
|
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE:HrTriggerGetAuxDomainInfoFlagsEvent" );
|
|
|
|
_ASSERT(pdwDomainInfoFlags);
|
|
|
|
// Before we trigger the event, let's pre-set pdwDomainInfoFlags
|
|
// to be "DOMAIN_INFO_INVALID" so we get the right result if there
|
|
// were no sinks
|
|
*pdwDomainInfoFlags = DOMAIN_INFO_INVALID;
|
|
|
|
// Construct the event params
|
|
EventParams.pIServer = GetInstancePropertyBag();
|
|
EventParams.pszDomainName = pszDomainName;
|
|
EventParams.pdwDomainInfoFlags = pdwDomainInfoFlags;
|
|
|
|
DebugTrace((LPARAM)this, "Triggering event SMTP_GET_AUX_DOMAIN_INFO_FLAGS_EVENT ...");
|
|
|
|
// Count ticks for calling this event
|
|
dwStartTicks = GetTickCount();
|
|
|
|
hr = TriggerServerEvent( SMTP_GET_AUX_DOMAIN_INFO_FLAGS_EVENT, (PVOID)&EventParams );
|
|
if(FAILED(hr)) {
|
|
goto Exit;
|
|
}
|
|
|
|
dwStopTicks = GetTickCount();
|
|
|
|
DebugTrace((LPARAM)this, "Event SMTP_GET_AUX_DOMAIN_INFO_FLAGS_EVENT took %d ms.",
|
|
dwStopTicks - dwStartTicks);
|
|
|
|
if (*EventParams.pdwDomainInfoFlags & DOMAIN_INFO_INVALID) {
|
|
// domain info not found ... the caller can interpret the flags
|
|
DebugTrace((LPARAM)this, "Event SMTP_GET_AUX_DOMAIN_INFO_FLAGS_EVENT did NOT return data");
|
|
hr = S_OK;
|
|
}
|
|
else {
|
|
DebugTrace((LPARAM)this, "Event SMTP_GET_AUX_DOMAIN_INFO_FLAGS_EVENT returned flags : %d", *EventParams.pdwDomainInfoFlags);
|
|
hr = S_OK;
|
|
}
|
|
|
|
Exit:
|
|
TraceFunctLeaveEx((LPARAM) this);
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
HRESULT SMTP_SERVER_INSTANCE::TriggerServerEvent(DWORD dwEventID, PVOID pvContext)
|
|
{
|
|
return m_CSMTPSeoMgr.HrTriggerServerEvent(dwEventID, pvContext);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
//--------------------------------------------------------------------------------------
|
|
// Description:
|
|
// Performs per-startup initialization of SMTP_SERVER_INSTANCE. All initialization
|
|
// in here is de-inited by InitiateShutDown(). IIS calls this function each time
|
|
// a VSI is started up.
|
|
// Arguments:
|
|
// None.
|
|
// Returns:
|
|
// TRUE on success, FALSE otherwise.
|
|
// Notes:
|
|
// InitiateStartup() and InitiateShutdown() could be called multiple times for the
|
|
// same SMTP_SERVER_INSTANCE by IIS. If this fails, IIS will shutdown the VSI by
|
|
// calling InitiateShutdown().
|
|
//--------------------------------------------------------------------------------------
|
|
BOOL SMTP_SERVER_INSTANCE::InitiateStartup(void)
|
|
{
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE:InitiateStartup" );
|
|
|
|
DWORD error = NO_ERROR, err = NO_ERROR;
|
|
CSMTPServer * Ptr = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
EnterCriticalSection( &m_critBoot );
|
|
|
|
InitializeClassVariables();
|
|
|
|
Ptr = new CSMTPServer();
|
|
if (Ptr != NULL) {
|
|
Ptr->Init(this);
|
|
hr = Ptr->QueryInterface(IID_ISMTPServer, (void **) &m_ComSmtpServer);
|
|
if (FAILED(hr) || !m_ComSmtpServer) {
|
|
err = GetLastError();
|
|
ErrorTrace((LPARAM) this, "QueryInterface for m_ComSmtpServer failed - %x", hr);
|
|
goto error_exit;
|
|
}
|
|
} else {
|
|
ErrorTrace((LPARAM) this, "new CSMTPServer() failed");
|
|
err = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto error_exit;
|
|
}
|
|
|
|
m_QStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
if (m_QStopEvent == NULL) {
|
|
err = GetLastError();
|
|
ErrorTrace((LPARAM) this, "Creating stop event failed - %d", err);
|
|
goto error_exit;
|
|
}
|
|
|
|
//
|
|
// Create statistics object before initializing the queues
|
|
//
|
|
|
|
m_pSmtpStats = new SMTP_SERVER_STATISTICS(this);
|
|
if ( m_pSmtpStats == NULL ) {
|
|
err = ERROR_NOT_ENOUGH_MEMORY;
|
|
ErrorTrace((LPARAM) this, "new SMTP_SERVER_STATISTICS(this) failed - %d", err);
|
|
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
|
goto error_exit;
|
|
}
|
|
|
|
//
|
|
// initialize the info list - used to collect performance info (a bit of a backdoor
|
|
// to get the information back
|
|
//
|
|
if (!(m_pSmtpInfo = new SMTP_INSTANCE_LIST_ENTRY)) {
|
|
ErrorTrace((LPARAM) this, "new SMTP_INSTANCE_LIST_ENTRY failed");
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
goto error_exit;
|
|
}
|
|
|
|
m_pSmtpInfo->dwInstanceId = QueryInstanceId();
|
|
m_pSmtpInfo->pSmtpServerStatsObj = m_pSmtpStats;
|
|
|
|
((PSMTP_IIS_SERVICE) g_pInetSvc)->AcquireServiceExclusiveLock();
|
|
InsertTailList((((PSMTP_IIS_SERVICE) g_pInetSvc)->GetInfoList()), &(m_pSmtpInfo->ListEntry));
|
|
((PSMTP_IIS_SERVICE) g_pInetSvc)->ReleaseServiceExclusiveLock();
|
|
|
|
((PSMTP_IIS_SERVICE) g_pInetSvc)->StartHintFunction();
|
|
|
|
//
|
|
// shinjuku initialization
|
|
//
|
|
hr = m_CSMTPSeoMgr.HrInit(QueryInstanceId());
|
|
|
|
if (FAILED(hr)) {
|
|
char szInst[10];
|
|
|
|
_itoa((int)QueryInstanceId(), szInst, 10);
|
|
ErrorTrace((LPARAM)this, "Error: Failed to initialize SEO for instance %u",
|
|
QueryInstanceId());
|
|
SmtpLogEventEx(SEO_INIT_FAILED_INSTANCE,
|
|
szInst,
|
|
hr);
|
|
goto error_exit;
|
|
}
|
|
|
|
if (!InitFromRegistry()) {
|
|
err= GetLastError();
|
|
ErrorTrace((LPARAM) this, "init from registry failed. err = %d", err);
|
|
if (err == NO_ERROR)
|
|
err = ERROR_INVALID_PARAMETER;
|
|
|
|
SetLastError(err);
|
|
goto error_exit;
|
|
}
|
|
|
|
((PSMTP_IIS_SERVICE) g_pInetSvc)->StartHintFunction();
|
|
|
|
TriggerStoreServerEvent(SMTP_STOREDRV_STARTUP_EVENT);
|
|
m_fStoreDrvStartEventCalled = TRUE;
|
|
|
|
// Enumerate files ...
|
|
DWORD dwThreadId;
|
|
m_hEnumBuildQ = CreateThread(
|
|
NULL,
|
|
0,
|
|
EnumBuildQProc,
|
|
(LPVOID)this,
|
|
0,
|
|
&dwThreadId);
|
|
if (m_hEnumBuildQ == NULL) {
|
|
err = GetLastError();
|
|
ErrorTrace((LPARAM) this, "Creating startup enumeration thread failed - %d", err);
|
|
goto error_exit;
|
|
}
|
|
|
|
// Initialize the mail pickup stuff, only if enabled
|
|
if (ShouldPickupMail() && !InitDirectoryNotification()) {
|
|
err = GetLastError();
|
|
ErrorTrace((LPARAM) this, "InitDirectoryNotification() failed. err: %u", error);
|
|
if (err == NO_ERROR)
|
|
err = ERROR_INVALID_PARAMETER;
|
|
|
|
SetLastError(err);
|
|
goto error_exit;
|
|
}
|
|
|
|
LeaveCriticalSection( &m_critBoot );
|
|
TraceFunctLeaveEx((LPARAM) this);
|
|
return TRUE;
|
|
|
|
error_exit:
|
|
|
|
LeaveCriticalSection( &m_critBoot );
|
|
TraceFunctLeaveEx((LPARAM) this);
|
|
return FALSE;
|
|
}
|
|
|
|
PSMTP_INSTANCE_LIST_ENTRY SMTP_SERVER_INSTANCE::GetSmtpInstanceInfo(void)
|
|
{
|
|
AQPerfCounters AqPerf;
|
|
HRESULT hr = S_FALSE;
|
|
|
|
if (m_pIAdvQueueConfig != NULL) {
|
|
AqPerf.cbVersion = sizeof(AQPerfCounters);
|
|
hr = m_pIAdvQueueConfig->GetPerfCounters(
|
|
&AqPerf,
|
|
(m_pSmtpInfo) ?
|
|
&(m_pSmtpInfo->pSmtpServerStatsObj->QueryStatsMember()->CatPerfBlock) :
|
|
NULL);
|
|
}
|
|
|
|
if(!FAILED(hr))
|
|
{
|
|
if(m_pSmtpInfo)
|
|
{
|
|
m_pSmtpInfo->pSmtpServerStatsObj->QueryStatsMember()->RemoteQueueLength = AqPerf.cCurrentQueueMsgInstances;
|
|
m_pSmtpInfo->pSmtpServerStatsObj->QueryStatsMember()->NumMsgsDelivered = AqPerf.cMsgsDeliveredLocal;
|
|
m_pSmtpInfo->pSmtpServerStatsObj->QueryStatsMember()->LocalQueueLength = AqPerf.cCurrentMsgsPendingLocalDelivery;
|
|
m_pSmtpInfo->pSmtpServerStatsObj->QueryStatsMember()->RemoteRetryQueueLength = AqPerf.cCurrentMsgsPendingRemoteRetry;
|
|
m_pSmtpInfo->pSmtpServerStatsObj->QueryStatsMember()->NumSendRetries = AqPerf.cTotalMsgRemoteSendRetries;
|
|
m_pSmtpInfo->pSmtpServerStatsObj->QueryStatsMember()->NumNDRGenerated = AqPerf.cNDRsGenerated;
|
|
m_pSmtpInfo->pSmtpServerStatsObj->QueryStatsMember()->RetryQueueLength = AqPerf.cCurrentMsgsPendingLocalRetry;
|
|
m_pSmtpInfo->pSmtpServerStatsObj->QueryStatsMember()->NumDeliveryRetries = AqPerf.cTotalMsgLocalRetries;
|
|
m_pSmtpInfo->pSmtpServerStatsObj->QueryStatsMember()->ETRNMessages = AqPerf.cTotalMsgsTURNETRN;
|
|
m_pSmtpInfo->pSmtpServerStatsObj->QueryStatsMember()->CatQueueLength = AqPerf.cCurrentMsgsPendingCat;
|
|
m_pSmtpInfo->pSmtpServerStatsObj->QueryStatsMember()->MsgsBadmailNoRecipients = AqPerf.cTotalMsgsBadmailNoRecipients;
|
|
m_pSmtpInfo->pSmtpServerStatsObj->QueryStatsMember()->MsgsBadmailHopCountExceeded = AqPerf.cTotalMsgsBadmailHopCountExceeded;
|
|
m_pSmtpInfo->pSmtpServerStatsObj->QueryStatsMember()->MsgsBadmailFailureGeneral = AqPerf.cTotalMsgsBadmailFailureGeneral;
|
|
m_pSmtpInfo->pSmtpServerStatsObj->QueryStatsMember()->MsgsBadmailBadPickupFile = AqPerf.cTotalMsgsBadmailBadPickupFile;
|
|
m_pSmtpInfo->pSmtpServerStatsObj->QueryStatsMember()->MsgsBadmailEvent = AqPerf.cTotalMsgsBadmailEvent;
|
|
m_pSmtpInfo->pSmtpServerStatsObj->QueryStatsMember()->MsgsBadmailNdrOfDsn = AqPerf.cTotalMsgsBadmailNdrOfDsn;
|
|
m_pSmtpInfo->pSmtpServerStatsObj->QueryStatsMember()->MsgsPendingRouting = AqPerf.cCurrentMsgsPendingRouting;
|
|
m_pSmtpInfo->pSmtpServerStatsObj->QueryStatsMember()->MsgsPendingUnreachableLink = AqPerf.cCurrentMsgsPendingUnreachableLink;
|
|
m_pSmtpInfo->pSmtpServerStatsObj->QueryStatsMember()->SubmittedMessages = AqPerf.cTotalMsgsSubmitted;
|
|
m_pSmtpInfo->pSmtpServerStatsObj->QueryStatsMember()->DSNFailures = AqPerf.cTotalDSNFailures;
|
|
m_pSmtpInfo->pSmtpServerStatsObj->QueryStatsMember()->MsgsInLocalDelivery = AqPerf.cCurrentMsgsInLocalDelivery;
|
|
|
|
}
|
|
}
|
|
return m_pSmtpInfo;
|
|
}
|
|
|
|
//---[ SMTP_SERVER_INSTANCE::HrGetDomainInfoFlags ]----------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Gets domain info flags for specified domain if present
|
|
// Parameters:
|
|
// IN szDomainName Name of domain to check for
|
|
// OUT pdwDomainInfoFlags DomainInfo flags for this domain
|
|
// Returns:
|
|
// S_OK on success
|
|
// E_INVALIDARG if szDomainName or pdwDomainInfoFlags is NULL
|
|
// E_FAIL if other failure
|
|
// History:
|
|
// 10/6/2000 - dbraun, Created.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT SMTP_SERVER_INSTANCE::HrGetDomainInfoFlags(
|
|
IN LPSTR szDomainName,
|
|
OUT DWORD *pdwDomainInfoFlags)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IAdvQueueDomainType * pIAdvQueueDomainType = NULL;
|
|
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE:HrGetDomainInfoFlags" );
|
|
|
|
// Make sure we have a valid IAdvQueue interface
|
|
if (!m_IAQ) {
|
|
ErrorTrace((LPARAM) this, "Member m_IAQ is not valid");
|
|
_ASSERT(m_IAQ);
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
// Get the IAdvQueueDomainType interface
|
|
hr = m_IAQ->QueryInterface(IID_IAdvQueueDomainType, (void **) &pIAdvQueueDomainType);
|
|
if (FAILED(hr) || !pIAdvQueueDomainType) {
|
|
ErrorTrace((LPARAM) this, "QueryInterface for IID_IAdvQueueDomainType failed - %x", hr);
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
// Got the interface, now check for the domain
|
|
hr = pIAdvQueueDomainType->GetDomainInfoFlags(szDomainName, pdwDomainInfoFlags);
|
|
|
|
exit:
|
|
|
|
if (pIAdvQueueDomainType)
|
|
pIAdvQueueDomainType->Release();
|
|
|
|
TraceFunctLeaveEx((LPARAM) this);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
BOOL SMTP_SERVER_INSTANCE::Stop(void)
|
|
{
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE:Stop" );
|
|
|
|
//set the global termination flag
|
|
m_IsShuttingDown = TRUE;
|
|
|
|
EnterCriticalSection( &m_critBoot );
|
|
|
|
if (m_ICM) {
|
|
m_ICM->ReleaseWaitingThreads();
|
|
}
|
|
|
|
if (!m_InstBooted) {
|
|
LeaveCriticalSection( &m_critBoot );
|
|
TraceFunctLeaveEx((LPARAM) this);
|
|
return TRUE;
|
|
}
|
|
|
|
if (m_fShutdownCalled) {
|
|
LeaveCriticalSection( &m_critBoot );
|
|
TraceFunctLeaveEx((LPARAM) this);
|
|
return TRUE;
|
|
}
|
|
|
|
if (m_QStopEvent) {
|
|
SetEvent(m_QStopEvent);
|
|
}
|
|
|
|
//disconnect all inbound connections
|
|
DisconnectAllConnections();
|
|
|
|
DisconnectAllAsyncDnsConnections();
|
|
|
|
//disconnect all outbound connections
|
|
DisconnectAllOutboundConnections();
|
|
|
|
DisconnectAllAsyncConnections();
|
|
|
|
//we need to disconnect all outbound connections again here,
|
|
//incase one slipped past the remote queue shutdown code
|
|
DisconnectAllOutboundConnections();
|
|
|
|
m_rfAccessCheck.Reset( (IMDCOM*)m_Service->QueryMDObject() );
|
|
LeaveCriticalSection( &m_critBoot );
|
|
|
|
TraceFunctLeaveEx((LPARAM) this);
|
|
return TRUE;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------
|
|
// Description:
|
|
// Function called by IIS to deinitialize SMTP_SERVER_INSTANCE when the VSI is
|
|
// stopping. Note that this function can be called multiple times for the same
|
|
// SMTP_SERVER_INSTANCE. A matching call to InitializeClassVariables() and
|
|
// InitiateStartup() do is made by IIS (to start SMTP_SERVER_INSTANCE).
|
|
// Arguments:
|
|
// None.
|
|
// Returns:
|
|
// None.
|
|
//-----------------------------------------------------------------------------------
|
|
void SMTP_SERVER_INSTANCE::InitiateShutDown(void)
|
|
{
|
|
char IntBuffer [20];
|
|
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE:InitiateShutDown" );
|
|
|
|
EnterCriticalSection( &m_critBoot );
|
|
|
|
Stop();
|
|
|
|
// Wait for the enum buildq thread to die ...
|
|
if (m_hEnumBuildQ) {
|
|
DWORD dwWait;
|
|
do {
|
|
dwWait = WaitForSingleObject(m_hEnumBuildQ, 1000);
|
|
if (dwWait == WAIT_TIMEOUT)
|
|
StopHint();
|
|
|
|
} while (dwWait != WAIT_OBJECT_0);
|
|
|
|
CloseHandle(m_hEnumBuildQ);
|
|
m_hEnumBuildQ = NULL;
|
|
}
|
|
|
|
// Wait for the enum domains thread to die ...
|
|
if (m_hEnumDomainThreadHandle) {
|
|
DWORD dwWait;
|
|
do {
|
|
dwWait = WaitForSingleObject(m_hEnumDomainThreadHandle, 1000);
|
|
if (dwWait == WAIT_TIMEOUT)
|
|
StopHint();
|
|
|
|
} while (dwWait != WAIT_OBJECT_0);
|
|
|
|
CloseHandle(m_hEnumDomainThreadHandle);
|
|
m_hEnumDomainThreadHandle = NULL;
|
|
}
|
|
|
|
//make sure directory notification threads are shut down
|
|
if (ShouldPickupMail())
|
|
DestroyDirectoryNotification();
|
|
|
|
//Prepare for shutdown *must* be called before StopQDrivers... otherwise
|
|
//we may have stray threads calling into submit messages... which could
|
|
//AV.
|
|
if(m_fStoreDrvStartEventCalled && !m_fStoreDrvPrepShutDownEventCalled)
|
|
{
|
|
TriggerStoreServerEvent(SMTP_STOREDRV_PREPSHUTDOWN_EVENT);
|
|
m_fStoreDrvPrepShutDownEventCalled = TRUE;
|
|
}
|
|
|
|
// After this NOBODY can submit to the queue, the pointers are GONE
|
|
StopQDrivers();
|
|
|
|
if( m_fStoreDrvStartEventCalled )
|
|
{
|
|
TriggerStoreServerEvent(SMTP_STOREDRV_SHUTDOWN_EVENT);
|
|
}
|
|
|
|
//now that all the queues have stopped receiving data,
|
|
//flush each queue, by removing all data and then delete
|
|
//the queues.
|
|
|
|
if (m_RemoteQ != NULL) {
|
|
delete m_RemoteQ;
|
|
m_RemoteQ = NULL;
|
|
}
|
|
|
|
|
|
DebugTrace((LPARAM)this, "removing and delete the Info List");
|
|
|
|
if (m_pSmtpInfo != NULL) {
|
|
((PSMTP_IIS_SERVICE)g_pInetSvc)->AcquireServiceExclusiveLock();
|
|
RemoveEntryList(&(m_pSmtpInfo->ListEntry));
|
|
((PSMTP_IIS_SERVICE)g_pInetSvc)->ReleaseServiceExclusiveLock();
|
|
|
|
delete (m_pSmtpInfo);
|
|
m_pSmtpInfo = NULL;
|
|
}
|
|
|
|
DebugTrace((LPARAM)this, "deleting statistics obj");
|
|
|
|
//
|
|
// delete statistics object
|
|
//
|
|
|
|
if ( m_pSmtpStats != NULL ) {
|
|
delete m_pSmtpStats;
|
|
m_pSmtpStats = NULL;
|
|
}
|
|
|
|
|
|
FreeVRootList(&m_leVRoots);
|
|
|
|
DebugTrace((LPARAM)this, "deleting crit sects");
|
|
|
|
//Delete the critical section objects
|
|
|
|
if (m_SmtpInitializeStatus & SMTP_INIT_CSLOCK) {
|
|
DeleteCriticalSection( &m_csLock);
|
|
m_SmtpInitializeStatus &= ~SMTP_INIT_CSLOCK;
|
|
}
|
|
|
|
if (m_ProviderPackages != NULL ) {
|
|
LocalFree((HANDLE)m_ProviderPackages);
|
|
m_ProviderPackages = NULL;
|
|
}
|
|
|
|
//free the SSL info object
|
|
if ( m_pSSLInfo != NULL ) {
|
|
//If the refcount is not zero - we have a problem
|
|
DWORD dwCount = IIS_SSL_INFO::Release( m_pSSLInfo );
|
|
|
|
m_pSSLInfo = NULL;
|
|
}
|
|
|
|
ResetRelayIpSecList();
|
|
|
|
//
|
|
// shutdown shinjuku
|
|
// this causes SEO to drop all loaded objects
|
|
//
|
|
m_CSMTPSeoMgr.Deinit();
|
|
|
|
if (m_ComSmtpServer != NULL) {
|
|
m_ComSmtpServer->Release();
|
|
m_ComSmtpServer = NULL;
|
|
}
|
|
|
|
if (m_QStopEvent != NULL) {
|
|
CloseHandle(m_QStopEvent);
|
|
m_QStopEvent = NULL;
|
|
}
|
|
|
|
//
|
|
// here we see if we are getting shutdown because we are being
|
|
// deleted. if so then we'll remove all of our bindings from
|
|
// the shinjuku event binding database
|
|
//
|
|
MB mb( (IMDCOM*) g_pInetSvc->QueryMDObject() );
|
|
|
|
StopHint();
|
|
|
|
if (mb.Open(QueryMDPath())) {
|
|
// our metabase path still exists, so we aren't being deleted
|
|
mb.Close();
|
|
} else {
|
|
StopHint();
|
|
|
|
// our metabase path is gone, delete the shinjuku binding
|
|
// database
|
|
HRESULT hr = UnregisterPlatSEOInstance(QueryInstanceId());
|
|
if (FAILED(hr)) {
|
|
char szInst[10];
|
|
|
|
_itoa((int)QueryInstanceId(), szInst, 10);
|
|
ErrorTrace(0, "UnregisterSEOInstance(%lu) failed with %x",
|
|
QueryInstanceId(), hr);
|
|
SmtpLogEventEx(SEO_DELETE_INSTANCE_FAILED,
|
|
szInst,
|
|
hr);
|
|
}
|
|
}
|
|
|
|
_ASSERT(m_fInitAsyncCS && "Deleting un-initialized critsec");
|
|
if(m_fInitAsyncCS) {
|
|
DeleteCriticalSection( &m_csAsyncDns);
|
|
DeleteCriticalSection( &m_csAsyncConnect);
|
|
m_fInitAsyncCS = FALSE;
|
|
}
|
|
|
|
m_fShutdownCalled = TRUE;
|
|
|
|
LeaveCriticalSection( &m_critBoot );
|
|
|
|
TraceFunctLeaveEx((LPARAM) this);
|
|
}
|
|
|
|
DWORD SMTP_SERVER_INSTANCE::PauseInstance()
|
|
{
|
|
DWORD err = NO_ERROR ;
|
|
char IntBuffer [20];
|
|
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE::PauseInstance");
|
|
|
|
err = IIS_SERVER_INSTANCE::PauseInstance() ;
|
|
|
|
if (err == NO_ERROR) {
|
|
_itoa(QueryInstanceId(), IntBuffer, 10);
|
|
|
|
SmtpLogEventEx(SMTP_EVENT_SERVICE_INSTANCE_PAUSED, IntBuffer, 0);
|
|
}
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
|
|
return err ;
|
|
}
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets instance to RUNNING
|
|
|
|
Arguments:
|
|
|
|
NewState - Receives the new state.
|
|
|
|
Return Value:
|
|
|
|
DWORD - 0 if successful, !0 otherwise.
|
|
|
|
--*/
|
|
|
|
DWORD SMTP_SERVER_INSTANCE::StartInstance(void)
|
|
{
|
|
DWORD RetCode = ERROR_INVALID_SERVICE_CONTROL;
|
|
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE::StartInstance(void)" );
|
|
|
|
_ASSERT(QueryServerState( ) == MD_SERVER_STATE_STOPPED);
|
|
|
|
//initiate our startup first
|
|
if ( InitiateStartup() ) {
|
|
|
|
RetCode = IIS_SERVER_INSTANCE::StartInstance();
|
|
|
|
if (RetCode != ERROR_SUCCESS) {
|
|
// shutdown the instance
|
|
InitiateShutDown();
|
|
DebugTrace((LPARAM)this, "StartInstance() failed, err= %d", RetCode);
|
|
}
|
|
else
|
|
{
|
|
m_InstBooted = TRUE;
|
|
}
|
|
|
|
|
|
} else {
|
|
//shutdown everything
|
|
InitiateShutDown();
|
|
}
|
|
|
|
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return RetCode;
|
|
}
|
|
|
|
DWORD SMTP_SERVER_INSTANCE::StopInstance(void)
|
|
{
|
|
DWORD RetCode = NO_ERROR;
|
|
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE::StopInstance(void)" );
|
|
|
|
//call the IIS stuff first.
|
|
RetCode = IIS_SERVER_INSTANCE::StopInstance();
|
|
|
|
if (RetCode == NO_ERROR) {
|
|
//shutdown everything
|
|
InitiateShutDown();
|
|
} else {
|
|
DebugTrace((LPARAM)this, "StopInstance() failed, err= %d", RetCode);
|
|
}
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return RetCode;
|
|
}
|
|
|
|
BOOL SMTP_SERVER_INSTANCE::InitQueues(void)
|
|
{
|
|
DWORD error = NO_ERROR;
|
|
BOOL fReturn = FALSE;
|
|
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE::InitQueues" );
|
|
|
|
m_RemoteQ = PERSIST_QUEUE::CreateQueue(REMOTEQ, this);
|
|
if (m_RemoteQ != NULL) {
|
|
fReturn = TRUE;
|
|
} else {
|
|
error = GetLastError();
|
|
ErrorTrace((LPARAM)this, "new failed for PERSIST_QUEUE::CreateQueue(REMOTEQ). err: %u", error);
|
|
if (error == NO_ERROR)
|
|
SetLastError (ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
return fReturn;
|
|
}
|
|
|
|
void SMTP_SERVER_INSTANCE::FreeVRootList(PLIST_ENTRY pleHead)
|
|
{
|
|
PLIST_ENTRY pEntry;
|
|
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE::FreeVRootList" );
|
|
|
|
while (!IsListEmpty(pleHead)) {
|
|
pEntry = RemoveHeadList(pleHead);
|
|
TCP_FREE(CONTAINING_RECORD(pEntry, SMTP_VROOT_ENTRY, list));
|
|
}
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
GetVroots(
|
|
PVOID pvContext,
|
|
MB * pmb,
|
|
VIRTUAL_ROOT * pvr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Virtual directory enumerater callback that allocates and builds the
|
|
virtual directory structure list
|
|
|
|
Arguments:
|
|
pvContext is a pointer to the midl allocated memory
|
|
|
|
Return:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
//LPINET_INFO_VIRTUAL_ROOT_LIST pvrl = (LPINET_INFO_VIRTUAL_ROOT_LIST) pv
|
|
//DWORD i = pvrl->cEntries;
|
|
//LPINET_INFO_VIRTUAL_ROOT_ENTRY pvre = &pvrl->aVirtRootEntry[i];
|
|
|
|
//_ASSERT( pvr->pszMetaPath[0] == '/' &&
|
|
// pvr->pszMetaPath[1] == '/' );
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL SMTP_SERVER_INSTANCE::FindBestVRoot(LPSTR szVRoot)
|
|
{
|
|
PLIST_ENTRY pEntry;
|
|
HANDLE hToken;
|
|
DWORD cbRoot;
|
|
char szRoot[MAX_PATH + 1];
|
|
DWORD dwErr;
|
|
DWORD dwBytes;
|
|
DWORD dwSectors;
|
|
DWORD dwFree;
|
|
DWORD dwTotal;
|
|
DWORD dwRatio;
|
|
DWORD dwRatioKeep;
|
|
PLIST_ENTRY pKeep = NULL;
|
|
LPSTR szT;
|
|
DWORD cSlash;
|
|
DWORD dwAccessMask = 0;
|
|
SMTP_VROOT_ENTRY *pVrEntry = NULL;
|
|
|
|
TraceFunctEnterEx((LPARAM)this, "SMTPCONFIG::FindBestVRoot");
|
|
|
|
if (IsListEmpty(&m_leVRoots)) {
|
|
ErrorTrace((LPARAM)this, "Vroots list empty");
|
|
return FALSE;
|
|
}
|
|
|
|
for (pEntry = m_leVRoots.Flink ; pEntry != &m_leVRoots ; pEntry = pEntry->Flink) {
|
|
cbRoot = sizeof(szRoot);
|
|
|
|
pVrEntry = (SMTP_VROOT_ENTRY *) CONTAINING_RECORD(pEntry, SMTP_VROOT_ENTRY, list);
|
|
|
|
if (!QueryVrootTable()->LookupVirtualRoot(pVrEntry->szVRoot,
|
|
szRoot, &cbRoot, &dwAccessMask, NULL, NULL,
|
|
&hToken, NULL)) {
|
|
dwErr = GetLastError();
|
|
ErrorTrace(NULL, "ResolveVirtualRoot failed for %s, %u",
|
|
CONTAINING_RECORD(pEntry, SMTP_VROOT_ENTRY, list)->szVRoot, dwErr);
|
|
} else {
|
|
cSlash = 0;
|
|
if (szRoot[0] == '\\' && szRoot[1] == '\\') {
|
|
// UNC Name
|
|
DebugTrace((LPARAM)this, "Found UNC path %s", szRoot);
|
|
szT = szRoot;
|
|
|
|
while (*szT) {
|
|
if (*szT == '\\') {
|
|
cSlash++;
|
|
if (cSlash == 4) {
|
|
*(szT + 1) = '\0';
|
|
}
|
|
}
|
|
|
|
szT++;
|
|
}
|
|
|
|
if (cSlash != 4) {
|
|
lstrcat(szRoot, "\\");
|
|
}
|
|
} else {
|
|
DebugTrace((LPARAM)this, "Found normal directory: %s", szRoot);
|
|
szRoot[3] = '\0';
|
|
}
|
|
|
|
DebugTrace((LPARAM)this, "Getting free disk ratio on %s", szRoot);
|
|
if (hToken == 0 || ImpersonateLoggedOnUser(hToken)) {
|
|
if (GetDiskFreeSpace(szRoot, &dwSectors, &dwBytes, &dwFree, &dwTotal)) {
|
|
dwSectors *= dwBytes;
|
|
dwRatio = MulDiv(dwSectors, dwTotal, dwFree);
|
|
if (pKeep == NULL) {
|
|
dwRatioKeep = dwRatio;
|
|
pKeep = pEntry;
|
|
} else {
|
|
if (dwRatioKeep > dwRatio) {
|
|
dwRatioKeep = dwRatio;
|
|
pKeep = pEntry;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hToken != 0)
|
|
_VERIFY(RevertToSelf());
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pKeep != NULL)
|
|
lstrcpy(szVRoot, CONTAINING_RECORD(pKeep, SMTP_VROOT_ENTRY, list)->szVRoot);
|
|
else
|
|
lstrcpy(szVRoot, pVrEntry->szVRoot);
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------
|
|
//
|
|
// Function: SMTPCONFIG::WriteRegParams
|
|
//
|
|
// Synopsis: Writes parameters from a config info structure
|
|
// into the registry
|
|
//
|
|
// Arguments: SMTP_CONFIG_INFO *: pointer to config information
|
|
//
|
|
// Returns: BOOL - TRUE on SUCCESS, FALSE on FAIL
|
|
//
|
|
//----------------------------------------------------------------
|
|
BOOL SMTP_SERVER_INSTANCE::WriteRegParams(SMTP_CONFIG_INFO *pconfig)
|
|
{
|
|
|
|
//TraceFunctLeaveEx((LPARAM)this);
|
|
return TRUE;
|
|
}
|
|
|
|
DWORD ReadMetabaseDword (MB& mb, DWORD Key, DWORD DefaultValue)
|
|
{
|
|
DWORD tmp = 0;
|
|
|
|
if ( !mb.GetDword("", Key, IIS_MD_UT_SERVER, &tmp)) {
|
|
//mb.SetDword("", Key, IIS_MD_UT_SERVER, DefaultValue);
|
|
tmp = DefaultValue;
|
|
}
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
BOOL SMTP_SERVER_INSTANCE::SetProviderPackages()
|
|
{
|
|
TraceFunctEnter( "SMTP_SERVER_INSTANCE::SetProviderPackages" );
|
|
|
|
LPSTR psz;
|
|
DWORD i;
|
|
|
|
PAUTH_BLOCK pBlock = NULL;
|
|
|
|
if ( m_ProviderNames == NULL || m_cProviderPackages == 0) {
|
|
ErrorTrace((LPARAM)this, "Invalid Parameters: 0x%08X, %d",
|
|
m_ProviderNames, m_cProviderPackages );
|
|
return FALSE;
|
|
}
|
|
|
|
pBlock = (PAUTH_BLOCK)LocalAlloc(0, m_cProviderPackages * sizeof(AUTH_BLOCK));
|
|
if (pBlock == NULL) {
|
|
ErrorTrace( 0, "AUTH_BLOCK LocalAlloc failed: %d", GetLastError() );
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// start at 1 since 0 indicates the Invalid protocol
|
|
//
|
|
for ( i=0, psz = (LPSTR)m_ProviderNames; i< m_cProviderPackages; i++ ) {
|
|
//
|
|
// this would be the place to check whether the package was valid
|
|
//
|
|
DebugTrace( 0, "Protocol: %s", psz);
|
|
|
|
pBlock[i].Name = psz;
|
|
|
|
psz += lstrlen(psz) + 1;
|
|
}
|
|
|
|
//
|
|
// if we're replacing already set packages; free their memory
|
|
//
|
|
if (m_ProviderPackages != NULL ) {
|
|
LocalFree((HANDLE)m_ProviderPackages );
|
|
m_ProviderPackages = NULL;
|
|
}
|
|
|
|
m_ProviderPackages = pBlock;
|
|
|
|
return TRUE;
|
|
|
|
} // SetAuthPackageNames
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
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(
|
|
STR * pstrDomainName
|
|
)
|
|
{
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
NTSTATUS NtStatus;
|
|
INT Result;
|
|
APIERR err = 0;
|
|
LSA_HANDLE LsaPolicyHandle = NULL;
|
|
PPOLICY_ACCOUNT_DOMAIN_INFO DomainInfo = NULL;
|
|
|
|
TraceFunctEnter("GetDefaultDomainName");
|
|
|
|
//
|
|
// 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 ) ) {
|
|
DebugTrace(0,"cannot open lsa policy, error %08lX\n",NtStatus );
|
|
err = LsaNtStatusToWinError( NtStatus );
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Query the domain information from the policy object.
|
|
//
|
|
|
|
NtStatus = LsaQueryInformationPolicy( LsaPolicyHandle,
|
|
PolicyAccountDomainInformation,
|
|
(PVOID *)&DomainInfo );
|
|
|
|
if ( !NT_SUCCESS( NtStatus ) ) {
|
|
DebugTrace(0,"cannot query lsa policy info, error %08lX\n",NtStatus );
|
|
err = LsaNtStatusToWinError( NtStatus );
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Compute the required length of the ANSI name.
|
|
//
|
|
|
|
Result = WideCharToMultiByte( CP_ACP,
|
|
0, // dwFlags
|
|
(LPCWSTR)DomainInfo->DomainName.Buffer,
|
|
DomainInfo->DomainName.Length /sizeof(WCHAR),
|
|
NULL, // lpMultiByteStr
|
|
0, // cchMultiByte
|
|
NULL, // lpDefaultChar
|
|
NULL // lpUsedDefaultChar
|
|
);
|
|
|
|
if ( Result <= 0 ) {
|
|
err = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Resize the output string as appropriate, including room for the
|
|
// terminating '\0'.
|
|
//
|
|
|
|
if ( !pstrDomainName->Resize( (UINT)Result + 1 ) ) {
|
|
err = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Convert the name from UNICODE to ANSI.
|
|
//
|
|
|
|
Result = WideCharToMultiByte( CP_ACP,
|
|
0, // flags
|
|
(LPCWSTR)DomainInfo->DomainName.Buffer,
|
|
DomainInfo->DomainName.Length /sizeof(WCHAR),
|
|
pstrDomainName->QueryStr(),
|
|
pstrDomainName->QuerySize() - 1, // for '\0'
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if ( Result <= 0 ) {
|
|
err = GetLastError();
|
|
|
|
DebugTrace(0,"cannot convert domain name to ANSI, error %d\n",err );
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Ensure the ANSI string is zero terminated.
|
|
//
|
|
|
|
_ASSERT( (DWORD)Result < pstrDomainName->QuerySize() );
|
|
|
|
pstrDomainName->QueryStr()[Result] = '\0';
|
|
|
|
//
|
|
// Success!
|
|
//
|
|
|
|
_ASSERT( err == 0 );
|
|
|
|
DebugTrace(0,"GetDefaultDomainName: default domain = %s\n",pstrDomainName->QueryStr() );
|
|
|
|
Cleanup:
|
|
|
|
if ( DomainInfo != NULL ) {
|
|
LsaFreeMemory( (PVOID)DomainInfo );
|
|
}
|
|
|
|
if ( LsaPolicyHandle != NULL ) {
|
|
LsaClose( LsaPolicyHandle );
|
|
}
|
|
|
|
return err;
|
|
|
|
} // GetDefaultDomainName()
|
|
|
|
DWORD
|
|
SMTP_SERVER_INSTANCE::ReadAuthentInfo(void)
|
|
|
|
/*++
|
|
|
|
Reads per-instance authentication info from the metabase.
|
|
|
|
Arguments:
|
|
|
|
ReadAll - If TRUE, then all authentication related items are
|
|
read from the metabase. If FALSE, then only a single item
|
|
is read.
|
|
|
|
SingleItemToRead - The single authentication item to read if
|
|
ReadAll is FALSE. Ignored if ReadAll is TRUE.
|
|
|
|
Notify - If TRUE, this is a MB notification
|
|
|
|
Returns:
|
|
|
|
DWORD - 0 if successful, !0 otherwise.
|
|
|
|
--*/
|
|
{
|
|
|
|
DWORD err = NO_ERROR;
|
|
BOOL rebuildAcctDesc = FALSE;
|
|
TCP_AUTHENT_INFO* pTcpAuthentInfo = NULL;
|
|
MB mb( (IMDCOM*)g_pInetSvc->QueryMDObject() );
|
|
|
|
TraceFunctEnter("SMTP_SERVER_INSTANCE::ReadAuthentInfo");
|
|
|
|
//
|
|
// Lock our configuration (since we'll presumably be making changes)
|
|
// and open the metabase.
|
|
//
|
|
m_GenLock.ExclusiveLock();
|
|
|
|
|
|
if ( !mb.Open( QueryMDPath() ) ) {
|
|
err = GetLastError();
|
|
DebugTrace(0,"ReadAuthentInfo: cannot open metabase, error %lx\n",err);
|
|
m_GenLock.ExclusiveUnlock();
|
|
return ERROR_PATH_NOT_FOUND;
|
|
}
|
|
|
|
pTcpAuthentInfo = &m_TcpAuthentInfo ;
|
|
|
|
//
|
|
// Read the anonymous username if necessary. Note this is a REQUIRED
|
|
// property. If it is missing from the metabase, bail.
|
|
//
|
|
|
|
|
|
if ( mb.GetStr("",MD_ANONYMOUS_USER_NAME, IIS_MD_UT_SERVER,&(pTcpAuthentInfo->strAnonUserName)
|
|
) ) {
|
|
|
|
rebuildAcctDesc = TRUE;
|
|
|
|
} else {
|
|
|
|
err = GetLastError();
|
|
DebugTrace(0,"ReadAuthentInfo: cannot read MD_ANONYMOUS_USER_NAME, error %lx\n",err);
|
|
|
|
}
|
|
|
|
//
|
|
// Read the "use subauthenticator" flag if necessary. This is an
|
|
// optional property.
|
|
//
|
|
|
|
if ( err == NO_ERROR) {
|
|
(pTcpAuthentInfo->fDontUseAnonSubAuth) = ReadMetabaseDword (mb, MD_ANONYMOUS_USE_SUBAUTH, DEFAULT_USE_SUBAUTH);
|
|
}
|
|
|
|
//
|
|
// Read the anonymous password if necessary. This is an optional
|
|
// property.
|
|
//
|
|
|
|
if ( err == NO_ERROR ) {
|
|
|
|
if ( mb.GetStr(
|
|
"",
|
|
MD_ANONYMOUS_PWD,
|
|
IIS_MD_UT_SERVER,
|
|
&(pTcpAuthentInfo->strAnonUserPassword),
|
|
METADATA_INHERIT,
|
|
DEFAULT_ANONYMOUS_PWD
|
|
) ) {
|
|
|
|
rebuildAcctDesc = TRUE;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Since we provided a default value to mb.GetStr(), it should
|
|
// only fail if something catastrophic occurred, such as an
|
|
// out of memory condition.
|
|
//
|
|
|
|
err = GetLastError();
|
|
DebugTrace(0,"ReadAuthentInfo: cannot read MD_ANONYMOUS_PWD, error %lx\n",err);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Read the default logon domain if necessary. This is an optional
|
|
// property.
|
|
//
|
|
|
|
if ( err == NO_ERROR ) {
|
|
|
|
if ( !mb.GetStr(
|
|
"",
|
|
MD_DEFAULT_LOGON_DOMAIN,
|
|
IIS_MD_UT_SERVER,
|
|
&(pTcpAuthentInfo->strDefaultLogonDomain)
|
|
) ) {
|
|
|
|
//
|
|
// Generate a default domain name.
|
|
//
|
|
|
|
err = GetDefaultDomainName( &(pTcpAuthentInfo->strDefaultLogonDomain) );
|
|
|
|
if ( err != NO_ERROR ) {
|
|
|
|
DebugTrace(0,"ReadAuthentInfo: cannot get default domain name, error %d\n",err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Read the logon method if necessary. This is an optional property.
|
|
//
|
|
|
|
if ( err == NO_ERROR) {
|
|
pTcpAuthentInfo->dwLogonMethod = ReadMetabaseDword (mb, MD_LOGON_METHOD, DEFAULT_LOGON_METHOD);
|
|
}
|
|
|
|
//
|
|
// If anything changed that could affect the anonymous account
|
|
// descriptor, then rebuild the descriptor.
|
|
//
|
|
|
|
if ( err == NO_ERROR && rebuildAcctDesc ) {
|
|
|
|
if ( !BuildAnonymousAcctDesc( pTcpAuthentInfo ) ) {
|
|
|
|
DebugTrace(0,"ReadAuthentInfo: BuildAnonymousAcctDesc() failed\n");
|
|
err = ERROR_NOT_ENOUGH_MEMORY; // SWAG
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m_GenLock.ExclusiveUnlock();
|
|
return err;
|
|
|
|
} // SMTP_SERVER_INSTANCE::ReadAuthentInfo
|
|
|
|
//+---------------------------------------------------------------
|
|
//
|
|
// Function: SMTPCONFIG::ReadRegParams
|
|
//
|
|
// Synopsis: Reads parameters from the registry into the config
|
|
// class member variables and IServer (m_InstancePropertyBag)
|
|
//
|
|
// Arguments: FIELD_CONTROL: Bit-field defining what params to
|
|
// read.
|
|
//
|
|
// Returns: BOOL - TRUE on SUCCESS, FALSE on FAIL
|
|
//
|
|
// Note: BOOL fInit argument removed by KeithLau on 7/15/96
|
|
//
|
|
//----------------------------------------------------------------
|
|
BOOL SMTP_SERVER_INSTANCE::ReadRegParams(
|
|
FIELD_CONTROL fc, BOOL fRebuild, BOOL fShowEvents)
|
|
{
|
|
BOOL fRet = TRUE;
|
|
DWORD dwErr = NO_ERROR;
|
|
DWORD dwAttr;
|
|
DWORD dwLen;
|
|
DWORD dwTempVar;
|
|
DWORD dwAqueueWait = 0;
|
|
MB mb( (IMDCOM*)g_pInetSvc->QueryMDObject() );
|
|
char ScratchBuffer [400];
|
|
STR TempString;
|
|
const CHAR * apszSubStrings[4];
|
|
CHAR pchAddr1[32] = "";
|
|
AQConfigInfo AQConfig;
|
|
HRESULT hr;
|
|
|
|
char szDomainName[MAX_PATH + 1] = {0};
|
|
|
|
TraceFunctEnterEx((LPARAM)this, "SMTPCONFIG::SMTP_SERVER_INSTANCE");
|
|
|
|
SetLastError(NO_ERROR);
|
|
|
|
m_fDefaultInRt = FALSE;
|
|
|
|
ZeroMemory(&AQConfig, sizeof(AQConfig));
|
|
|
|
// Make sure we've got a valid field control input
|
|
_ASSERT(fc != 0 && !(fc & ~(FC_SMTP_INFO_ALL)));
|
|
|
|
m_GenLock.ExclusiveLock();
|
|
|
|
_itoa(QueryInstanceId(), pchAddr1, 10);
|
|
|
|
//
|
|
// Read metabase data.
|
|
//
|
|
|
|
if ( !mb.Open( QueryMDPath(), METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE) ) {
|
|
m_GenLock.ExclusiveUnlock();
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
if (IsFieldSet(fc, FC_SMTP_INFO_ROUTING)) {
|
|
GetCatInfo(mb, AQConfig);
|
|
}
|
|
|
|
ZeroMemory(&AQConfig, sizeof(AQConfig));
|
|
|
|
if (IsFieldSet(fc, FC_SMTP_INFO_REVERSE_LOOKUP)) {
|
|
dwTempVar = 0;
|
|
dwTempVar = ReadMetabaseDword(mb, MD_REVERSE_NAME_LOOKUP, 0);
|
|
|
|
// If the value is changing, generate an information NT event...
|
|
if (dwTempVar != m_RDNSOptions) {
|
|
apszSubStrings[0] = pchAddr1;
|
|
|
|
if (fShowEvents) {
|
|
if (dwTempVar)
|
|
SmtpLogEvent(SMTP_EVENT_SET_REVERSE_LOOKUP_ENABLED, 1, apszSubStrings, 0);
|
|
else
|
|
SmtpLogEvent(SMTP_EVENT_SET_REVERSE_LOOKUP_DISABLED, 1, apszSubStrings, 0);
|
|
}
|
|
|
|
m_RDNSOptions = dwTempVar;
|
|
|
|
StateTrace((LPARAM)this, "m_fEnableReverseLookup = %u", m_RDNSOptions);
|
|
}
|
|
}
|
|
|
|
//I am isung this for all commands
|
|
if (IsFieldSet(fc, FC_SMTP_INFO_INBOUND_SUPPORT_OPTIONS)) {
|
|
m_InboundCmdOptions = ReadMetabaseDword(mb, MD_INBOUND_COMMAND_SUPPORT_OPTIONS, SMTP_DEFAULT_CMD_SUPPORT);
|
|
m_OutboundCmdOptions = ReadMetabaseDword(mb, MD_OUTBOUND_COMMAND_SUPPORT_OPTIONS, SMTP_DEFAULT_OUTBOUND_SUPPORT);
|
|
|
|
m_fAddNoHdrs = !!ReadMetabaseDword(mb, MD_ADD_NOHEADERS, FALSE);
|
|
}
|
|
|
|
if (IsFieldSet(fc, FC_SMTP_INFO_SSL_PERM)) {
|
|
|
|
BOOL fRequiresCertVerifySubject;
|
|
BOOL fRequiresCertVerifyIssuer;
|
|
|
|
fRequiresCertVerifyIssuer =
|
|
ReadMetabaseDword (mb, MD_SMTP_SSL_REQUIRE_TRUSTED_CA, FALSE);
|
|
|
|
fRequiresCertVerifySubject =
|
|
ReadMetabaseDword (mb, MD_SMTP_SSL_CERT_HOSTNAME_VALIDATION, FALSE);
|
|
|
|
m_fRequiresCertVerifySubject = fRequiresCertVerifySubject;
|
|
m_fRequiresCertVerifyIssuer = fRequiresCertVerifyIssuer;
|
|
|
|
BOOL fRequiresSSL, fRequires128Bits;
|
|
|
|
dwTempVar = ReadMetabaseDword(mb, MD_SSL_ACCESS_PERM, FALSE);
|
|
|
|
fRequiresSSL = IsFieldSet(dwTempVar, MD_ACCESS_SSL);
|
|
fRequires128Bits = IsFieldSet(dwTempVar, MD_ACCESS_SSL128);
|
|
|
|
apszSubStrings[0] = pchAddr1;
|
|
|
|
// If the value is changing, generate an information NT event...
|
|
if (fShowEvents && (fRequiresSSL != m_fRequiresSSL)) {
|
|
SmtpLogEvent(
|
|
fRequiresSSL ?
|
|
SMTP_EVENT_REQUIRE_SSL_INBOUND_ENABLE :
|
|
SMTP_EVENT_REQUIRE_SSL_INBOUND_DISABLE, 1, apszSubStrings, 0);
|
|
}
|
|
m_fRequiresSSL = fRequiresSSL;
|
|
|
|
if (fShowEvents && (fRequires128Bits != m_fRequires128Bits)) {
|
|
SmtpLogEvent(
|
|
fRequires128Bits ?
|
|
SMTP_EVENT_REQUIRE_128BIT_SSL_INBOUND_ENABLE :
|
|
SMTP_EVENT_REQUIRE_128BIT_SSL_INBOUND_DISABLE, 1, apszSubStrings, 0);
|
|
}
|
|
m_fRequires128Bits = fRequires128Bits;
|
|
|
|
StateTrace((LPARAM)this,
|
|
"m_fRequiresSSL = %s, m_fRequires128Bits = %s",
|
|
m_fRequiresSSL ? "TRUE" : "FALSE",
|
|
m_fRequires128Bits ? "TRUE" : "FALSE");
|
|
|
|
}
|
|
|
|
if (IsFieldSet(fc, FC_SMTP_INFO_COMMON_PARAMS)) {
|
|
DWORD dwDomainValidationFlags = 0;
|
|
DWORD dwNameResolution = 0;
|
|
|
|
m_dwDnsFlags = ReadMetabaseDword(mb, MD_SMTP_USE_TCP_DNS, 0);
|
|
|
|
m_dwNameResolution = ReadMetabaseDword(mb, MD_NAME_RESOLUTION_TYPE, 1);
|
|
|
|
StateTrace((LPARAM)this, "m_dwNameResolution = %u", m_dwNameResolution);
|
|
|
|
m_cMaxBatchLimit = ReadMetabaseDword(mb, MD_BATCH_MSG_LIMIT, 20);
|
|
|
|
AQConfig.cMinMessagesPerConnection = m_cMaxBatchLimit;
|
|
AQConfig.dwAQConfigInfoFlags |= AQ_CONFIG_INFO_MIN_MSG;
|
|
|
|
AQConfig.dwConnectionWaitMilliseconds = ReadMetabaseDword(mb, MD_SMTP_AQUEUE_WAIT, 60000);
|
|
//AQConfig.dwConnectionWaitMilliseconds = INFINITE;
|
|
|
|
AQConfig.dwAQConfigInfoFlags |= AQ_CONFIG_INFO_CON_WAIT;
|
|
|
|
StateTrace((LPARAM)this, "m_cMaxBatchLimit = %u", m_cMaxBatchLimit);
|
|
|
|
m_fRelayForAuthUsers = !!ReadMetabaseDword(mb, MD_SMTP_RELAY_FOR_AUTH_USERS, TRUE);
|
|
|
|
m_fIsRelayEnabled = !!ReadMetabaseDword(mb, MD_SMTP_DISABLE_RELAY, TRUE);
|
|
m_fHelloNoDomain = !!ReadMetabaseDword(mb, MD_SMTP_HELO_NODOMAIN, TRUE);
|
|
m_fMailFromNoHello = !!ReadMetabaseDword(mb, MD_SMTP_MAIL_NO_HELO, FALSE);
|
|
|
|
//Per spec these two are related
|
|
if (m_fMailFromNoHello)
|
|
m_fHelloNoDomain = TRUE;
|
|
|
|
m_fNagleIn = !!ReadMetabaseDword(mb, MD_SMTP_INBOUND_NAGLE, FALSE);
|
|
m_fNagleOut = !!ReadMetabaseDword(mb, MD_SMTP_OUTBOUND_NAGLE, FALSE);
|
|
|
|
dwDomainValidationFlags = !!ReadMetabaseDword(mb, MD_DOMAIN_VALIDATION_FLAGS, 0);
|
|
m_fHelloNoValidate = dwDomainValidationFlags & SMTP_NOVALIDATE_EHLO;
|
|
m_fMailNoValidate = dwDomainValidationFlags & SMTP_NOVALIDATE_MAIL;
|
|
m_fRcptNoValidate = dwDomainValidationFlags & SMTP_NOVALIDATE_RCPT;
|
|
m_fEtrnNoValidate = dwDomainValidationFlags & SMTP_NOVALIDATE_ETRN;
|
|
m_fPickupNoValidate = dwDomainValidationFlags & SMTP_NOVALIDATE_PKUP;
|
|
|
|
ReadRouteDomainIpSecList(mb);
|
|
// Raid 174038
|
|
m_fDisablePickupDotStuff = !!ReadMetabaseDword(mb, MD_SMTP_DISABLE_PICKUP_DOT_STUFF, FALSE);
|
|
StateTrace((LPARAM)this, "m_fDisablePickupDotStuff = %u", m_fDisablePickupDotStuff);
|
|
m_dwEventlogLevel = ReadMetabaseDword(mb,
|
|
MD_SMTP_EVENTLOG_LEVEL,
|
|
LOGEVENT_LEVEL_MEDIUM);
|
|
|
|
}
|
|
|
|
if (IsFieldSet(fc, FC_SMTP_INFO_MAX_OUT_CONN_PER_DOMAIN)) {
|
|
dwTempVar = ReadMetabaseDword(mb, MD_MAX_OUT_CONN_PER_DOMAIN, 20);
|
|
|
|
if (fShowEvents && (dwTempVar != m_cMaxOutConnectionsPerDomain)) {
|
|
_itoa(dwTempVar, ScratchBuffer, 10);
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = ScratchBuffer;
|
|
SmtpLogEvent(SMTP_EVENT_SET_MAX_CONN_PER_DOMAIN, 2, apszSubStrings, 0);
|
|
}
|
|
|
|
m_cMaxOutConnectionsPerDomain = dwTempVar;
|
|
AQConfig.dwAQConfigInfoFlags |= AQ_CONFIG_INFO_MAX_LINK;
|
|
AQConfig.cMaxLinkConnections = dwTempVar;
|
|
|
|
StateTrace((LPARAM)this, "m_cMaxOutConnectionsPerDomain = %u", m_cMaxOutConnectionsPerDomain);
|
|
}
|
|
|
|
if (IsFieldSet(fc, FC_SMTP_INFO_AUTHORIZATION)) {
|
|
m_dwAuth = ReadMetabaseDword(mb, MD_AUTHORIZATION, DEFAULT_AUTHENTICATION);
|
|
DebugTrace((LPARAM)this, "m_dwAuth=%u", m_dwAuth);
|
|
}
|
|
|
|
//
|
|
// update the following data members:
|
|
// m_ProviderPackages
|
|
// m_ProviderNames
|
|
// m_cProviderPackages
|
|
if (IsFieldSet(fc, FC_SMTP_INFO_NTAUTHENTICATION_PROVIDERS)) {
|
|
CHAR szAuthPack[MAX_PATH + 1];
|
|
DWORD dwLen;
|
|
|
|
TempString.Reset();
|
|
|
|
if (mb.GetStr("", MD_NTAUTHENTICATION_PROVIDERS, IIS_MD_UT_SERVER, &TempString, METADATA_INHERIT, "")) {
|
|
lstrcpyn(szAuthPack, TempString.QueryStr(), MAX_PATH);
|
|
dwLen = lstrlen(szAuthPack);
|
|
DebugTrace((LPARAM)this, "Authentication packages=%s", szAuthPack);
|
|
if (!ConvertToMultisz(m_ProviderNames, &m_cProviderPackages, szAuthPack)) {
|
|
CopyMemory(m_ProviderNames, pszPackagesDefault, ccbPackagesDefault);
|
|
m_cProviderPackages = 2;
|
|
}
|
|
} else {
|
|
DebugTrace((LPARAM)this, "Use default authentication packages=%s", pszPackagesDefault);
|
|
CopyMemory(m_ProviderNames, pszPackagesDefault, ccbPackagesDefault);
|
|
m_cProviderPackages = 1;
|
|
}
|
|
|
|
// set the AUTH_BLOCK info
|
|
if (!SetProviderPackages()) {
|
|
ErrorTrace((LPARAM)this, "Unable to allocate AUTH_BLOCK");
|
|
}
|
|
}
|
|
|
|
if (IsFieldSet(fc, FC_SMTP_INFO_SASL_LOGON_DOMAIN)) {
|
|
TempString.Reset();
|
|
|
|
if (mb.GetStr("", MD_SASL_LOGON_DOMAIN, IIS_MD_UT_SERVER, &TempString, METADATA_INHERIT, "")) {
|
|
lstrcpyn(m_szDefaultLogonDomain, TempString.QueryStr(), MAX_SERVER_NAME_LEN);
|
|
DebugTrace((LPARAM)this, "SASL logon domain =%s", m_szDefaultLogonDomain);
|
|
} else {
|
|
m_szDefaultLogonDomain[0] = '\0';
|
|
DebugTrace((LPARAM)this, "no SASL default logon domain was found");
|
|
}
|
|
}
|
|
|
|
if (IsFieldSet(fc, FC_SMTP_CLEARTEXT_AUTH_PROVIDER)) {
|
|
TempString.Reset();
|
|
|
|
m_cbCleartextAuthPackage = sizeof(m_szCleartextAuthPackage);
|
|
if (mb.GetStr("", MD_SMTP_CLEARTEXT_AUTH_PROVIDER, IIS_MD_UT_SERVER, &TempString, METADATA_INHERIT, "")) {
|
|
lstrcpy(m_szCleartextAuthPackage, TempString.QueryStr());
|
|
m_cbCleartextAuthPackage = lstrlen(m_szCleartextAuthPackage) + 1;
|
|
|
|
StateTrace((LPARAM)this, "Cleartext authentication provider: <%s>, length %u",
|
|
m_szCleartextAuthPackage,
|
|
m_cbCleartextAuthPackage);
|
|
} else {
|
|
m_szCleartextAuthPackage[0] = '\0';
|
|
m_cbCleartextAuthPackage = 0;
|
|
StateTrace((LPARAM)this, "No default cleartext authentication provider specified, using CleartextLogon");
|
|
}
|
|
|
|
TempString.Reset();
|
|
|
|
if (mb.GetStr("", MD_MD_SERVER_SS_AUTH_MAPPING, IIS_MD_UT_SERVER, &TempString, METADATA_INHERIT, "")) {
|
|
lstrcpyn(m_szMembershipBroker, TempString.QueryStr(), MAX_PATH);
|
|
StateTrace((LPARAM)this, "Membership Broker name is set to %s", m_szMembershipBroker);
|
|
} else {
|
|
m_szMembershipBroker[0] = '\0';
|
|
StateTrace((LPARAM)this, "No Membership Broker name configured");
|
|
}
|
|
}
|
|
|
|
if (IsFieldSet(fc, FC_SMTP_INFO_MAX_HOP_COUNT)) {
|
|
dwTempVar = ReadMetabaseDword(mb, MD_HOP_COUNT, 15);
|
|
StateTrace((LPARAM)this, "m_cMaxHopCount = %u", dwTempVar);
|
|
|
|
if (fShowEvents && (dwTempVar != m_cMaxHopCount)) {
|
|
_itoa(dwTempVar, ScratchBuffer, 10);
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = ScratchBuffer;
|
|
SmtpLogEvent(SMTP_EVENT_SET_MAX_HOPCOUNT, 2, apszSubStrings, 0);
|
|
}
|
|
|
|
m_cMaxHopCount = dwTempVar;
|
|
}
|
|
|
|
if (IsFieldSet(fc, FC_SMTP_INFO_REMOTE_PORT)) {
|
|
dwTempVar = ReadMetabaseDword(mb, MD_REMOTE_SMTP_PORT, 25);
|
|
if (fShowEvents && (dwTempVar != m_RemoteSmtpPort)) {
|
|
_itoa(dwTempVar, ScratchBuffer, 10);
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = ScratchBuffer;
|
|
SmtpLogEvent(SMTP_EVENT_SET_REMOTE_PORT, 2, apszSubStrings, 0);
|
|
}
|
|
|
|
m_RemoteSmtpPort = dwTempVar;
|
|
|
|
StateTrace((LPARAM)this, "m_RemoteSmtpPort = %u", m_RemoteSmtpPort);
|
|
}
|
|
|
|
if (IsFieldSet(fc, FC_SMTP_INFO_MAX_ERRORS)) {
|
|
dwTempVar = ReadMetabaseDword(mb, MD_MAX_SMTP_ERRORS, 10);
|
|
if (dwTempVar == 0)
|
|
dwTempVar = 10;
|
|
|
|
if (fShowEvents && (dwTempVar != m_cMaxErrors)) {
|
|
_itoa(dwTempVar, ScratchBuffer, 10);
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = ScratchBuffer;
|
|
SmtpLogEvent(SMTP_EVENT_SET_MAX_ERRORS, 2, apszSubStrings, 0);
|
|
}
|
|
|
|
m_cMaxErrors = dwTempVar;
|
|
StateTrace((LPARAM)this, "m_cMaxErrors = %u", m_cMaxErrors);
|
|
|
|
dwTempVar = ReadMetabaseDword(mb, MD_MAX_SMTP_AUTHLOGON_ERRORS, 4);
|
|
if (dwTempVar == 0)
|
|
dwTempVar = 4;
|
|
|
|
if (fShowEvents && (dwTempVar != m_dwMaxLogonFailures)) {
|
|
//_itoa(dwTempVar, ScratchBuffer, 10);
|
|
// apszSubStrings[0] = pchAddr1;
|
|
// apszSubStrings[1] = ScratchBuffer;
|
|
//SmtpLogEvent(SMTP_EVENT_SET_MAX_ERRORS, 2, apszSubStrings, 0);
|
|
|
|
}
|
|
|
|
m_dwMaxLogonFailures = dwTempVar;
|
|
StateTrace((LPARAM)this, "m_dwMaxLogonFailures = %u", m_dwMaxLogonFailures);
|
|
}
|
|
|
|
if (IsFieldSet(fc, FC_SMTP_INFO_MAX_SIZE)) {
|
|
dwTempVar = ReadMetabaseDword(mb, MD_MAX_MSG_SIZE, 2 * 1024);
|
|
|
|
if (fShowEvents && (dwTempVar != m_cbMaxMsgSize)) {
|
|
_itoa(dwTempVar, ScratchBuffer, 10);
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = ScratchBuffer;
|
|
SmtpLogEvent(SMTP_EVENT_SET_MAX_SIZE_ACCEPTED, 2, apszSubStrings, 0);
|
|
}
|
|
|
|
m_cbMaxMsgSize = dwTempVar;
|
|
StateTrace((LPARAM)this, "m_cbMaxMsgSize = %u", m_cbMaxMsgSize);
|
|
|
|
dwTempVar = ReadMetabaseDword(mb, MD_MAX_MSG_SIZE_B4_CLOSE, 10 * 1024);
|
|
if (fShowEvents && (dwTempVar != m_cbMaxMsgSizeBeforeClose)) {
|
|
_itoa(dwTempVar, ScratchBuffer, 10);
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = ScratchBuffer;
|
|
SmtpLogEvent(SMTP_EVENT_SET_MAX_SIZE_BEFORE_CLOSE, 2, apszSubStrings, 0);
|
|
}
|
|
|
|
m_cbMaxMsgSizeBeforeClose = dwTempVar;
|
|
StateTrace((LPARAM)this, "m_cbMaxMsgSizeBeforeClose = %u", m_cbMaxMsgSizeBeforeClose);
|
|
}
|
|
|
|
if (IsFieldSet(fc, FC_SMTP_INFO_REMOTE_TIMEOUT)) {
|
|
dwTempVar = ReadMetabaseDword(mb, MD_REMOTE_TIMEOUT, 600);
|
|
|
|
if (fShowEvents && (dwTempVar != m_cMaxRemoteTimeOut)) {
|
|
_itoa(dwTempVar, ScratchBuffer, 10);
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = ScratchBuffer;
|
|
SmtpLogEvent(SMTP_EVENT_SET_MAX_REMOTE_TIMEOUT, 2, apszSubStrings, 0);
|
|
}
|
|
|
|
m_cMaxRemoteTimeOut = dwTempVar;
|
|
StateTrace((LPARAM)this, "m_cMaxRemoteTimeOut = %u", m_cMaxRemoteTimeOut);
|
|
|
|
m_ConnectTimeout = ReadMetabaseDword(mb, MD_SMTP_CONNECT_TIMEOUT, 150);
|
|
|
|
if (m_ConnectTimeout == 0)
|
|
m_ConnectTimeout = 1;
|
|
|
|
// Calculate timeout in milliseconds from timeout in seconds.
|
|
m_ConnectTimeout = m_ConnectTimeout * 60 * 1000;
|
|
|
|
m_MailFromTimeout = ReadMetabaseDword(mb, MD_SMTP_MAILFROM_TIMEOUT, 600);
|
|
m_RcptToTimeout = ReadMetabaseDword(mb, MD_SMTP_RCPTTO_TIMEOUT, 600);
|
|
m_DataTimeout = ReadMetabaseDword(mb, MD_SMTP_DATA_TIMEOUT, 600);
|
|
m_AuthTimeout = ReadMetabaseDword(mb, MD_SMTP_AUTH_TIMEOUT, 600);
|
|
m_SaslTimeout = ReadMetabaseDword(mb, MD_SMTP_SASL_TIMEOUT, 600);
|
|
m_HeloTimeout = ReadMetabaseDword(mb, MD_SMTP_HELO_TIMEOUT, 600);
|
|
m_BdatTimeout = ReadMetabaseDword(mb, MD_SMTP_BDAT_TIMEOUT, 600);
|
|
m_TurnTimeout = ReadMetabaseDword(mb, MD_SMTP_TURN_TIMEOUT, 600);
|
|
m_RSetTimeout = ReadMetabaseDword(mb, MD_SMTP_RSET_TIMEOUT, 600);
|
|
m_QuitTimeout = ReadMetabaseDword(mb, MD_SMTP_RSET_TIMEOUT, 600);
|
|
}
|
|
|
|
if (IsFieldSet(fc, FC_SMTP_INFO_MAX_OUTBOUND_CONN)) {
|
|
dwTempVar = ReadMetabaseDword(mb, MD_MAX_OUTBOUND_CONNECTION, 100);
|
|
if (fShowEvents && (dwTempVar != m_cMaxOutConnections)) {
|
|
_itoa(dwTempVar, ScratchBuffer, 10);
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = ScratchBuffer;
|
|
SmtpLogEvent(SMTP_EVENT_SET_MAX_OUTBOUND_CONNECTIONS, 2, apszSubStrings, 0);
|
|
}
|
|
|
|
m_cMaxOutConnections = dwTempVar;
|
|
AQConfig.cMaxConnections = dwTempVar;
|
|
AQConfig.dwAQConfigInfoFlags |= AQ_CONFIG_INFO_MAX_CON;
|
|
|
|
StateTrace((LPARAM)this, "m_cMaxOutConnections = %u", m_cMaxOutConnections);
|
|
}
|
|
|
|
if (IsFieldSet(fc, FC_SMTP_INFO_MAX_RECIPS)) {
|
|
dwTempVar = ReadMetabaseDword(mb, MD_MAX_RECIPIENTS, 100);
|
|
if (fShowEvents && (dwTempVar != m_cMaxRcpts)) {
|
|
_itoa(dwTempVar, ScratchBuffer, 10);
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = ScratchBuffer;
|
|
SmtpLogEvent(SMTP_EVENT_SET_MAX_RECIPIENTS, 2, apszSubStrings, 0);
|
|
}
|
|
|
|
m_cMaxRcpts = dwTempVar;
|
|
StateTrace((LPARAM)this, "m_cMaxRcpts = %u", m_cMaxRcpts);
|
|
}
|
|
|
|
if (IsFieldSet(fc, FC_SMTP_INFO_ETRN_SUBDOMAINS)) {
|
|
m_fAllowEtrnSubDomains = !!ReadMetabaseDword(mb, MD_ETRN_SUBDOMAINS, TRUE);
|
|
StateTrace((LPARAM)this, "m_fAllowEtrnSubDomains = %u", m_fAllowEtrnSubDomains);
|
|
}
|
|
|
|
if (IsFieldSet(fc, FC_SMTP_INFO_RETRY)) {
|
|
DWORD dwTempVar2 = 0;
|
|
char ScratchBuffer2[50];
|
|
|
|
dwTempVar = ReadMetabaseDword(mb, MD_LOCAL_RETRY_ATTEMPTS, 48);
|
|
dwTempVar2 = ReadMetabaseDword(mb, MD_LOCAL_RETRY_MINUTES, 60);
|
|
|
|
if (fShowEvents && ((m_cRetryAttempts != dwTempVar) ||(m_cRetryMinutes != dwTempVar2))) {
|
|
_itoa(dwTempVar, ScratchBuffer, 10);
|
|
_itoa(dwTempVar2, ScratchBuffer2, 10);
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = "Local";
|
|
apszSubStrings[2] = ScratchBuffer;
|
|
apszSubStrings[3] = ScratchBuffer2;
|
|
SmtpLogEvent(SMTP_EVENT_SET_RETRY_PARAMETERS, 4, apszSubStrings, 0);
|
|
}
|
|
|
|
|
|
m_cRetryAttempts = dwTempVar;
|
|
m_cRetryMinutes = dwTempVar2;
|
|
|
|
StateTrace((LPARAM)this, "m_cRetryAttempts = %u", m_cRetryAttempts);
|
|
StateTrace((LPARAM)this, "m_cRetryMinutes = %u", m_cRetryMinutes);
|
|
|
|
dwTempVar = ReadMetabaseDword(mb, MD_REMOTE_RETRY_ATTEMPTS, 48);
|
|
dwTempVar2 = ReadMetabaseDword(mb, MD_REMOTE_RETRY_MINUTES, 60);
|
|
if ( fShowEvents && ((m_cRemoteRetryAttempts != dwTempVar) ||(m_cRemoteRetryMinutes != dwTempVar2))) {
|
|
_itoa(dwTempVar, ScratchBuffer, 10);
|
|
_itoa(dwTempVar2, ScratchBuffer2, 10);
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = "Remote";
|
|
apszSubStrings[2] = ScratchBuffer;
|
|
apszSubStrings[3] = ScratchBuffer2;
|
|
SmtpLogEvent(SMTP_EVENT_SET_RETRY_PARAMETERS, 4, apszSubStrings, 0);
|
|
}
|
|
|
|
m_cRemoteRetryAttempts = dwTempVar;
|
|
m_cRemoteRetryMinutes = dwTempVar2;
|
|
|
|
StateTrace((LPARAM)this, "m_cRetryAttempts = %u", m_cRemoteRetryAttempts);
|
|
StateTrace((LPARAM)this, "m_cRetryMinutes = %u", m_cRemoteRetryMinutes);
|
|
|
|
TempString.Reset();
|
|
|
|
m_cbProgressiveRetryMinutes = sizeof(m_szProgressiveRetryMinutes);
|
|
if (mb.GetStr("", MD_SMTP_REMOTE_PROGRESSIVE_RETRY_MINUTES, IIS_MD_UT_SERVER, &TempString, METADATA_INHERIT, "")) {
|
|
lstrcpy(m_szProgressiveRetryMinutes, TempString.QueryStr());
|
|
m_cbProgressiveRetryMinutes = lstrlen(m_szProgressiveRetryMinutes) + 1;
|
|
|
|
StateTrace((LPARAM)this, "Progressive retry minutes: <%s>, length %u",
|
|
m_szProgressiveRetryMinutes,
|
|
m_cbProgressiveRetryMinutes);
|
|
}
|
|
|
|
//Parse out the string to get at most 4 seperate minute values
|
|
//the values will be part of a comma delimited string
|
|
int cRetryMin[4];
|
|
DWORD i = 0;
|
|
char *szTemp;
|
|
char *Ptr = NULL;
|
|
szTemp = m_szProgressiveRetryMinutes;
|
|
|
|
//Parse out the 4 integers
|
|
for (;i<4;) {
|
|
Ptr = strchr(szTemp,',');
|
|
if (Ptr)
|
|
*Ptr = '\0';
|
|
|
|
cRetryMin[i] = 0;
|
|
cRetryMin[i] = atoi(szTemp);
|
|
if (cRetryMin[i] < 1)
|
|
break;
|
|
i++;
|
|
if (Ptr) {
|
|
*Ptr = ',';
|
|
szTemp = ++Ptr;
|
|
Ptr = NULL;
|
|
} else
|
|
break;
|
|
}
|
|
|
|
//check if could parse nothing
|
|
if (i==0) {
|
|
//dwRetryMin[i] = 60; //defualt retry is 60 minutes
|
|
//NK** for now look at the old value - this way we can set something
|
|
//using MMC
|
|
cRetryMin[i] = m_cRemoteRetryMinutes;
|
|
|
|
i++;
|
|
}
|
|
|
|
//If not all four retry intervals were specified
|
|
//Make the use the last specifed interval in place of unspecified intervals
|
|
while (i<4) {
|
|
cRetryMin[i] = cRetryMin[i - 1];
|
|
i++;
|
|
}
|
|
|
|
AQConfig.dwFirstRetrySeconds = cRetryMin[0] * 60;
|
|
AQConfig.dwSecondRetrySeconds = cRetryMin[1] * 60;
|
|
AQConfig.dwThirdRetrySeconds = cRetryMin[2] * 60;
|
|
AQConfig.dwFourthRetrySeconds = cRetryMin[3] * 60;
|
|
|
|
AQConfig.dwConnectionRetryMilliseconds = (m_cRemoteRetryMinutes*60*1000);
|
|
AQConfig.dwRetryThreshold = ReadMetabaseDword(mb,MD_SMTP_REMOTE_RETRY_THRESHOLD,3);
|
|
if (!AQConfig.dwRetryThreshold)
|
|
AQConfig.dwRetryThreshold = 3;
|
|
StateTrace((LPARAM)this, "RetryThreshold = %u", AQConfig.dwRetryThreshold);
|
|
|
|
AQConfig.dwAQConfigInfoFlags |= AQ_CONFIG_INFO_CON_RETRY;
|
|
|
|
//
|
|
// If DSN intervals are not set, then derive them from the retry intervals
|
|
// 10/6/98 - MikeSwa
|
|
//
|
|
|
|
AQConfig.dwDelayExpireMinutes = ReadMetabaseDword(mb,
|
|
MD_SMTP_EXPIRE_REMOTE_DELAY_MIN, m_cRemoteRetryMinutes);
|
|
AQConfig.dwNDRExpireMinutes = ReadMetabaseDword(mb,
|
|
MD_SMTP_EXPIRE_REMOTE_NDR_MIN,
|
|
m_cRemoteRetryMinutes * m_cRemoteRetryAttempts);
|
|
AQConfig.dwAQConfigInfoFlags |=
|
|
(AQ_CONFIG_INFO_EXPIRE_DELAY |
|
|
AQ_CONFIG_INFO_EXPIRE_NDR);
|
|
|
|
AQConfig.dwLocalDelayExpireMinutes = ReadMetabaseDword(mb,
|
|
MD_SMTP_EXPIRE_LOCAL_DELAY_MIN, m_cRetryMinutes);
|
|
AQConfig.dwLocalNDRExpireMinutes = ReadMetabaseDword(mb,
|
|
MD_SMTP_EXPIRE_LOCAL_NDR_MIN,
|
|
m_cRetryMinutes * m_cRetryAttempts);
|
|
AQConfig.dwAQConfigInfoFlags |=
|
|
(AQ_CONFIG_INFO_LOCAL_EXPIRE_DELAY |
|
|
AQ_CONFIG_INFO_LOCAL_EXPIRE_NDR);
|
|
|
|
}
|
|
|
|
if (IsFieldSet(fc, FC_SMTP_INFO_PIPELINE)) {
|
|
dwTempVar = !!ReadMetabaseDword(mb, MD_SHOULD_PIPELINE_OUT, TRUE);
|
|
if (fShowEvents && ((dwTempVar && !m_fShouldPipelineOut) || (!dwTempVar && m_fShouldPipelineOut))) {
|
|
apszSubStrings[0] = pchAddr1;
|
|
if (dwTempVar)
|
|
SmtpLogEvent(SMTP_EVENT_SET_PIPELINE_OUT_ENABLED, 1, apszSubStrings, 0);
|
|
else
|
|
SmtpLogEvent(SMTP_EVENT_SET_PIPELINE_OUT_DISABLED, 1, apszSubStrings, 0);
|
|
}
|
|
|
|
m_fShouldPipelineOut = dwTempVar;
|
|
StateTrace((LPARAM)this, "m_fShouldPipelineOut = %u", m_fShouldPipelineOut);
|
|
|
|
dwTempVar = !!ReadMetabaseDword(mb, MD_SHOULD_PIPELINE_IN, TRUE);
|
|
if (fShowEvents && ((dwTempVar && !m_fShouldPipelineIn)|| (!dwTempVar && m_fShouldPipelineIn))) {
|
|
apszSubStrings[0] = pchAddr1;
|
|
if (dwTempVar)
|
|
SmtpLogEvent(SMTP_EVENT_SET_PIPELINE_IN_ENABLED, 1, apszSubStrings, 0);
|
|
else
|
|
SmtpLogEvent(SMTP_EVENT_SET_PIPELINE_IN_DISABLED, 1, apszSubStrings, 0);
|
|
|
|
}
|
|
|
|
m_fShouldPipelineIn = dwTempVar;
|
|
StateTrace((LPARAM)this, "m_fShouldPipelineIn = %u", m_fShouldPipelineIn);
|
|
}
|
|
|
|
if (IsFieldSet(fc, FC_SMTP_INFO_SMART_HOST)) {
|
|
dwTempVar = ReadMetabaseDword(mb, MD_SMARTHOST_TYPE, 0);
|
|
StateTrace((LPARAM)this, "m_fSmartHostType = %u", dwTempVar);
|
|
if (dwTempVar != smarthostNone) {
|
|
TempString.Reset();
|
|
|
|
if (! mb.GetStr("", MD_SMARTHOST_NAME, IIS_MD_UT_SERVER, &TempString) ||
|
|
TempString.IsEmpty()) {
|
|
// Don't have a smart host, so turn off smart host and start.
|
|
// Log it though, because the settings conflicted and so somebody
|
|
// probably messed up...
|
|
dwTempVar = m_fSmartHostType = smarthostNone;
|
|
m_szSmartHostName[0] = '\0';
|
|
ErrorTrace((LPARAM)this, "Unable to read smart host name, error %u", dwErr);
|
|
apszSubStrings[0] = pchAddr1;
|
|
SmtpLogEvent(SMTP_EVENT_INVALID_SMART_HOST, 1, apszSubStrings, 0);
|
|
} else {
|
|
if (fShowEvents && lstrcmpi(m_szSmartHostName,TempString.QueryStr())) {
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = TempString.QueryStr();
|
|
SmtpLogEvent(SMTP_EVENT_SET_SMART_HOST_NAME, 2, apszSubStrings, 0);
|
|
}
|
|
|
|
lstrcpyn (m_szSmartHostName,TempString.QueryStr(), MAX_PATH);
|
|
}
|
|
|
|
StateTrace((LPARAM)this, "m_szSmartHost = %s", m_szSmartHostName);
|
|
}
|
|
|
|
// If the value is changing, generate an information NT event...
|
|
if (fShowEvents && (dwTempVar != m_fSmartHostType)) {
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = m_szSmartHostName;
|
|
|
|
switch (dwTempVar) {
|
|
case smarthostNone:
|
|
{
|
|
SmtpLogEvent(SMTP_EVENT_SET_SMART_HOST_TYPE_NONE, 1, apszSubStrings, 0);
|
|
break;
|
|
}
|
|
case smarthostAfterFail:
|
|
{
|
|
SmtpLogEvent(SMTP_EVENT_SET_SMART_HOST_TYPE_AFTER_FAIL,
|
|
2, apszSubStrings, 0);
|
|
break;
|
|
}
|
|
case smarthostAlways:
|
|
{
|
|
SmtpLogEvent(SMTP_EVENT_SET_SMART_HOST_TYPE_ALWAYS,
|
|
2, apszSubStrings, 0);
|
|
break;
|
|
}
|
|
}//end switch
|
|
|
|
}//endf if
|
|
|
|
m_fSmartHostType = dwTempVar;
|
|
}
|
|
|
|
if (IsFieldSet(fc, FC_SMTP_INFO_MASQUERADE)) {
|
|
m_fMasquerade = !!ReadMetabaseDword(mb, MD_DO_MASQUERADE, FALSE);
|
|
StateTrace((LPARAM)this, "m_fSmartHostType = %u", m_fMasquerade);
|
|
if (m_fMasquerade) {
|
|
TempString.Reset();
|
|
|
|
if (! mb.GetStr("", MD_MASQUERADE_NAME, IIS_MD_UT_SERVER, &TempString) ||
|
|
TempString.IsEmpty()) {
|
|
// Don't have a masquerade, so turn off masquerading and start.
|
|
// Log it though, because the settings conflicted and so somebody
|
|
// probably messed up...
|
|
m_fMasquerade = 0;
|
|
m_szMasqueradeName[0] = '\0';
|
|
ErrorTrace((LPARAM)this, "Unable to read masquerade name, error %u", dwErr);
|
|
apszSubStrings[0] = pchAddr1;
|
|
SmtpLogEvent(SMTP_EVENT_INVALID_MASQUERADE, 1, apszSubStrings, 0);
|
|
} else {
|
|
if (fShowEvents && lstrcmpi(m_szMasqueradeName,TempString.QueryStr())) {
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = TempString.QueryStr();
|
|
SmtpLogEvent(SMTP_EVENT_SET_MASQUERADE_NAME, 2, apszSubStrings, 0);
|
|
}
|
|
|
|
lstrcpyn (m_szMasqueradeName,TempString.QueryStr(), AB_MAX_DOMAIN);
|
|
}
|
|
|
|
StateTrace((LPARAM)this, "m_szMasqueradeName = %s", m_szMasqueradeName);
|
|
}
|
|
}
|
|
|
|
|
|
if (IsFieldSet(fc, FC_SMTP_INFO_DEFAULT_DOMAIN)) {
|
|
|
|
m_fDefaultDomainExists = TRUE;
|
|
|
|
TempString.Reset();
|
|
if (! mb.GetStr("", MD_DEFAULT_DOMAIN_VALUE, IIS_MD_UT_SERVER, &TempString)) {
|
|
//
|
|
// we set this value on system start up this is a problem... it should be set.
|
|
//
|
|
lstrcpyn(m_szDefaultDomain, ((SMTP_IIS_SERVICE *) g_pInetSvc)->QueryTcpipName() , MAX_PATH);
|
|
ErrorTrace((LPARAM) this, "Error reading Default Domain from Metabase. Using TcpipValue Name: %s", m_szDefaultDomain);
|
|
}
|
|
|
|
else if (TempString.IsEmpty()) {
|
|
//
|
|
// blow away the value, this will invoke the routine again, and it will be updated
|
|
// with the higher level default. Just in case, put the Instance value in there as a
|
|
// placeholder... just in case.
|
|
//
|
|
|
|
lstrcpyn(m_szDefaultDomain, ((SMTP_IIS_SERVICE *) g_pInetSvc)->QueryTcpipName() , MAX_PATH);
|
|
ErrorTrace((LPARAM) this, "Default Domain was blank string, removing Instance value.");
|
|
|
|
if (! mb.DeleteData("", MD_DEFAULT_DOMAIN_VALUE, IIS_MD_UT_SERVER, STRING_METADATA)) {
|
|
ErrorTrace((LPARAM) this, "Error deleting Default Domain from Metabase. Using TcpipValue Name: %s", m_szDefaultDomain);
|
|
}
|
|
}
|
|
|
|
else {
|
|
lstrcpyn(m_szDefaultDomain,TempString.QueryStr(), sizeof(m_szDefaultDomain));
|
|
|
|
if (fShowEvents) {
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = m_szDefaultDomain;
|
|
|
|
// If the value is changing, generate an information NT event...
|
|
SmtpLogEvent(SMTP_EVENT_SET_DEFAULT_DOMAIN, 2, apszSubStrings, 0);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Inform aqueue of the default domain
|
|
//
|
|
AQConfig.szDefaultLocalDomain = m_szDefaultDomain;
|
|
AQConfig.dwAQConfigInfoFlags |= AQ_CONFIG_INFO_DEFAULT_DOMAIN;
|
|
ErrorTrace((LPARAM)this , "Default domain is %s", m_szDefaultDomain);
|
|
}
|
|
|
|
|
|
if (IsFieldSet(fc, FC_SMTP_INFO_FQDN)) {
|
|
|
|
TempString.Reset();
|
|
if (! mb.GetStr("", MD_FQDN_VALUE, IIS_MD_UT_SERVER, &TempString)) {
|
|
//
|
|
// We set this value on system start up - see main.cxx,
|
|
// InitializeService
|
|
// This is a problem... it should be set.
|
|
//
|
|
lstrcpyn(m_szFQDomainName, ((SMTP_IIS_SERVICE *) g_pInetSvc)->QueryTcpipName(), MAX_PATH);
|
|
ErrorTrace((LPARAM) this, "Error reading FQDN value from Metabase. Using TcpipValue Name: %s", m_szFQDomainName);
|
|
} else if (TempString.IsEmpty()) {
|
|
//
|
|
// blow away the value, this will invoke the routine again, and it will be updated
|
|
// with the higher level default. Just in case, put the Instance value in there as a
|
|
// placeholder... just in case.
|
|
//
|
|
|
|
lstrcpyn(m_szFQDomainName, ((SMTP_IIS_SERVICE *) g_pInetSvc)->QueryTcpipName() , MAX_PATH);
|
|
ErrorTrace((LPARAM) this, "FQDN Value was blank string, removing Instance value.");
|
|
|
|
if (! mb.DeleteData("", MD_FQDN_VALUE, IIS_MD_UT_SERVER, STRING_METADATA)) {
|
|
ErrorTrace((LPARAM) this, "Error reading FQDN value from Metabase. Using TcpipValue Name: %s", m_szFQDomainName);
|
|
}
|
|
}
|
|
|
|
else {
|
|
|
|
lstrcpyn(m_szFQDomainName,TempString.QueryStr(),
|
|
sizeof(m_szFQDomainName));
|
|
|
|
//
|
|
// Register the SPNs for this virtual server. Currently, we ignore
|
|
// errors here.
|
|
//
|
|
|
|
if (!RegisterServicePrincipalNames(FALSE)) {
|
|
|
|
ErrorTrace((LPARAM) this, "Unable to register Kerberos SPNs %d, will try later",
|
|
GetLastError());
|
|
|
|
}
|
|
}
|
|
|
|
//VerifyFQDNWithBindings();
|
|
|
|
AQConfig.szServerFQDN = m_szFQDomainName;
|
|
AQConfig.dwAQConfigInfoFlags |= AQ_CONFIG_INFO_SERVER_FQDN;
|
|
|
|
ErrorTrace((LPARAM)this , "Fully qualified domain name is %s", m_szFQDomainName);
|
|
}
|
|
|
|
|
|
|
|
if (IsFieldSet(fc, FC_SMTP_INFO_SEND_TO_ADMIN)) {
|
|
char * DomainOffset = NULL;
|
|
DWORD NameSize = 0;
|
|
|
|
TempString.Reset();
|
|
|
|
if (! mb.GetStr("", MD_SEND_NDR_TO, IIS_MD_UT_SERVER, &TempString) ||
|
|
TempString.IsEmpty()) {
|
|
m_fSendNDRToAdmin = FALSE;
|
|
m_AdminName[0] = '\0';
|
|
ErrorTrace((LPARAM)this, "Unable to read admin name, error %u", dwErr);
|
|
} else {
|
|
lstrcpyn (m_AdminName,TempString.QueryStr(), MAX_INTERNET_NAME);
|
|
DomainOffset = strchr(m_AdminName, '@');
|
|
if (CAddr::ValidateCleanEmailName(m_AdminName, DomainOffset)) {
|
|
m_fSendNDRToAdmin = TRUE;
|
|
if (DomainOffset == NULL) {
|
|
lstrcat(m_AdminName, "@");
|
|
lstrcat(m_AdminName, m_szDefaultDomain);
|
|
}
|
|
} else {
|
|
ErrorTrace((LPARAM)this, "Unable to read admin name, error %u", dwErr);
|
|
m_AdminName[0] = '\0';
|
|
m_fSendNDRToAdmin = FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
StateTrace((LPARAM)this, "m_AdminName = %s", m_AdminName);
|
|
|
|
if (fShowEvents && m_fSendNDRToAdmin) {
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = m_AdminName;
|
|
SmtpLogEvent(SMTP_EVENT_SET_SEND_NDR_TO_ADMIN_ENABLED, 2, apszSubStrings, 0);
|
|
} else if (fShowEvents && !m_fSendNDRToAdmin) {
|
|
apszSubStrings[0] = pchAddr1;
|
|
SmtpLogEvent(SMTP_EVENT_SET_SEND_NDR_TO_ADMIN_DISABLED, 1, apszSubStrings, 0);
|
|
}
|
|
|
|
DomainOffset = NULL;
|
|
NameSize = 0;
|
|
|
|
TempString.Reset();
|
|
|
|
if (! mb.GetStr("", MD_SEND_BAD_TO, IIS_MD_UT_SERVER, &TempString) ||
|
|
TempString.IsEmpty()) {
|
|
m_fSendBadToAdmin = FALSE;
|
|
m_BadMailName[0] = '\0';
|
|
ErrorTrace((LPARAM)this, "Unable to read badmail email name, error %u", dwErr);
|
|
} else {
|
|
lstrcpyn(m_BadMailName,TempString.QueryStr(), MAX_INTERNET_NAME);
|
|
DomainOffset = strchr(m_BadMailName, '@');
|
|
|
|
if (CAddr::ValidateCleanEmailName(m_BadMailName, DomainOffset)) {
|
|
m_fSendBadToAdmin = TRUE;
|
|
if (DomainOffset == NULL) {
|
|
lstrcat(m_BadMailName, "@");
|
|
lstrcat(m_BadMailName, m_szDefaultDomain);
|
|
}
|
|
} else {
|
|
m_fSendBadToAdmin = FALSE;
|
|
m_BadMailName[0] = '\0';
|
|
ErrorTrace((LPARAM)this, "Unable to read badmail email name, error %u", dwErr);
|
|
}
|
|
}
|
|
|
|
StateTrace((LPARAM)this, "m_BadMailName = %s", m_BadMailName);
|
|
|
|
if (fShowEvents && m_fSendBadToAdmin) {
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = m_BadMailName;
|
|
SmtpLogEvent(SMTP_EVENT_SET_SEND_BAD_TO_ADMIN_ENABLED, 2, apszSubStrings, 0);
|
|
} else if (fShowEvents && !m_fSendBadToAdmin) {
|
|
apszSubStrings[0] = pchAddr1;
|
|
SmtpLogEvent(SMTP_EVENT_SET_SEND_BAD_TO_ADMIN_DISABLED, 1, apszSubStrings, 0);
|
|
}
|
|
|
|
}
|
|
|
|
if (IsFieldSet(fc, FC_SMTP_INFO_DEFAULT_DROP_DIR)) {
|
|
TempString.Reset();
|
|
|
|
if (! mb.GetStr("", MD_MAIL_DROP_DIR, IIS_MD_UT_SERVER, &TempString, 0) ||
|
|
TempString.IsEmpty()) {
|
|
// We had a problem reading the metabase.
|
|
// This is a very bad thing.
|
|
m_szMailDropDir[0] = '\0';
|
|
m_cchMailDropDir = 0;
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = szMailDropDir;
|
|
SmtpLogEvent(SMTP_EVENT_INVALID_MAIL_DROP_DIR, 2, apszSubStrings, 0);
|
|
} else {
|
|
lstrcpyn(m_szMailDropDir, TempString.QueryStr(), MAX_PATH);
|
|
|
|
if (fShowEvents) {
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = m_szMailDropDir;
|
|
SmtpLogEvent(SMTP_EVENT_SET_MAIL_DROP_DIR, 2, apszSubStrings, dwErr);
|
|
}
|
|
|
|
// We found a path in the reg, so see if we can use it...
|
|
dwAttr = GetFileAttributes(m_szMailDropDir);
|
|
if (dwAttr == 0xFFFFFFFF) {
|
|
// The path doesn't exist yet, so we'll try to create it.
|
|
if (!CreateLayerDirectory(m_szMailDropDir) && (dwErr = GetLastError()) != ERROR_ALREADY_EXISTS) {
|
|
ErrorTrace((LPARAM)this, "Unable to create mail drop directory (%s)", m_szMailQueueDir);
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = m_szMailDropDir;
|
|
SmtpLogEvent(SMTP_EVENT_INVALID_MAIL_DROP_DIR, 2, apszSubStrings, dwErr);
|
|
m_szMailDropDir[0] = '\0';
|
|
m_cchMailDropDir = 0;
|
|
}
|
|
}
|
|
|
|
else {
|
|
if (!(dwAttr & FILE_ATTRIBUTE_DIRECTORY)) {
|
|
// The registry points to a file, so we're outta luck.
|
|
// The directory doesn't exist, and we can't create it.
|
|
// Because this is the queue directory, we're not going
|
|
// to be able to start. Log it so it can be fixed, but
|
|
// set fRet to FALSE so that we shut back down.
|
|
ErrorTrace((LPARAM)this, "Mail drop directory (%s) already exists as a file", m_szMailDropDir);
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = m_szMailDropDir;
|
|
SmtpLogEvent(SMTP_EVENT_INVALID_MAIL_DROP_DIR, 2, apszSubStrings, ERROR_ALREADY_EXISTS);
|
|
m_szMailDropDir[0] = '\0';
|
|
}
|
|
}
|
|
|
|
if (m_szMailDropDir[0] != '\0') {
|
|
// Looks like everything is going to be OK, so we add a backslash (if
|
|
// necessary) because it makes things easier later.
|
|
m_cchMailDropDir = lstrlen(m_szMailDropDir);
|
|
if (m_cchMailDropDir > 0 && m_szMailDropDir[m_cchMailDropDir - 1] != '\\') {
|
|
lstrcat(m_szMailDropDir, "\\");
|
|
m_cchMailDropDir++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Added by keithlau on 7/8/96
|
|
//
|
|
if (IsFieldSet(fc, FC_SMTP_INFO_BAD_MAIL_DIR)) {
|
|
TempString.Reset();
|
|
|
|
if (! mb.GetStr("", MD_BAD_MAIL_DIR, IIS_MD_UT_SERVER, &TempString, 0) ||
|
|
TempString.IsEmpty()) {
|
|
// We had a problem reading the registry, so
|
|
// set the flags back to not save bad mail and
|
|
// log it and hop out.
|
|
// This is NOT fatal. We'll still start up and run,
|
|
// but we're not going to save bad mail, and we wanted
|
|
// to, so at least we'll log the event.
|
|
m_szBadMailDir[0] = '\0';
|
|
ErrorTrace((LPARAM)this, "Unable to read bad mail dir value, error = %u", dwErr);
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = szBadMailDir;
|
|
SmtpLogEvent(SMTP_EVENT_CANNOT_READ_SVC_REGKEY, 2, apszSubStrings, 0);
|
|
} else {
|
|
lstrcpyn (m_szBadMailDir,TempString.QueryStr(), MAX_PATH);
|
|
}
|
|
|
|
if (m_szBadMailDir[0] != '\0') {
|
|
// We found a path in the registry, so see if it already exists.
|
|
dwAttr = GetFileAttributes(m_szBadMailDir);
|
|
if (dwAttr == 0xFFFFFFFF) {
|
|
// It doesn't exist at all, so try to create it.
|
|
if (!CreateLayerDirectory(m_szBadMailDir) && (dwErr = GetLastError()) != ERROR_ALREADY_EXISTS) {
|
|
// We couldn't create it, so we can't save bad mail.
|
|
// Log it because somebody messed up the registry.
|
|
// This is NOT fatal. We'll still start up and run,
|
|
// but we're not going to save bad mail, and we wanted
|
|
// to, so at least we'll log the event.
|
|
ErrorTrace((LPARAM)this, "Unable to create bad mail directory (%s)", m_szBadMailDir);
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = m_szBadMailDir;
|
|
SmtpLogEvent(SMTP_EVENT_INVALID_BAD_MAIL_DIR, 2, apszSubStrings, 0);
|
|
m_szBadMailDir[0] = '\0';
|
|
}
|
|
} else {
|
|
if (!(dwAttr & FILE_ATTRIBUTE_DIRECTORY)) {
|
|
// The registry points to a file, so we're outta luck.
|
|
// The directory doesn't exist, and we can't create it.
|
|
// This is NOT fatal. We'll still start up and run,
|
|
// but we're not going to save bad mail, and we wanted
|
|
// to, so at least we'll log the event.
|
|
ErrorTrace((LPARAM)this, "Bad mail directory (%s) already exists", m_szBadMailDir);
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = m_szBadMailDir;
|
|
SmtpLogEvent(SMTP_EVENT_INVALID_BAD_MAIL_DIR, 2, apszSubStrings, 0);
|
|
m_szBadMailDir[0] = '\0';
|
|
}
|
|
}
|
|
|
|
StateTrace((LPARAM)this, "Save bad mail is enabled and m_szBadMailDir = %s", m_szBadMailDir);
|
|
} else {
|
|
// We at least leave a trace saying that save bad mail is disabled
|
|
StateTrace((LPARAM)this, "Save bad mail is disabled");
|
|
}
|
|
|
|
if (m_szBadMailDir[0] != '\0') {
|
|
// Finally, if everything has gone OK, then add a trailing backslash so
|
|
// that things are easier later.
|
|
dwLen = lstrlen(m_szBadMailDir);
|
|
if (dwLen > 0 && m_szBadMailDir[dwLen-1] != '\\')
|
|
lstrcat(m_szBadMailDir, "\\");
|
|
}
|
|
}
|
|
|
|
if (IsFieldSet(fc, FC_SMTP_INFO_DOMAIN_ROUTING)) {
|
|
m_DefaultRouteAction = ReadMetabaseDword(mb, MD_ROUTE_ACTION, 0);
|
|
|
|
TempString.Reset();
|
|
|
|
if (!mb.GetStr("", MD_ROUTE_USER_NAME, IIS_MD_UT_SERVER, &TempString, 0) ||
|
|
TempString.IsEmpty()) {
|
|
m_DefaultRemoteUserName[0] = '\0';
|
|
m_DefaultRemotePassword[0] = '\0';
|
|
m_DefaultRouteAction &= ~SMTP_AUTH_NTLM;
|
|
m_DefaultRouteAction &= ~SMTP_AUTH_CLEARTEXT;
|
|
m_DefaultRouteAction &= ~SMTP_AUTH_KERBEROS;
|
|
m_DefaultRouteAction &= ~SMTP_SASL;
|
|
} else {
|
|
lstrcpyn (m_DefaultRemoteUserName,TempString.QueryStr(), MAX_INTERNET_NAME);
|
|
}
|
|
|
|
TempString.Reset();
|
|
|
|
if (!mb.GetStr("", MD_ROUTE_PASSWORD, IIS_MD_UT_SERVER, &TempString, METADATA_SECURE) ||
|
|
TempString.IsEmpty()) {
|
|
m_DefaultRemotePassword[0] = '\0';
|
|
} else {
|
|
lstrcpyn (m_DefaultRemotePassword,TempString.QueryStr(), MAX_PATH);
|
|
}
|
|
|
|
// Get change domain name.
|
|
if (m_pChangeObject)
|
|
{
|
|
char *psz = strstr((const char *) m_pChangeObject->pszMDPath, "/Domain/");
|
|
|
|
if (!psz)
|
|
{
|
|
// Changing default config or even more, rebuild
|
|
fRebuild = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// Found a normal domain change, copy the name
|
|
strncpy(szDomainName, psz+8, strlen(psz)-8);
|
|
szDomainName[strlen(psz)-8-1]='\0';
|
|
}
|
|
|
|
if (!strcmp(szDomainName, "*"))
|
|
{
|
|
// Changing '*' domain, rebuild
|
|
fRebuild = TRUE;
|
|
}
|
|
}
|
|
|
|
fRet = GetRouteDomains(mb, szDomainName, fRebuild);
|
|
}
|
|
|
|
AQConfig.cbVersion = sizeof(AQConfigInfo);
|
|
|
|
//Send badmail information
|
|
AQConfig.szBadMailDir = m_szBadMailDir;
|
|
AQConfig.dwAQConfigInfoFlags |= AQ_CONFIG_INFO_BADMAIL_DIR;
|
|
|
|
//Get DSN Options
|
|
AQConfig.dwDSNOptions = ReadMetabaseDword(mb, MD_SMTP_DSN_OPTIONS, DSN_OPTIONS_DEFAULT);
|
|
AQConfig.dwDSNLanguageID = ReadMetabaseDword(mb, MD_SMTP_DSN_LANGUAGE_ID, 0);
|
|
|
|
AQConfig.dwAQConfigInfoFlags |= AQ_CONFIG_INFO_USE_DSN_OPTIONS |
|
|
AQ_CONFIG_INFO_USE_DSN_LANGUAGE;
|
|
|
|
if (m_fSendNDRToAdmin)
|
|
AQConfig.szSendCopyOfNDRToAddress = m_AdminName;
|
|
else
|
|
AQConfig.szSendCopyOfNDRToAddress = NULL;
|
|
AQConfig.dwAQConfigInfoFlags |= AQ_CONFIG_INFO_SEND_DSN_TO;
|
|
|
|
m_pIAdvQueueConfig->SetConfigInfo(&AQConfig);
|
|
|
|
//
|
|
// jstamerj 1998/11/17 16:34:48:
|
|
// Set the well known proeprties of ISession
|
|
//
|
|
hr = HrSetWellKnownIServerProps();
|
|
if(FAILED(hr)) {
|
|
//
|
|
// Just like everything else in this fucntion, don't treat
|
|
// this as fatal; just log it
|
|
//
|
|
ErrorTrace((LPARAM)this, "HrSetWellKnownIServerProps failed hr %08lx", hr);
|
|
}
|
|
|
|
m_GenLock.ExclusiveUnlock();
|
|
|
|
if (!fRet && (GetLastError() == NO_ERROR))
|
|
SetLastError(ERROR_PATH_NOT_FOUND);
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return fRet;
|
|
}
|
|
|
|
//+---------------------------------------------------------------
|
|
//
|
|
// Function: DeleteDomainEntry
|
|
//
|
|
// Synopsis: Delete a domain from cached tables.
|
|
//
|
|
// Arguments: DomainName: name of the domain to delete.
|
|
//
|
|
// Returns: BOOL - TRUE on SUCCESS, FALSE on FAIL
|
|
//
|
|
//----------------------------------------------------------------
|
|
|
|
BOOL SMTP_SERVER_INSTANCE::DeleteDomainEntry(const char *DomainName)
|
|
{
|
|
TraceFunctEnterEx((LPARAM)this, "DeleteDomainEntry");
|
|
|
|
DebugTrace((LPARAM)this , "Delete Domain [%s] ", DomainName);
|
|
|
|
// Remove this domain from our SMTPSVC tables
|
|
m_TurnAccessList.RemoveFromTable((const char *) DomainName);
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------
|
|
//
|
|
// Function: RemoveRegParams
|
|
//
|
|
// Synopsis: Remove metabase info from cached tables.
|
|
// We only handle domain removal at this moment.
|
|
//
|
|
// Arguments: DomainName: name of the domain to delete.
|
|
// If DomainName is NULL, we get it from
|
|
// m_pChangeObject.
|
|
//
|
|
// Returns: BOOL - TRUE on SUCCESS, FALSE on FAIL
|
|
//
|
|
//----------------------------------------------------------------
|
|
BOOL SMTP_SERVER_INSTANCE::RemoveRegParams(const char *DomainName)
|
|
{
|
|
TraceFunctEnterEx((LPARAM)this, "RemoveRegParams");
|
|
|
|
char szDomainName [AB_MAX_DOMAIN + 1] = {0};
|
|
BOOL fRet = TRUE;
|
|
|
|
m_GenLock.ExclusiveLock();
|
|
|
|
if (!m_pChangeObject)
|
|
goto Exit;
|
|
|
|
if (DomainName)
|
|
{
|
|
strcpy(szDomainName, DomainName);
|
|
}
|
|
else
|
|
{
|
|
// At this stage, we only handle Domain removale.
|
|
char *psz = strstr((const char *) m_pChangeObject->pszMDPath, "/Domain/");
|
|
|
|
if (psz)
|
|
{
|
|
// We find it.
|
|
strncpy(szDomainName, psz+8, strlen(psz)-8);
|
|
szDomainName[strlen(psz)-8-1]='\0';
|
|
}
|
|
}
|
|
|
|
if (szDomainName[0] == '\0')
|
|
goto Exit;
|
|
|
|
{
|
|
HRESULT hr = S_OK;
|
|
char szRoutePath [MAX_PATH + 1];
|
|
char szActionType [MAX_PATH + 1];
|
|
char szUserName [MAX_INTERNET_NAME + 1];
|
|
char szEtrnDomain [AB_MAX_DOMAIN + 1];
|
|
char szPassword [MAX_PATH + 1];
|
|
char szTargetName [MAX_PATH + 1];
|
|
DomainInfo DefaultDomainInfo;
|
|
DomainInfo StarDomainInfo;
|
|
MB mb( (IMDCOM*)g_pInetSvc->QueryMDObject() );
|
|
|
|
if( !mb.Open( QueryMDPath(), METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE) )
|
|
{
|
|
fRet = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
if (!strcmp(szDomainName, "*"))
|
|
{
|
|
// Deleting the '*' domain, must rebuild
|
|
fRet = GetRouteDomains(mb, szDomainName, TRUE);
|
|
goto Exit;
|
|
}
|
|
|
|
// Delete the domain from the table in SMTPSVC
|
|
DeleteDomainEntry((const char *) szDomainName);
|
|
|
|
// Since we have no way to tell AQ to delete this domain apart from
|
|
// doing a full rebuild, we are going to push the defaults to AQ
|
|
// to overwrite the custom settings this domain had before
|
|
|
|
// Load up the "default config" : We get this by loading the server
|
|
// default config and then trying to overwrite it with the '*'
|
|
// domain config (if present)
|
|
|
|
// REVIEW : Ideally this code would be in DeleteDomainEntry but putting it
|
|
// there hurts us now because we have to call DeleteDomainEntry from
|
|
// SetRouteDomainParameters to clean the tables in SMTPSVC. If we can get
|
|
// rid of those tables, the layout of these functions shoule be reconsidered.
|
|
|
|
wsprintf(szRoutePath, "");
|
|
SetRouteDomainParameters(mb,
|
|
szDomainName,
|
|
szRoutePath,
|
|
szActionType,
|
|
szUserName,
|
|
szEtrnDomain,
|
|
szPassword,
|
|
szTargetName,
|
|
&DefaultDomainInfo);
|
|
|
|
if (AlwaysUseSmartHost() && m_szSmartHostName[0]) {
|
|
DefaultDomainInfo.dwDomainInfoFlags |= DOMAIN_INFO_REMOTE_SMARTHOST;
|
|
DefaultDomainInfo.szSmartHostDomainName = m_szSmartHostName;
|
|
DefaultDomainInfo.cbSmartHostDomainNameLength = lstrlen(m_szSmartHostName);
|
|
}
|
|
|
|
//check if we should always use SSL
|
|
if (GetDefaultRouteAction() & SMTP_SSL) {
|
|
DefaultDomainInfo.dwDomainInfoFlags |= DOMAIN_INFO_USE_SSL;
|
|
}
|
|
|
|
// Try to overwrite this with the "*" domain if it exists
|
|
wsprintf(szRoutePath, "/Domain/*");
|
|
SetRouteDomainParameters(mb,
|
|
szDomainName,
|
|
szRoutePath,
|
|
szActionType,
|
|
szUserName,
|
|
szEtrnDomain,
|
|
szPassword,
|
|
szTargetName,
|
|
&StarDomainInfo);
|
|
|
|
// If we found the star domain - dwDomainInfoFlags is zero if
|
|
// the domain does not exist in the metabase
|
|
if (StarDomainInfo.dwDomainInfoFlags) {
|
|
hr = m_pIAdvQueueConfig->SetDomainInfo(&StarDomainInfo);
|
|
}
|
|
// else push the default domain info
|
|
else {
|
|
hr = m_pIAdvQueueConfig->SetDomainInfo(&DefaultDomainInfo);
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
m_GenLock.ExclusiveUnlock();
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return fRet;
|
|
}
|
|
|
|
BOOL SMTP_SERVER_INSTANCE::GetCatInfo(MB& mb, AQConfigInfo& AQConfig)
|
|
{
|
|
STR TempString;
|
|
char Password[MAX_PATH];
|
|
char BindType[MAX_PATH];
|
|
char SchemaType[MAX_PATH];
|
|
char Domain[MAX_PATH];
|
|
char UserName[MAX_PATH];
|
|
char Host[MAX_PATH];
|
|
char NamingContext[MAX_PATH];
|
|
char DsType[MAX_PATH];
|
|
|
|
Password[0] = '\0';
|
|
BindType[0] = '\0';
|
|
SchemaType[0] = '\0';
|
|
Domain[0] = '\0';
|
|
UserName[0] = '\0';
|
|
Host[0] = '\0';
|
|
NamingContext[0] = '\0';
|
|
DsType [0] = '\0';
|
|
|
|
if( mb.GetDword("RoutingSources", MD_SMTP_DS_USE_CAT, IIS_MD_UT_SERVER, &AQConfig.dwMsgCatEnable))
|
|
{
|
|
AQConfig.dwAQConfigInfoFlags |= AQ_CONFIG_INFO_MSGCAT_ENABLE;
|
|
_VERIFY(SUCCEEDED(
|
|
m_InstancePropertyBag.PutDWORD(
|
|
PE_ISERVID_DW_CATENABLE,
|
|
AQConfig.dwMsgCatEnable)));
|
|
}
|
|
|
|
if( mb.GetDword("RoutingSources", MD_SMTP_DS_FLAGS, IIS_MD_UT_SERVER, &AQConfig.dwMsgCatFlags))
|
|
{
|
|
AQConfig.dwAQConfigInfoFlags |= AQ_CONFIG_INFO_MSGCAT_FLAGS;
|
|
_VERIFY(SUCCEEDED(
|
|
m_InstancePropertyBag.PutDWORD(
|
|
PE_ISERVID_DW_CATFLAGS,
|
|
AQConfig.dwMsgCatFlags)));
|
|
}
|
|
|
|
if( mb.GetDword("RoutingSources", MD_SMTP_DS_PORT, IIS_MD_UT_SERVER, &AQConfig.dwMsgCatPort))
|
|
{
|
|
AQConfig.dwAQConfigInfoFlags |= AQ_CONFIG_INFO_MSGCAT_PORT;
|
|
_VERIFY(SUCCEEDED(
|
|
m_InstancePropertyBag.PutDWORD(
|
|
PE_ISERVID_DW_CATPORT,
|
|
AQConfig.dwMsgCatPort)));
|
|
}
|
|
|
|
TempString.Reset();
|
|
|
|
if (mb.GetStr("RoutingSources", MD_SMTP_DS_ACCOUNT, IIS_MD_UT_SERVER, &TempString) &&
|
|
!TempString.IsEmpty()) {
|
|
lstrcpyn(UserName, TempString.QueryStr(), MAX_PATH);
|
|
AQConfig.dwAQConfigInfoFlags |= AQ_CONFIG_INFO_MSGCAT_USER;
|
|
AQConfig.szMsgCatUser = UserName;
|
|
_VERIFY(SUCCEEDED(
|
|
m_InstancePropertyBag.PutStringA(
|
|
PE_ISERVID_SZ_CATUSER,
|
|
TempString.QueryStr())));
|
|
}
|
|
|
|
TempString.Reset();
|
|
|
|
if (mb.GetStr("RoutingSources", MD_SMTP_DS_SCHEMA_TYPE, IIS_MD_UT_SERVER, &TempString) &&
|
|
!TempString.IsEmpty()) {
|
|
lstrcpyn(SchemaType, TempString.QueryStr(), MAX_PATH);
|
|
AQConfig.dwAQConfigInfoFlags |= AQ_CONFIG_INFO_MSGCAT_SCHEMATYPE;
|
|
AQConfig.szMsgCatSchemaType = SchemaType;
|
|
_VERIFY(SUCCEEDED(
|
|
m_InstancePropertyBag.PutStringA(
|
|
PE_ISERVID_SZ_CATSCHEMA,
|
|
TempString.QueryStr())));
|
|
}
|
|
|
|
TempString.Reset();
|
|
|
|
if (mb.GetStr("RoutingSources", MD_SMTP_DS_BIND_TYPE, IIS_MD_UT_SERVER, &TempString) &&
|
|
!TempString.IsEmpty()) {
|
|
lstrcpyn(BindType, TempString.QueryStr(), MAX_PATH);
|
|
AQConfig.dwAQConfigInfoFlags |= AQ_CONFIG_INFO_MSGCAT_BINDTYPE;
|
|
AQConfig.szMsgCatBindType = BindType;
|
|
_VERIFY(SUCCEEDED(
|
|
m_InstancePropertyBag.PutStringA(
|
|
PE_ISERVID_SZ_CATBINDTYPE,
|
|
TempString.QueryStr())));
|
|
}
|
|
|
|
TempString.Reset();
|
|
|
|
if (mb.GetStr("RoutingSources", MD_SMTP_DS_PASSWORD, IIS_MD_UT_SERVER, &TempString, METADATA_INHERIT | METADATA_SECURE )) {
|
|
lstrcpyn(Password, TempString.QueryStr(), MAX_PATH);
|
|
AQConfig.dwAQConfigInfoFlags |= AQ_CONFIG_INFO_MSGCAT_PASSWORD;
|
|
AQConfig.szMsgCatPassword = Password;
|
|
_VERIFY(SUCCEEDED(
|
|
m_InstancePropertyBag.PutStringA(
|
|
PE_ISERVID_SZ_CATPASSWORD,
|
|
TempString.QueryStr())));
|
|
}
|
|
|
|
TempString.Reset();
|
|
|
|
if (mb.GetStr("RoutingSources", MD_SMTP_DS_DOMAIN, IIS_MD_UT_SERVER, &TempString) &&
|
|
!TempString.IsEmpty()) {
|
|
lstrcpyn(Domain, TempString.QueryStr(), MAX_PATH);
|
|
AQConfig.dwAQConfigInfoFlags |= AQ_CONFIG_INFO_MSGCAT_DOMAIN;
|
|
AQConfig.szMsgCatDomain = Domain;
|
|
_VERIFY(SUCCEEDED(
|
|
m_InstancePropertyBag.PutStringA(
|
|
PE_ISERVID_SZ_CATDOMAIN,
|
|
TempString.QueryStr())));
|
|
}
|
|
|
|
TempString.Reset();
|
|
|
|
if (mb.GetStr("RoutingSources", MD_SMTP_DS_NAMING_CONTEXT, IIS_MD_UT_SERVER, &TempString) &&
|
|
!TempString.IsEmpty()) {
|
|
lstrcpyn(NamingContext, TempString.QueryStr(), MAX_PATH);
|
|
AQConfig.dwAQConfigInfoFlags |= AQ_CONFIG_INFO_MSGCAT_NAMING_CONTEXT;
|
|
AQConfig.szMsgCatNamingContext = NamingContext;
|
|
_VERIFY(SUCCEEDED(
|
|
m_InstancePropertyBag.PutStringA(
|
|
PE_ISERVID_SZ_CATNAMINGCONTEXT,
|
|
TempString.QueryStr())));
|
|
}
|
|
|
|
TempString.Reset();
|
|
|
|
if (mb.GetStr("RoutingSources", MD_SMTP_DS_TYPE, IIS_MD_UT_SERVER, &TempString) &&
|
|
!TempString.IsEmpty()) {
|
|
lstrcpyn(DsType, TempString.QueryStr(), MAX_PATH);
|
|
AQConfig.dwAQConfigInfoFlags |= AQ_CONFIG_INFO_MSGCAT_TYPE;
|
|
AQConfig.szMsgCatType = DsType;
|
|
_VERIFY(SUCCEEDED(
|
|
m_InstancePropertyBag.PutStringA(
|
|
PE_ISERVID_SZ_CATDSTYPE,
|
|
TempString.QueryStr())));
|
|
}
|
|
|
|
AQConfig.cbVersion = sizeof(AQConfigInfo);
|
|
|
|
TempString.Reset();
|
|
|
|
if(mb.GetStr("RoutingSources", MD_SMTP_DS_HOST, IIS_MD_UT_SERVER, &TempString) &&
|
|
!TempString.IsEmpty())
|
|
{
|
|
lstrcpyn(Host, TempString.QueryStr(), MAX_PATH);
|
|
AQConfig.dwAQConfigInfoFlags |= AQ_CONFIG_INFO_MSGCAT_HOST;
|
|
AQConfig.szMsgCatHost = Host;
|
|
_VERIFY(SUCCEEDED(
|
|
m_InstancePropertyBag.PutStringA(
|
|
PE_ISERVID_SZ_CATDSHOST,
|
|
TempString.QueryStr())));
|
|
}
|
|
|
|
//
|
|
// Indicate that all the official "msgcat" keys that exist are set
|
|
//
|
|
AQConfig.dwAQConfigInfoFlags |= AQ_CONFIG_INFO_MSGCAT_DEFAULT;
|
|
|
|
AQConfig.cbVersion = sizeof(AQConfigInfo);
|
|
|
|
m_pIAdvQueueConfig->SetConfigInfo(&AQConfig);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL SMTP_SERVER_INSTANCE::ReadRouteDomainIpSecList(MB& mb)
|
|
{
|
|
IMDCOM* pMBCom;
|
|
HRESULT hRes;
|
|
METADATA_RECORD mdRecord;
|
|
DWORD dwRequiredLen;
|
|
DWORD dwErr;
|
|
BOOL fSuccess = TRUE;
|
|
char *szValueName = "";
|
|
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE::ReadRouteDomainIpSecList");
|
|
|
|
ResetRelayIpSecList();
|
|
|
|
pMBCom = (IMDCOM*)m_Service->QueryMDObject();
|
|
|
|
mdRecord.dwMDIdentifier = MD_SMTP_IP_RELAY_ADDRESSES;
|
|
mdRecord.dwMDAttributes = METADATA_INHERIT;
|
|
mdRecord.dwMDUserType = IIS_MD_UT_FILE;
|
|
mdRecord.dwMDDataType = BINARY_METADATA;
|
|
mdRecord.dwMDDataLen = 5000;
|
|
mdRecord.pbMDData = (PBYTE) new char [5000];
|
|
|
|
if (mdRecord.pbMDData == NULL) {
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return FALSE;
|
|
}
|
|
|
|
hRes = pMBCom->ComMDGetMetaData( mb.QueryHandle(),
|
|
(LPBYTE)szValueName,
|
|
&mdRecord,
|
|
&dwRequiredLen );
|
|
if ( SUCCEEDED( hRes ) ) {
|
|
|
|
SetRelayIpSecList(mdRecord.pbMDData,
|
|
mdRecord.dwMDDataLen,
|
|
mdRecord.dwMDDataTag );
|
|
} else {
|
|
if (mdRecord.pbMDData)
|
|
delete mdRecord.pbMDData;
|
|
fSuccess = FALSE;
|
|
dwErr = HRESULTTOWIN32( hRes );
|
|
}
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return fSuccess;
|
|
}
|
|
|
|
void SMTP_SERVER_INSTANCE::BuildTurnTable(MULTISZ& msz, char * szDomainName)
|
|
{
|
|
const char * StartPtr = NULL;
|
|
CTurnData * pTurnData = NULL;
|
|
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE::BuildTurnTable");
|
|
|
|
for (StartPtr = msz.First(); StartPtr != NULL; StartPtr = msz.Next( StartPtr )) {
|
|
((PSMTP_IIS_SERVICE) g_pInetSvc)->StartHintFunction();
|
|
|
|
DebugTrace((LPARAM)this , "%s is allowed to issue TURN", StartPtr);
|
|
|
|
pTurnData = new CTurnData(StartPtr, szDomainName);
|
|
if (pTurnData != NULL) {
|
|
if (!m_TurnAccessList.InsertIntoTable((CHASH_ENTRY *) pTurnData)) {
|
|
delete pTurnData;
|
|
}
|
|
}
|
|
}
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
}
|
|
|
|
//+---------------------------------------------------------------
|
|
//
|
|
// Function: SetRouteDomainParameters
|
|
//
|
|
// Synopsis: Does the actual work of adding a domain from the metabase
|
|
//
|
|
//----------------------------------------------------------------
|
|
void SMTP_SERVER_INSTANCE::SetRouteDomainParameters(MB &mb,
|
|
char *szDomainName,
|
|
char *szRoutePath,
|
|
char szActionType [MAX_PATH + 1],
|
|
char szUserName [MAX_INTERNET_NAME + 1],
|
|
char szEtrnDomain [MAX_INTERNET_NAME + 1],
|
|
char szPassword [MAX_PATH + 1],
|
|
char szTargetName [MAX_PATH + 1],
|
|
DomainInfo *pLocalDomainInfo)
|
|
{
|
|
TraceFunctEnter("SMTP_SERVER_INSTANCE::SetRouteDomainParameters");
|
|
|
|
char * DomainPtr = NULL;
|
|
char * UserNamePtr = NULL;
|
|
char * PasswordPtr = NULL;
|
|
char * TargetNamePtr = NULL;
|
|
DWORD dwAction = 0;
|
|
STR TempString;
|
|
DWORD dwErr = NO_ERROR;
|
|
DWORD dwLen = 0;
|
|
BOOL RelayForAuth = TRUE;
|
|
DWORD dwEtrnWaitTime = 0;
|
|
BOOL WildCard = FALSE;
|
|
CHAR pchAddr1[32] = "";
|
|
MULTISZ msz;
|
|
|
|
if (szDomainName[0]) {
|
|
ZeroMemory(pLocalDomainInfo, sizeof(DomainInfo));
|
|
pLocalDomainInfo->cbVersion = sizeof(DomainInfo);
|
|
pLocalDomainInfo->cbDomainNameLength = lstrlen(szDomainName);
|
|
pLocalDomainInfo->szDomainName = szDomainName;
|
|
|
|
szActionType [0] = '\0';
|
|
szUserName [0] = '\0';
|
|
szPassword [0] = '\0';
|
|
szEtrnDomain[0] = '\0';
|
|
szTargetName[0] = '\0';
|
|
|
|
UserNamePtr = szUserName;
|
|
PasswordPtr = szPassword;
|
|
TargetNamePtr = szTargetName;
|
|
dwAction = 0;
|
|
|
|
DomainPtr = szDomainName;
|
|
|
|
if (!mb.GetDword(szRoutePath, MD_ROUTE_ACTION, IIS_MD_UT_SERVER, &dwAction)) {
|
|
dwAction = 0;
|
|
}
|
|
|
|
// If we don't recognize the actions we bail now - SMTP_DEFAULT
|
|
// shound never be set on any RouteAction in the metabase
|
|
if ((dwAction & ~SMTP_ALL_ROUTE_FLAGS) || (dwAction & SMTP_DEFAULT)) {
|
|
TraceFunctLeave();
|
|
return;
|
|
}
|
|
|
|
TempString.Reset();
|
|
if (mb.GetStr(szRoutePath, MD_ROUTE_ACTION_TYPE, IIS_MD_UT_SERVER, &TempString, 0) &&
|
|
!TempString.IsEmpty()) {
|
|
lstrcpyn(szActionType, TempString.QueryStr(), MAX_PATH);
|
|
}
|
|
|
|
TempString.Reset();
|
|
|
|
if (((dwAction & SMTP_SMARTHOST) || (dwAction & SMTP_SASL)) && mb.GetStr(szRoutePath, MD_ROUTE_USER_NAME, IIS_MD_UT_SERVER, &TempString) &&
|
|
!TempString.IsEmpty()) {
|
|
lstrcpyn(szUserName, TempString.QueryStr(), MAX_INTERNET_NAME);
|
|
} else {
|
|
UserNamePtr = NULL;
|
|
}
|
|
|
|
TempString.Reset();
|
|
|
|
if (UserNamePtr != NULL) {
|
|
if (mb.GetStr(szRoutePath, MD_ROUTE_PASSWORD, IIS_MD_UT_SERVER, &TempString, METADATA_SECURE | METADATA_INHERIT) &&
|
|
!TempString.IsEmpty()) {
|
|
lstrcpyn(szPassword, TempString.QueryStr(), MAX_PATH);
|
|
}
|
|
} else {
|
|
PasswordPtr = "";
|
|
}
|
|
|
|
TempString.Reset();
|
|
|
|
if (TargetNamePtr != NULL) {
|
|
if (mb.GetStr(szRoutePath, MD_ROUTE_AUTHTARGET, IIS_MD_UT_SERVER, &TempString, METADATA_SECURE | METADATA_INHERIT) &&
|
|
!TempString.IsEmpty()) {
|
|
lstrcpyn(szTargetName, TempString.QueryStr(), MAX_PATH);
|
|
}
|
|
} else {
|
|
TargetNamePtr = "";
|
|
}
|
|
|
|
TempString.Reset();
|
|
if (mb.GetStr(szRoutePath, MD_SMTP_CSIDE_ETRN_DOMAIN, IIS_MD_UT_SERVER, &TempString, 0) &&
|
|
!TempString.IsEmpty()) {
|
|
lstrcpyn(szEtrnDomain, TempString.QueryStr(), AB_MAX_DOMAIN);
|
|
}
|
|
|
|
dwEtrnWaitTime = ReadMetabaseDword(mb, MD_SMTP_CSIDE_ETRN_DELAY, 0);
|
|
|
|
//
|
|
// If the domain is set to explicitly allow relay for authenticated users..
|
|
// use that value. Otherwise, use the value set on the VSI (to maintain
|
|
// backwards compatibility with W2K users).
|
|
//
|
|
if (dwAction & SMTP_AUTH_RELAY)
|
|
RelayForAuth = TRUE;
|
|
else
|
|
RelayForAuth = m_fRelayForAuthUsers;
|
|
|
|
if (dwAction & SMTP_SMARTHOST) {
|
|
pLocalDomainInfo->dwDomainInfoFlags |= DOMAIN_INFO_REMOTE_SMARTHOST;
|
|
|
|
if (dwAction & SMTP_SSL)
|
|
pLocalDomainInfo->dwDomainInfoFlags |= DOMAIN_INFO_USE_SSL;
|
|
|
|
if (szActionType[0] != '\0') {
|
|
pLocalDomainInfo->szSmartHostDomainName = szActionType;
|
|
pLocalDomainInfo->cbSmartHostDomainNameLength = lstrlen(szActionType);
|
|
} else if (*szDomainName == '*') {
|
|
//The domain names could be specified as "*" - an explicit smart
|
|
//host must be used.
|
|
pLocalDomainInfo->dwDomainInfoFlags &= ~DOMAIN_INFO_REMOTE_SMARTHOST;
|
|
} else { //use the domain name as our smarthost
|
|
pLocalDomainInfo->szSmartHostDomainName = szDomainName;
|
|
pLocalDomainInfo->cbSmartHostDomainNameLength = lstrlen(pLocalDomainInfo->szSmartHostDomainName);
|
|
}
|
|
}
|
|
|
|
//if we are doing SASL, make sure we have a username and password
|
|
//and a correct authentication bits
|
|
if (dwAction & SMTP_SASL) {
|
|
|
|
// One of these must be set or else the SMTP_SASL flag doesn't
|
|
// make sense
|
|
if (!(dwAction & SMTP_AUTH_NTLM) &&
|
|
!(dwAction & SMTP_AUTH_CLEARTEXT) &&
|
|
!(dwAction & SMTP_AUTH_KERBEROS)) {
|
|
|
|
// dbraun : we can be cleaner about handling this - bailing
|
|
// leaves us with an incompletely configured domain
|
|
|
|
TraceFunctLeave();
|
|
return;
|
|
}
|
|
|
|
if (UserNamePtr) {
|
|
pLocalDomainInfo->szUserName = UserNamePtr;
|
|
pLocalDomainInfo->cbUserNameLength = lstrlen (UserNamePtr);
|
|
}
|
|
|
|
if (PasswordPtr) {
|
|
pLocalDomainInfo->szPassword = PasswordPtr;
|
|
pLocalDomainInfo->cbPasswordLength = lstrlen(PasswordPtr);
|
|
}
|
|
|
|
if (dwAction & SMTP_AUTH_NTLM) {
|
|
pLocalDomainInfo->dwDomainInfoFlags |= DOMAIN_INFO_USE_NTLM;
|
|
}
|
|
|
|
if (dwAction & SMTP_AUTH_CLEARTEXT) {
|
|
pLocalDomainInfo->dwDomainInfoFlags |= DOMAIN_INFO_USE_PLAINTEXT;
|
|
}
|
|
if (dwAction & SMTP_AUTH_KERBEROS) {
|
|
pLocalDomainInfo->dwDomainInfoFlags |= DOMAIN_INFO_USE_KERBEROS;
|
|
if (TargetNamePtr) {
|
|
pLocalDomainInfo->szAuthType = TargetNamePtr;
|
|
pLocalDomainInfo->cbAuthTypeLength = lstrlen(TargetNamePtr);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
char * szTmpDomain;
|
|
//Check for the wildcard entries
|
|
if (*DomainPtr == '*' && *(DomainPtr+1) == '.') {
|
|
WildCard = TRUE;
|
|
szTmpDomain = DomainPtr + 2;
|
|
} else {
|
|
szTmpDomain = DomainPtr;
|
|
}
|
|
|
|
|
|
if (szTmpDomain[0] != '*' || szTmpDomain[1] != 0) {
|
|
if (!CAddr::ValidateDomainName(szTmpDomain)) {
|
|
ErrorTrace((LPARAM)this , "%s is an invalid domain", DomainPtr);
|
|
|
|
//bad domain name
|
|
TraceFunctLeave();
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (dwAction & SMTP_DROP) {
|
|
if (!CreateLayerDirectory(szActionType) && (dwErr = GetLastError()) != ERROR_ALREADY_EXISTS) {
|
|
// Reflect the changes
|
|
const CHAR *aszStrings[3];
|
|
CHAR szTemp1[MAX_PATH + 1];
|
|
CHAR szTemp2[MAX_PATH + 1];
|
|
|
|
aszStrings[0] = pchAddr1;
|
|
aszStrings[1] = szTemp1;
|
|
aszStrings[2] = szTemp2;
|
|
|
|
lstrcpyn(szTemp1, szActionType, MAX_PATH);
|
|
lstrcpyn(szTemp2, DomainPtr, MAX_PATH);
|
|
SmtpLogEvent(SMTP_EVENT_NO_DROP_DIRECTORY, 3, aszStrings, dwErr);
|
|
}
|
|
|
|
dwLen = lstrlen(szActionType);
|
|
if (dwLen > 0 && szActionType[dwLen-1] != '\\')
|
|
lstrcat(szActionType, "\\");
|
|
|
|
pLocalDomainInfo->szDropDirectory = szActionType;
|
|
pLocalDomainInfo->cbDropDirectoryLength = lstrlen (szActionType);
|
|
pLocalDomainInfo->dwDomainInfoFlags = DOMAIN_INFO_LOCAL_DROP;
|
|
}
|
|
|
|
// Remove original one if it is there
|
|
DeleteDomainEntry((const char *) DomainPtr);
|
|
|
|
//
|
|
// Insert local domains into the routing table.
|
|
//
|
|
if ((dwAction & SMTP_DELIVER) && (szActionType[0] == '\0')) {
|
|
DebugTrace((LPARAM)this , "adding %s as a DELIVER domain", szDomainName);
|
|
|
|
pLocalDomainInfo->dwDomainInfoFlags = DOMAIN_INFO_LOCAL_MAILBOX;
|
|
|
|
} else if (dwAction & SMTP_ALIAS) {
|
|
DebugTrace((LPARAM)this , "adding %s as a ALIAS domain", szDomainName);
|
|
|
|
if (IsDefaultInRt()) {
|
|
pLocalDomainInfo->dwDomainInfoFlags = DOMAIN_INFO_LOCAL_MAILBOX | DOMAIN_INFO_ALIAS;
|
|
} else {
|
|
pLocalDomainInfo->szDropDirectory = m_szMailDropDir;
|
|
pLocalDomainInfo->cbDropDirectoryLength = lstrlen (m_szMailDropDir);
|
|
pLocalDomainInfo->dwDomainInfoFlags = DOMAIN_INFO_LOCAL_DROP | DOMAIN_INFO_ALIAS;
|
|
}
|
|
}
|
|
|
|
if (RelayForAuth) {
|
|
pLocalDomainInfo->dwDomainInfoFlags |= DOMAIN_INFO_AUTH_RELAY;
|
|
}
|
|
|
|
if (dwAction & SMTP_DOMAIN_RELAY) {
|
|
pLocalDomainInfo->dwDomainInfoFlags |= DOMAIN_INFO_DOMAIN_RELAY;
|
|
}
|
|
|
|
msz.Reset();
|
|
|
|
if ((dwAction & SMTP_ETRN_CMD) && mb.GetMultisz(szRoutePath, MD_SMTP_AUTHORIZED_TURN_LIST, IIS_MD_UT_SERVER, &msz) &&
|
|
!msz.IsEmpty()) {
|
|
BuildTurnTable(msz, szTmpDomain);
|
|
pLocalDomainInfo->dwDomainInfoFlags |= DOMAIN_INFO_TURN_ONLY;
|
|
}
|
|
if (dwAction & SMTP_ETRN_CMD && !(dwAction & SMTP_DISABLE_ETRN) ) {
|
|
pLocalDomainInfo->dwDomainInfoFlags |= DOMAIN_INFO_ETRN_ONLY;
|
|
}//if(dwAction & SMTP_ETRN_CMD)
|
|
|
|
if (dwAction & SMTP_USE_HELO ) {
|
|
pLocalDomainInfo->dwDomainInfoFlags |= DOMAIN_INFO_USE_HELO;
|
|
}//if(dwAction & SMTP_USE_HELO)
|
|
|
|
if (dwAction & SMTP_CSIDE_ETRN) {
|
|
|
|
TempString.Reset();
|
|
if (mb.GetStr(szRoutePath, MD_SMTP_CSIDE_ETRN_DOMAIN, IIS_MD_UT_SERVER, &TempString, 0) &&
|
|
!TempString.IsEmpty()) {
|
|
pLocalDomainInfo->szETRNDomainName = szEtrnDomain;
|
|
lstrcpyn(pLocalDomainInfo->szETRNDomainName, TempString.QueryStr(), AB_MAX_DOMAIN);
|
|
pLocalDomainInfo->cbETRNDomainNameLength = strlen(szEtrnDomain);
|
|
pLocalDomainInfo->dwDomainInfoFlags |= DOMAIN_INFO_SEND_ETRN;
|
|
}
|
|
|
|
}//if(dwAction & SMTP_CSIDE_ETRN)
|
|
|
|
if (dwAction & SMTP_CSIDE_TURN) {
|
|
pLocalDomainInfo->dwDomainInfoFlags |= DOMAIN_INFO_SEND_TURN;
|
|
pLocalDomainInfo->dwDomainInfoFlags |= DOMAIN_INFO_TURN_ON_EMPTY;
|
|
|
|
}//if(dwAction & SMTP_CSIDE_TURN)
|
|
|
|
|
|
if (dwAction & SMTP_DISABLE_BMIME) {
|
|
pLocalDomainInfo->dwDomainInfoFlags |= DOMAIN_INFO_DISABLE_BMIME;
|
|
|
|
}//if(dwAction & SMTP_DISABLE_BMIME)
|
|
|
|
if (dwAction & SMTP_CHUNKING) {
|
|
pLocalDomainInfo->dwDomainInfoFlags |= DOMAIN_INFO_USE_CHUNKING;
|
|
|
|
}//if(dwAction & SMTP_CHUNKING)
|
|
else if (dwAction & SMTP_DISABLE_CHUNK) {
|
|
pLocalDomainInfo->dwDomainInfoFlags |= DOMAIN_INFO_DISABLE_CHUNKING;
|
|
pLocalDomainInfo->dwDomainInfoFlags |= DOMAIN_INFO_DISABLE_BMIME;
|
|
}
|
|
|
|
if (dwAction & SMTP_DISABLE_DSN) {
|
|
pLocalDomainInfo->dwDomainInfoFlags |= DOMAIN_INFO_DISABLE_DSN;
|
|
|
|
}//if(dwAction & SMTP_DISBALE_DSN)
|
|
|
|
if (dwAction & SMTP_DISABLE_PIPELINE) {
|
|
pLocalDomainInfo->dwDomainInfoFlags |= DOMAIN_INFO_DISABLE_PIPELINE;
|
|
|
|
}//if(dwAction & SMTP_DISABLE_PIPELINE)
|
|
|
|
}//if (szDomainName[0])
|
|
TraceFunctLeave();
|
|
}
|
|
|
|
//+---------------------------------------------------------------
|
|
//
|
|
// Function: AddDomainEntry
|
|
//
|
|
// Synopsis: Add a domain into cached tables.
|
|
//
|
|
// Arguments: MB: already opened metabase.
|
|
// DomainName: name of the domain to add.
|
|
//
|
|
// Returns: BOOL - TRUE on SUCCESS, FALSE on FAIL
|
|
//
|
|
//----------------------------------------------------------------
|
|
BOOL SMTP_SERVER_INSTANCE::AddDomainEntry (MB &mb, char * DomainName)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BOOL fReturn = TRUE;
|
|
char szDomainName [AB_MAX_DOMAIN + 1];
|
|
char szRoutePath [MAX_PATH + 1];
|
|
char szActionType [MAX_PATH + 1];
|
|
char szUserName [MAX_INTERNET_NAME + 1];
|
|
char szEtrnDomain [AB_MAX_DOMAIN + 1];
|
|
char szPassword [MAX_PATH + 1];
|
|
char szTargetName [MAX_PATH + 1];
|
|
DomainInfo LocalDomainInfo;
|
|
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE::AddNewEntry");
|
|
|
|
strcpy(szDomainName, DomainName);
|
|
|
|
if (szDomainName[0])
|
|
{
|
|
szRoutePath[0] = '\0';
|
|
wsprintf(szRoutePath, "/Domain/%s", szDomainName);
|
|
|
|
SetRouteDomainParameters(mb,
|
|
szDomainName,
|
|
szRoutePath,
|
|
szActionType,
|
|
szUserName,
|
|
szEtrnDomain,
|
|
szPassword,
|
|
szTargetName,
|
|
&LocalDomainInfo);
|
|
hr = m_pIAdvQueueConfig->SetDomainInfo(&LocalDomainInfo);
|
|
if (FAILED(hr))
|
|
{
|
|
fReturn = FALSE;
|
|
}
|
|
}//if (szDomainName[0])
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return fReturn;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------
|
|
//
|
|
// Function: GetRouteDomains
|
|
//
|
|
// Synopsis: Get Routing domains from the metabase
|
|
//
|
|
// Arguments: MB: already opened metabase.
|
|
// DomainName: name of the domain to add.
|
|
// fRebuild: bool indicating if we need to rebuild
|
|
// the whole table
|
|
//
|
|
// Returns: BOOL - TRUE on SUCCESS, FALSE on FAIL
|
|
//
|
|
//----------------------------------------------------------------
|
|
BOOL SMTP_SERVER_INSTANCE::GetRouteDomains(MB &mb, char * DomainName, BOOL fRebuild)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD ThreadId;
|
|
DWORD error;
|
|
BOOL fReturn = TRUE;
|
|
DomainInfo LocalDomainInfo;
|
|
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE::GetRouteDomains");
|
|
|
|
((PSMTP_IIS_SERVICE) g_pInetSvc)->StartHintFunction();
|
|
|
|
m_TurnAccessList.SetDupesAllowed();
|
|
|
|
// Only rebuild when fRebuild is TRUE.
|
|
if (fRebuild)
|
|
{
|
|
// We need to clean m_hEnumDomainThreadHandle here
|
|
// to avoid handle leak.
|
|
if (m_hEnumDomainThreadHandle)
|
|
{
|
|
if (!m_fEnumThreadStarted) {
|
|
// the thread has been created, but it has not been
|
|
// able to grab the gencrit lock yet. This means
|
|
// that it will be doing a full rebuild already, so
|
|
// we can just bail
|
|
goto cleanup;
|
|
}
|
|
|
|
// Set up signal and wait
|
|
WaitForSingleObject(m_hEnumDomainThreadHandle, INFINITE);
|
|
ErrorTrace((LPARAM)this, "EnumDomain Thread is dead");
|
|
CloseHandle(m_hEnumDomainThreadHandle);
|
|
m_hEnumDomainThreadHandle = NULL;
|
|
}
|
|
|
|
m_fEnumThreadStarted = FALSE;
|
|
m_hEnumDomainThreadHandle = CreateThread (NULL, 0,
|
|
EnumAllDomains, this, 0, &ThreadId);
|
|
if(m_hEnumDomainThreadHandle == NULL)
|
|
{
|
|
error = GetLastError();
|
|
ErrorTrace((LPARAM)this, "CreateThread failed for EnumAllDomains. err: %u", error);
|
|
fReturn = FALSE;
|
|
}
|
|
else
|
|
{
|
|
DebugTrace((LPARAM)this , "EnumDomainThread is created, threadId [%ld]", ThreadId);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!AddDomainEntry(mb, DomainName))
|
|
fReturn = FALSE;
|
|
}
|
|
|
|
cleanup:
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return fReturn;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------
|
|
//
|
|
// Function: EnumAllDomains
|
|
//
|
|
// Synopsis: Enumerate all domains in this SMTP instance.
|
|
//
|
|
// Arguments: ptr: pointer to the SMTP server instance.
|
|
//
|
|
// Returns: BOOL - TRUE on SUCCESS, FALSE on FAIL
|
|
//
|
|
//----------------------------------------------------------------
|
|
DWORD EnumAllDomains(VOID *ptr)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
char szDomainName [AB_MAX_DOMAIN + 1];
|
|
char szRoutePath [MAX_PATH + 1];
|
|
char szActionType [MAX_PATH + 1];
|
|
char szUserName [MAX_INTERNET_NAME + 1];
|
|
char szEtrnDomain [AB_MAX_DOMAIN + 1];
|
|
char szPassword [MAX_PATH + 1];
|
|
char szTargetName [MAX_PATH + 1];
|
|
char szStarDomain[] = "*";
|
|
DWORD dwTotal = 0;
|
|
DomainInfo LocalDomainInfo;
|
|
MB mb( (IMDCOM*)g_pInetSvc->QueryMDObject() );
|
|
SMTP_SERVER_INSTANCE *pInstance = (SMTP_SERVER_INSTANCE *) ptr;
|
|
|
|
TraceFunctEnterEx((LPARAM)pInstance, "EnumAllDomains");
|
|
|
|
pInstance->ExclusiveLockGenCrit();
|
|
|
|
pInstance->m_fEnumThreadStarted = TRUE;
|
|
|
|
pInstance->m_TurnAccessList.SetDupesAllowed();
|
|
pInstance->m_TurnAccessList.RemoveAllEntries();
|
|
|
|
//Signal AQ that we are starting over
|
|
pInstance->m_pIAdvQueueConfig->StartConfigUpdate();
|
|
|
|
if (pInstance->m_szMailDropDir[0] == '\0')
|
|
{
|
|
ZeroMemory(&LocalDomainInfo, sizeof(DomainInfo));
|
|
LocalDomainInfo.cbVersion = sizeof(DomainInfo);
|
|
LocalDomainInfo.cbDomainNameLength = lstrlen(pInstance->m_szDefaultDomain);
|
|
LocalDomainInfo.szDomainName = pInstance->m_szDefaultDomain;
|
|
LocalDomainInfo.dwDomainInfoFlags = DOMAIN_INFO_LOCAL_MAILBOX;
|
|
|
|
HRESULT hr;
|
|
hr = pInstance->m_pIAdvQueueConfig->SetDomainInfo(&LocalDomainInfo);
|
|
|
|
DebugTrace((LPARAM)pInstance , "default domain %s was added to the routing table", pInstance->m_szDefaultDomain);
|
|
|
|
//signals default domain was added to routing table
|
|
pInstance->m_fDefaultInRt = TRUE;
|
|
}
|
|
else
|
|
{
|
|
ZeroMemory(&LocalDomainInfo, sizeof(DomainInfo));
|
|
LocalDomainInfo.cbVersion = sizeof(DomainInfo);
|
|
LocalDomainInfo.cbDomainNameLength = lstrlen(pInstance->m_szDefaultDomain);
|
|
LocalDomainInfo.szDomainName = pInstance->m_szDefaultDomain;
|
|
LocalDomainInfo.szDropDirectory = pInstance->m_szMailDropDir;
|
|
LocalDomainInfo.cbDropDirectoryLength = lstrlen (pInstance->m_szMailDropDir);
|
|
LocalDomainInfo.dwDomainInfoFlags = DOMAIN_INFO_LOCAL_DROP;
|
|
|
|
hr = pInstance->m_pIAdvQueueConfig->SetDomainInfo(&LocalDomainInfo);
|
|
}
|
|
|
|
if( !mb.Open( pInstance->QueryMDPath(), METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE) )
|
|
{
|
|
pInstance->ExclusiveUnLockGenCrit();
|
|
return FALSE;
|
|
}
|
|
|
|
while (!pInstance->IsShuttingDown() && mb.EnumObjects("/Domain", szDomainName, dwTotal++)) {
|
|
|
|
if (szDomainName[0]) {
|
|
szRoutePath[0] = '\0';
|
|
wsprintf(szRoutePath, "/Domain/%s", szDomainName);
|
|
|
|
pInstance->SetRouteDomainParameters(mb,
|
|
szDomainName,
|
|
szRoutePath,
|
|
szActionType,
|
|
szUserName,
|
|
szEtrnDomain,
|
|
szPassword,
|
|
szTargetName,
|
|
&LocalDomainInfo);
|
|
hr = pInstance->m_pIAdvQueueConfig->SetDomainInfo(&LocalDomainInfo);
|
|
if (FAILED(hr)) {
|
|
}
|
|
}//if (szDomainName[0])
|
|
}//while (mb.EnumObjects("/RouteDomains", szDomainName, dw++))
|
|
|
|
|
|
pInstance->SetRouteDomainParameters(mb,
|
|
szStarDomain, "",
|
|
szActionType,
|
|
szUserName,
|
|
szEtrnDomain,
|
|
szPassword,
|
|
szTargetName,
|
|
&LocalDomainInfo);
|
|
|
|
if (pInstance->AlwaysUseSmartHost() && pInstance->m_szSmartHostName[0]) {
|
|
LocalDomainInfo.dwDomainInfoFlags |= DOMAIN_INFO_REMOTE_SMARTHOST;
|
|
LocalDomainInfo.szSmartHostDomainName = pInstance->m_szSmartHostName;
|
|
LocalDomainInfo.cbSmartHostDomainNameLength = lstrlen(pInstance->m_szSmartHostName);
|
|
}
|
|
|
|
//check if we should always use SSL
|
|
if (pInstance->GetDefaultRouteAction() & SMTP_SSL) {
|
|
LocalDomainInfo.dwDomainInfoFlags |= DOMAIN_INFO_USE_SSL;
|
|
}
|
|
|
|
hr = pInstance->m_pIAdvQueueConfig->SetDomainInfo(&LocalDomainInfo);
|
|
|
|
// jstamerj 1998/07/24 11:18:39:
|
|
// For M2, AQueue requires a local domain entry " " in its
|
|
// configuration to handle recipients without SMTP addresses
|
|
// (such as an remote X400 address). This will be removed when
|
|
// code is added to encapsualte non-SMTP addresses into SMTP.
|
|
// Add this local domain here.
|
|
//
|
|
ZeroMemory(&LocalDomainInfo, sizeof(DomainInfo));
|
|
|
|
LocalDomainInfo.cbVersion = sizeof(DomainInfo);
|
|
LocalDomainInfo.cbDomainNameLength = 1;
|
|
LocalDomainInfo.szDomainName = " ";
|
|
LocalDomainInfo.dwDomainInfoFlags = DOMAIN_INFO_LOCAL_MAILBOX;
|
|
|
|
hr = pInstance->m_pIAdvQueueConfig->SetDomainInfo(&LocalDomainInfo);
|
|
|
|
//Signal AQ that we are finished updating domain config
|
|
pInstance->m_pIAdvQueueConfig->FinishConfigUpdate();
|
|
|
|
pInstance->ExclusiveUnLockGenCrit();
|
|
|
|
TraceFunctLeaveEx((LPARAM)pInstance);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL SMTP_SERVER_INSTANCE::ReadIpSecList(void)
|
|
{
|
|
IMDCOM* pMBCom;
|
|
METADATA_HANDLE hMB;
|
|
HRESULT hRes;
|
|
METADATA_RECORD mdRecord;
|
|
DWORD dwRequiredLen;
|
|
DWORD dwErr;
|
|
BOOL fSuccess;
|
|
|
|
m_GenLock.ExclusiveLock();
|
|
|
|
m_rfAccessCheck.Reset( (IMDCOM*)m_Service->QueryMDObject() );
|
|
|
|
pMBCom = (IMDCOM*)m_Service->QueryMDObject();
|
|
hRes = pMBCom->ComMDOpenMetaObject( METADATA_MASTER_ROOT_HANDLE,
|
|
(BYTE *) QueryMDPath(),
|
|
METADATA_PERMISSION_READ,
|
|
5000,
|
|
&hMB );
|
|
if ( SUCCEEDED( hRes ) ) {
|
|
mdRecord.dwMDIdentifier = MD_IP_SEC;
|
|
mdRecord.dwMDAttributes = METADATA_INHERIT | METADATA_REFERENCE;
|
|
mdRecord.dwMDUserType = IIS_MD_UT_FILE;
|
|
mdRecord.dwMDDataType = BINARY_METADATA;
|
|
mdRecord.dwMDDataLen = 0;
|
|
mdRecord.pbMDData = (PBYTE)NULL;
|
|
|
|
hRes = pMBCom->ComMDGetMetaData( hMB,
|
|
(LPBYTE)"",
|
|
&mdRecord,
|
|
&dwRequiredLen );
|
|
if ( SUCCEEDED( hRes ) && mdRecord.dwMDDataTag ) {
|
|
m_rfAccessCheck.Set( mdRecord.pbMDData,
|
|
mdRecord.dwMDDataLen,
|
|
mdRecord.dwMDDataTag );
|
|
}
|
|
|
|
DBG_REQUIRE( SUCCEEDED(pMBCom->ComMDCloseMetaObject( hMB )) );
|
|
} else {
|
|
fSuccess = FALSE;
|
|
dwErr = HRESULTTOWIN32( hRes );
|
|
}
|
|
|
|
m_GenLock.ExclusiveUnlock();
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
BOOL IsNTFS(IN LPCSTR pszRealPath)
|
|
|
|
/*++
|
|
Gets file system specific information for a given path.
|
|
It uses GetVolumeInfomration() to query the file system type
|
|
and file system flags.
|
|
On success the flags and file system type are returned in
|
|
passed in pointers.
|
|
|
|
--*/
|
|
{
|
|
#define MAX_FILE_SYSTEM_NAME_SIZE ( MAX_PATH)
|
|
CHAR rgchBuf[MAX_FILE_SYSTEM_NAME_SIZE];
|
|
CHAR rgchRoot[MAX_FILE_SYSTEM_NAME_SIZE];
|
|
int i;
|
|
DWORD dwReturn = ERROR_PATH_NOT_FOUND;
|
|
|
|
if ( pszRealPath == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
if ( pszRealPath[0] == ('\\') &&
|
|
pszRealPath[1] == ('\\')) {
|
|
|
|
return FALSE;
|
|
|
|
} // else
|
|
|
|
ZeroMemory( (void *) rgchRoot, sizeof(rgchRoot) );
|
|
|
|
//
|
|
// This is non UNC name.
|
|
// Copy just the root directory to rgchRoot for querying
|
|
//
|
|
|
|
for ( i = 0; i < 9 && pszRealPath[i] != '\0'; i++) {
|
|
|
|
if ( (rgchRoot[i] = pszRealPath[i]) == ':') {
|
|
|
|
break;
|
|
}
|
|
} // for
|
|
|
|
|
|
if ( rgchRoot[i] != ':') {
|
|
|
|
//
|
|
// we could not find the root directory.
|
|
// return with error value
|
|
//
|
|
return ( FALSE);
|
|
}
|
|
|
|
rgchRoot[i+1] = '\\'; // terminate the drive spec with a slash
|
|
rgchRoot[i+2] = '\0'; // terminate the drive spec with null char
|
|
|
|
// The rgchRoot should end with a "\" (slash)
|
|
// otherwise, the call will fail.
|
|
if ( GetVolumeInformation( rgchRoot, // lpRootPathName
|
|
NULL, // lpVolumeNameBuffer
|
|
0, // len of volume name buffer
|
|
NULL, // lpdwVolSerialNumber
|
|
NULL, // lpdwMaxComponentLength
|
|
NULL, // lpdwSystemFlags
|
|
rgchBuf, // lpFileSystemNameBuff
|
|
sizeof(rgchBuf)/sizeof(WCHAR)
|
|
)) {
|
|
|
|
|
|
|
|
if ( lstrcmp( rgchBuf, "NTFS") == 0) {
|
|
return TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
return ( FALSE);
|
|
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------
|
|
//
|
|
// Function: SMTPCONFIG::ReadStartupRegParams
|
|
//
|
|
// Synopsis: Reads fixed (i.e. not modifiable on-the-fly) parameters
|
|
// from the registry into the config class member variables.
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: BOOL - TRUE on SUCCESS, FALSE on FAIL
|
|
//
|
|
// Note: Created by KeithLau on 7/15/96
|
|
//
|
|
//----------------------------------------------------------------
|
|
BOOL SMTP_SERVER_INSTANCE::ReadStartupRegParams(VOID)
|
|
{
|
|
BOOL fRet = TRUE;
|
|
DWORD dwErr = NO_ERROR;
|
|
DWORD dwAttr;
|
|
char szValueName[MAX_PATH + 1];
|
|
MB mb( (IMDCOM*) g_pInetSvc->QueryMDObject() );
|
|
STR TempString;
|
|
const CHAR * apszSubStrings[2];
|
|
CHAR pchAddr1[32] = "";
|
|
|
|
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE::ReadStartupRegParams");
|
|
|
|
GetServerBindings();
|
|
|
|
m_GenLock.ExclusiveLock();
|
|
|
|
//
|
|
// Read metabase data.
|
|
//
|
|
|
|
lstrcpy(szValueName, QueryMDPath());
|
|
|
|
_itoa(QueryInstanceId(), pchAddr1, 10);
|
|
|
|
if ( !mb.Open( szValueName, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE) ) {
|
|
//UnLockConfig();
|
|
m_GenLock.ExclusiveUnlock();
|
|
return FALSE;
|
|
}
|
|
|
|
m_CmdLogFlags = ReadMetabaseDword(mb, MD_COMMAND_LOG_MASK, DEFAULT_CMD_LOG_FLAGS);
|
|
|
|
m_fFlushMailFiles = !!ReadMetabaseDword(mb, MD_FLUSH_MAIL_FILE, TRUE);
|
|
|
|
m_cMaxRoutingThreads = ReadMetabaseDword(mb, MD_ROUTING_THREADS, 8);
|
|
StateTrace((LPARAM)this, "m_cMaxRoutingThreads = %u", m_cMaxRoutingThreads);
|
|
|
|
m_fDisablePickupDotStuff = !!ReadMetabaseDword(mb, MD_SMTP_DISABLE_PICKUP_DOT_STUFF, FALSE);
|
|
StateTrace((LPARAM)this, "m_fDisablePickupDotStuff = %u", m_fDisablePickupDotStuff);
|
|
|
|
m_cMaxRemoteQThreads = ReadMetabaseDword(mb, MD_SMTP_MAX_REMOTEQ_THREADS, 1);
|
|
StateTrace((LPARAM)this, "m_cMaxRoutingThreads = %u",m_cMaxRemoteQThreads);
|
|
m_cMaxLocalQThreads = ReadMetabaseDword(mb, MD_SMTP_MAX_LOCALQ_THREADS, 1);
|
|
StateTrace((LPARAM)this, "m_cMaxRoutingThreads = %u", m_cMaxLocalQThreads);
|
|
|
|
TempString.Reset();
|
|
if (!mb.GetStr("", MD_MAIL_QUEUE_DIR, IIS_MD_UT_SERVER, &TempString, 0) ||
|
|
TempString.IsEmpty()) {
|
|
// We had a problem reading the registry.
|
|
// This is a very bad thing. We obviously cannot run without
|
|
// a queue directory, so set fRet to FALSE so that we shut
|
|
// back down (and log it so that an admin can fix it).
|
|
m_szMailQueueDir[0] = '\0';
|
|
fRet = FALSE;
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = szMailQueueDir;
|
|
|
|
SmtpLogEvent(SMTP_EVENT_CANNOT_READ_SVC_REGKEY, 2, apszSubStrings, 0);
|
|
} else {
|
|
lstrcpyn(m_szMailQueueDir, TempString.QueryStr(), MAX_PATH);
|
|
|
|
if (!IsNTFS(m_szMailQueueDir)) {
|
|
m_IsFileSystemNtfs = FALSE;
|
|
|
|
DebugTrace((LPARAM)this, "Queue dir (%s) is not NTFS", m_szMailQueueDir);
|
|
}
|
|
|
|
// We found a path in the reg, so see if we can use it...
|
|
dwAttr = GetFileAttributes(m_szMailQueueDir);
|
|
if (dwAttr == 0xFFFFFFFF) {
|
|
// The path doesn't exist yet, so we'll try to create it.
|
|
if (!CreateLayerDirectory(m_szMailQueueDir) && (dwErr = GetLastError()) != ERROR_ALREADY_EXISTS) {
|
|
// It doesn't exist and we couldn't create it, so
|
|
// log it and bail with fRet = FALSE so that we shut
|
|
// back down.
|
|
ErrorTrace((LPARAM)this, "Unable to create mail queue directory (%s)", m_szMailQueueDir);
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = m_szMailQueueDir;
|
|
SmtpLogEvent(SMTP_EVENT_INVALID_MAIL_QUEUE_DIR, 2, apszSubStrings, dwErr);
|
|
m_szMailQueueDir[0] = '\0';
|
|
fRet = FALSE;
|
|
}
|
|
} else {
|
|
if (!(dwAttr & FILE_ATTRIBUTE_DIRECTORY)) {
|
|
// The registry points to a file, so we're outta luck.
|
|
// The directory doesn't exist, and we can't create it.
|
|
// Because this is the queue directory, we're not going
|
|
// to be able to start. Log it so it can be fixed, but
|
|
// set fRet to FALSE so that we shut back down.
|
|
|
|
ErrorTrace((LPARAM)this, "Mail queue directory (%s) already exists as a file", m_szMailQueueDir);
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = m_szMailQueueDir;
|
|
SmtpLogEvent(SMTP_EVENT_INVALID_MAIL_QUEUE_DIR, 2, apszSubStrings, dwErr);
|
|
m_szMailQueueDir[0] = '\0';
|
|
fRet = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
TempString.Reset();
|
|
|
|
if (! mb.GetStr("", MD_MAIL_DROP_DIR, IIS_MD_UT_SERVER, &TempString, 0) ||
|
|
TempString.IsEmpty()) {
|
|
// We had a problem reading the metabase.
|
|
// This is a very bad thing. We obviously cannot run without
|
|
// a drop directory if we are in drop mode, so set fRet to
|
|
// FALSE so that we shut back down (and log it so that an
|
|
// admin can fix it).
|
|
m_szMailDropDir[0] = '\0';
|
|
m_cchMailDropDir = 0;
|
|
|
|
//don't start if we are disabled, since drop directory is not
|
|
//configurable.
|
|
if (!m_fIsRoutingTable) {
|
|
fRet = FALSE;
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = szMailDropDir;
|
|
SmtpLogEvent(SMTP_EVENT_CANNOT_READ_SVC_REGKEY, 2, apszSubStrings, 0);
|
|
}
|
|
} else {
|
|
lstrcpyn(m_szMailDropDir, TempString.QueryStr(), MAX_PATH);
|
|
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = m_szMailDropDir;
|
|
|
|
// We found a path in the reg, so see if we can use it...
|
|
dwAttr = GetFileAttributes(m_szMailDropDir);
|
|
if (dwAttr == 0xFFFFFFFF) {
|
|
// The path doesn't exist yet, so we'll try to create it.
|
|
if (!CreateLayerDirectory(m_szMailDropDir) && (dwErr = GetLastError()) != ERROR_ALREADY_EXISTS) {
|
|
// It doesn't exist and we couldn't create it, so
|
|
// log it and bail with fRet = FALSE so that we shut
|
|
// back down.
|
|
ErrorTrace((LPARAM)this, "Unable to create mail drop directory (%s)", m_szMailQueueDir);
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = m_szMailDropDir;
|
|
SmtpLogEvent(SMTP_EVENT_INVALID_MAIL_DROP_DIR, 2, apszSubStrings, dwErr);
|
|
m_szMailDropDir[0] = '\0';
|
|
m_cchMailDropDir = 0;
|
|
|
|
//don't start if we are disabled, since drop directory is not
|
|
//configurable.
|
|
if (!m_fIsRoutingTable)
|
|
fRet = FALSE;
|
|
}
|
|
} else {
|
|
if (!(dwAttr & FILE_ATTRIBUTE_DIRECTORY)) {
|
|
// The registry points to a file, so we're outta luck.
|
|
// The directory doesn't exist, and we can't create it.
|
|
// Because this is the queue directory, we're not going
|
|
// to be able to start. Log it so it can be fixed, but
|
|
// set fRet to FALSE so that we shut back down.
|
|
ErrorTrace((LPARAM)this, "Mail drop directory (%s) already exists as a file", m_szMailDropDir);
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = m_szMailDropDir;
|
|
SmtpLogEvent(SMTP_EVENT_INVALID_MAIL_DROP_DIR, 2, apszSubStrings, dwErr);
|
|
m_szMailDropDir[0] = '\0';
|
|
|
|
//don't start if we are disabled, since drop directory is not
|
|
//configurable.
|
|
if (!m_fIsRoutingTable)
|
|
fRet = FALSE;
|
|
}
|
|
}
|
|
|
|
// Looks like everything is going to be OK, so we add a backslash (if
|
|
// necessary) because it makes things easier later.
|
|
m_cchMailDropDir = lstrlen(m_szMailDropDir);
|
|
if (m_cchMailDropDir > 0 && m_szMailDropDir[m_cchMailDropDir - 1] != '\\') {
|
|
lstrcat(m_szMailDropDir, "\\");
|
|
m_cchMailDropDir++;
|
|
}
|
|
}
|
|
|
|
// Looks like everything is going to be OK, so we add a backslash (if
|
|
// necessary) because it makes things easier later.
|
|
m_cchMailQueueDir = lstrlen(m_szMailQueueDir);
|
|
if (m_cchMailQueueDir > 0 && m_szMailQueueDir[m_cchMailQueueDir - 1] != '\\') {
|
|
lstrcat(m_szMailQueueDir, "\\");
|
|
m_cchMailQueueDir++;
|
|
}
|
|
|
|
m_fShouldPickupMail = !!ReadMetabaseDword(mb, MD_SHOULD_PICKUP_MAIL, TRUE);
|
|
if (m_fShouldPickupMail) {
|
|
m_cMaxDirBuffers = ReadMetabaseDword(mb, MD_MAX_DIR_BUFFERS, 2000);
|
|
m_cMaxDirChangeIoSize = ReadMetabaseDword(mb, MD_MAX_DIR_CHANGE_IO_SIZE, 1000);
|
|
m_cMaxDirPendingIos = ReadMetabaseDword(mb, MD_MAX_DIR_PENDING_IOS, 1);
|
|
|
|
TempString.Reset();
|
|
|
|
if (!mb.GetStr("", MD_MAIL_PICKUP_DIR, IIS_MD_UT_SERVER, &TempString, 0) ||
|
|
TempString.IsEmpty()) {
|
|
// We had a problem reading the registry.
|
|
// This is a very bad thing.
|
|
m_szMailPickupDir[0] = '\0';
|
|
m_fShouldPickupMail = 0;
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = szMailPickupDir;
|
|
SmtpLogEvent(SMTP_EVENT_CANNOT_READ_SVC_REGKEY, 2, apszSubStrings, 0);
|
|
|
|
} else {
|
|
lstrcpyn(m_szMailPickupDir, TempString.QueryStr(), MAX_PATH);
|
|
|
|
// We found a path in the reg, so see if we can use it...
|
|
dwAttr = GetFileAttributes(m_szMailPickupDir);
|
|
if (dwAttr == 0xFFFFFFFF) {
|
|
// The path doesn't exist yet, so we'll try to create it.
|
|
if (!CreateLayerDirectory(m_szMailPickupDir) && (dwErr = GetLastError()) != ERROR_ALREADY_EXISTS) {
|
|
// It doesn't exist and we couldn't create it, so
|
|
// log it and bail with fRet = FALSE so that we shut
|
|
// back down.
|
|
ErrorTrace((LPARAM)this, "Unable to create mail pickup queue directory (%s)", m_szMailPickupDir);
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = m_szMailPickupDir;
|
|
SmtpLogEvent(SMTP_EVENT_INVALID_MAIL_DROP_DIR, 2, apszSubStrings, dwErr);
|
|
m_szMailPickupDir[0] = '\0';
|
|
m_fShouldPickupMail = 0;
|
|
}
|
|
} else {
|
|
if (!(dwAttr & FILE_ATTRIBUTE_DIRECTORY)) {
|
|
// The registry points to a file, so we're outta luck.
|
|
// The directory doesn't exist, and we can't create it.
|
|
ErrorTrace((LPARAM)this, "Mail pickup queue directory (%s) already exists as a file", m_szMailPickupDir);
|
|
apszSubStrings[0] = pchAddr1;
|
|
apszSubStrings[1] = m_szMailPickupDir;
|
|
SmtpLogEvent(SMTP_EVENT_INVALID_MAIL_DROP_DIR, 2, apszSubStrings, dwErr);
|
|
m_szMailPickupDir[0] = '\0';
|
|
m_fShouldPickupMail = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Looks like everything is going to be OK, so we add a backslash (if
|
|
// necessary) because it makes things easier later.
|
|
m_cchMailPickupDir = lstrlen(m_szMailPickupDir);
|
|
if (m_cchMailPickupDir > 0 && m_szMailPickupDir[m_cchMailPickupDir - 1] != '\\') {
|
|
lstrcat(m_szMailPickupDir, "\\");
|
|
m_cchMailPickupDir++;
|
|
}
|
|
}
|
|
|
|
if (!mb.GetStr("", MD_CONNECT_RESPONSE, IIS_MD_UT_SERVER, &TempString) ||
|
|
TempString.IsEmpty()) {
|
|
// We had a problem reading the metabase
|
|
// This is a very bad thing.
|
|
lstrcpy (m_szConnectResponse, "Microsoft ESMTP MAIL Service, ");
|
|
lstrcat (m_szConnectResponse, g_VersionString);
|
|
lstrcat (m_szConnectResponse, " ready at ");
|
|
// SmtpLogEvent(SMTP_EVENT_CANNOT_READ_SVC_REGKEY, 2, apszSubStrings, 0);
|
|
} else {
|
|
lstrcpyn(m_szConnectResponse, TempString.QueryStr(), MAX_PATH);
|
|
}
|
|
m_cchConnectResponse = lstrlenA(m_szConnectResponse);
|
|
|
|
mb.Close();
|
|
|
|
m_GenLock.ExclusiveUnlock();
|
|
|
|
ReadIpSecList();
|
|
|
|
if (!fRet)
|
|
SetLastError(ERROR_PATH_NOT_FOUND);
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return fRet;
|
|
}
|
|
|
|
void SMTP_SERVER_INSTANCE::GetServerBindings(void)
|
|
{
|
|
DWORD dwErr = NO_ERROR;
|
|
|
|
MB mb( (IMDCOM*)g_pInetSvc->QueryMDObject() );
|
|
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE::GetServerBindings");
|
|
|
|
m_GenLock.ExclusiveLock();
|
|
|
|
//
|
|
// open metabase data.
|
|
//
|
|
|
|
if ( !mb.Open( QueryMDPath(), METADATA_PERMISSION_READ ) ) {
|
|
m_GenLock.ExclusiveUnlock();
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return ;
|
|
}
|
|
|
|
m_ServerBindings.Reset();
|
|
|
|
if (!mb.GetMultisz("", MD_SERVER_BINDINGS, IIS_MD_UT_SERVER, &m_ServerBindings) ||
|
|
m_ServerBindings.IsEmpty()) {
|
|
dwErr = GetLastError();
|
|
ErrorTrace((LPARAM)this, "Unable to read server bindings, error = %u", dwErr);
|
|
}
|
|
|
|
m_GenLock.ExclusiveUnlock();
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
}
|
|
|
|
|
|
VOID
|
|
SMTP_SERVER_INSTANCE::MDChangeNotify(
|
|
MD_CHANGE_OBJECT * pco
|
|
)
|
|
/*++
|
|
|
|
This method handles the metabase change notification for this instance
|
|
|
|
Arguments:
|
|
|
|
hMDHandle - Metabase handle generating the change notification
|
|
pcoChangeList - path and id that has changed
|
|
|
|
--*/
|
|
{
|
|
FIELD_CONTROL control = 0;
|
|
BOOL fSslModified = FALSE;
|
|
DWORD i;
|
|
DWORD err;
|
|
DWORD id;
|
|
DWORD MdState;
|
|
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE::MDChangeNotify");
|
|
|
|
//
|
|
// Tell our parent about the change notification first
|
|
//
|
|
|
|
LockThisForWrite();
|
|
|
|
IIS_SERVER_INSTANCE::MDChangeNotify( pco );
|
|
|
|
// Save change object
|
|
m_pChangeObject = pco;
|
|
|
|
for ( i = 0; i < pco->dwMDNumDataIDs; i++ ) {
|
|
id = pco->pdwMDDataIDs[i];
|
|
|
|
switch ( id ) {
|
|
case MD_REVERSE_NAME_LOOKUP:
|
|
control |= FC_SMTP_INFO_REVERSE_LOOKUP;
|
|
break;
|
|
|
|
case MD_NTAUTHENTICATION_PROVIDERS:
|
|
control |= FC_SMTP_INFO_NTAUTHENTICATION_PROVIDERS;
|
|
break;
|
|
|
|
case MD_MD_SERVER_SS_AUTH_MAPPING:
|
|
case MD_SMTP_CLEARTEXT_AUTH_PROVIDER:
|
|
control |= FC_SMTP_CLEARTEXT_AUTH_PROVIDER;
|
|
break;
|
|
|
|
case MD_AUTHORIZATION:
|
|
control |= FC_SMTP_INFO_AUTHORIZATION;
|
|
break;
|
|
|
|
case MD_HOP_COUNT:
|
|
control |= FC_SMTP_INFO_MAX_HOP_COUNT;
|
|
break;
|
|
|
|
case MD_MAX_SMTP_ERRORS:
|
|
case MD_MAX_SMTP_AUTHLOGON_ERRORS:
|
|
control |= FC_SMTP_INFO_MAX_ERRORS;
|
|
break;
|
|
|
|
case MD_MAX_MSG_SIZE:
|
|
case MD_MAX_MSG_SIZE_B4_CLOSE:
|
|
control |= FC_SMTP_INFO_MAX_SIZE;
|
|
break;
|
|
|
|
case MD_REMOTE_TIMEOUT:
|
|
control |= FC_SMTP_INFO_REMOTE_TIMEOUT;
|
|
break;
|
|
|
|
case MD_MAX_OUTBOUND_CONNECTION:
|
|
control |= FC_SMTP_INFO_MAX_OUTBOUND_CONN;
|
|
break;
|
|
|
|
case MD_MAX_RECIPIENTS:
|
|
control |= FC_SMTP_INFO_MAX_RECIPS;
|
|
break;
|
|
|
|
case MD_ETRN_SUBDOMAINS:
|
|
control |= FC_SMTP_INFO_ETRN_SUBDOMAINS;
|
|
break;
|
|
|
|
case MD_MAIL_DROP_DIR:
|
|
control |= FC_SMTP_INFO_DEFAULT_DROP_DIR;
|
|
control |= FC_SMTP_INFO_DOMAIN_ROUTING;
|
|
break;
|
|
|
|
case MD_LOCAL_RETRY_ATTEMPTS:
|
|
case MD_LOCAL_RETRY_MINUTES:
|
|
case MD_REMOTE_RETRY_ATTEMPTS:
|
|
case MD_REMOTE_RETRY_MINUTES:
|
|
// case MD_SHARE_RETRY_MINUTES:
|
|
case MD_SMTP_REMOTE_RETRY_THRESHOLD:
|
|
case MD_SMTP_REMOTE_PROGRESSIVE_RETRY_MINUTES:
|
|
case MD_SMTP_EXPIRE_REMOTE_NDR_MIN:
|
|
case MD_SMTP_EXPIRE_REMOTE_DELAY_MIN:
|
|
case MD_SMTP_EXPIRE_LOCAL_NDR_MIN:
|
|
case MD_SMTP_EXPIRE_LOCAL_DELAY_MIN:
|
|
control |= FC_SMTP_INFO_RETRY;
|
|
break;
|
|
|
|
case MD_SHOULD_PIPELINE_OUT:
|
|
case MD_SHOULD_PIPELINE_IN:
|
|
control |= FC_SMTP_INFO_PIPELINE;
|
|
break;
|
|
|
|
case MD_SMTP_DS_TYPE:
|
|
case MD_SMTP_DS_DATA_DIRECTORY:
|
|
case MD_SMTP_DS_DEFAULT_MAIL_ROOT:
|
|
case MD_SMTP_DS_BIND_TYPE:
|
|
case MD_SMTP_DS_SCHEMA_TYPE:
|
|
case MD_SMTP_DS_HOST:
|
|
case MD_SMTP_DS_NAMING_CONTEXT:
|
|
case MD_SMTP_DS_ACCOUNT:
|
|
case MD_SMTP_DS_PASSWORD:
|
|
case MD_SMTP_DS_DOMAIN:
|
|
case MD_SMTP_DS_USE_CAT:
|
|
case MD_SMTP_DS_PORT:
|
|
case MD_SMTP_DS_FLAGS:
|
|
control |= FC_SMTP_INFO_ROUTING;
|
|
break;
|
|
|
|
case MD_SEND_BAD_TO:
|
|
case MD_SEND_NDR_TO:
|
|
control |= FC_SMTP_INFO_SEND_TO_ADMIN;
|
|
break;
|
|
|
|
case MD_SMARTHOST_TYPE:
|
|
case MD_SMARTHOST_NAME:
|
|
control |= FC_SMTP_INFO_SMART_HOST;
|
|
control |= FC_SMTP_INFO_DOMAIN_ROUTING;
|
|
break;
|
|
|
|
case MD_NAME_RESOLUTION_TYPE:
|
|
case MD_BATCH_MSG_LIMIT:
|
|
case MD_SMTP_IP_RELAY_ADDRESSES:
|
|
case MD_SMTP_DISABLE_RELAY:
|
|
case MD_SMTP_MAIL_NO_HELO:
|
|
case MD_SMTP_HELO_NODOMAIN:
|
|
case MD_SMTP_DISABLE_PICKUP_DOT_STUFF:
|
|
case MD_SMTP_EVENTLOG_LEVEL:
|
|
control |= FC_SMTP_INFO_COMMON_PARAMS;
|
|
break;
|
|
|
|
case MD_DEFAULT_DOMAIN_VALUE:
|
|
control |= FC_SMTP_INFO_DEFAULT_DOMAIN;
|
|
control |= FC_SMTP_INFO_DOMAIN_ROUTING;
|
|
break;
|
|
|
|
case MD_FQDN_VALUE:
|
|
control |= FC_SMTP_INFO_FQDN;
|
|
control |= FC_SMTP_INFO_DOMAIN_ROUTING;
|
|
break;
|
|
|
|
case MD_BAD_MAIL_DIR:
|
|
control |= FC_SMTP_INFO_BAD_MAIL_DIR;
|
|
break;
|
|
|
|
case MD_DO_MASQUERADE:
|
|
case MD_MASQUERADE_NAME:
|
|
control |= FC_SMTP_INFO_MASQUERADE;
|
|
break;
|
|
|
|
case MD_REMOTE_SMTP_PORT:
|
|
control |= FC_SMTP_INFO_REMOTE_PORT;
|
|
break;
|
|
|
|
case MD_LOCAL_DOMAINS:
|
|
control |= FC_SMTP_INFO_LOCAL_DOMAINS;
|
|
break;
|
|
|
|
case MD_DOMAIN_ROUTING:
|
|
control |= FC_SMTP_INFO_DOMAIN_ROUTING;
|
|
break;
|
|
|
|
case MD_POSTMASTER_EMAIL:
|
|
case MD_POSTMASTER_NAME:
|
|
control |= FC_SMTP_INFO_ADMIN_EMAIL_NAME;
|
|
break;
|
|
|
|
case MD_SMTP_SSL_REQUIRE_TRUSTED_CA:
|
|
case MD_SMTP_SSL_CERT_HOSTNAME_VALIDATION:
|
|
case MD_SSL_ACCESS_PERM:
|
|
control |= FC_SMTP_INFO_SSL_PERM;
|
|
break;
|
|
|
|
case MD_SASL_LOGON_DOMAIN:
|
|
control |= FC_SMTP_INFO_SASL_LOGON_DOMAIN;
|
|
break;
|
|
|
|
case MD_MAX_OUT_CONN_PER_DOMAIN:
|
|
control |= FC_SMTP_INFO_MAX_OUT_CONN_PER_DOMAIN;
|
|
break;
|
|
|
|
case MD_INBOUND_COMMAND_SUPPORT_OPTIONS:
|
|
case MD_OUTBOUND_COMMAND_SUPPORT_OPTIONS:
|
|
case MD_ADD_NOHEADERS :
|
|
control |= FC_SMTP_INFO_INBOUND_SUPPORT_OPTIONS;
|
|
break;
|
|
|
|
case MD_SERVER_BINDINGS:
|
|
GetServerBindings();
|
|
break;
|
|
|
|
case MD_IP_SEC:
|
|
control |= FC_SMTP_INFO_DOMAIN_ROUTING;
|
|
ReadIpSecList();
|
|
break;
|
|
|
|
case MD_SMTP_RELAY_FOR_AUTH_USERS:
|
|
control |= FC_SMTP_INFO_DOMAIN_ROUTING;
|
|
control |= FC_SMTP_INFO_COMMON_PARAMS;
|
|
break;
|
|
|
|
case MD_DOMAIN_VALIDATION_FLAGS:
|
|
control |= FC_SMTP_INFO_COMMON_PARAMS;
|
|
break;
|
|
|
|
case MD_ROUTE_ACTION:
|
|
case MD_ROUTE_ACTION_TYPE:
|
|
case MD_ROUTE_USER_NAME:
|
|
case MD_ROUTE_PASSWORD:
|
|
case MD_ROUTE_AUTHTARGET:
|
|
case MD_SMTP_CSIDE_ETRN_DELAY:
|
|
case MD_SMTP_CSIDE_ETRN_DOMAIN:
|
|
case MD_SMTP_AUTHORIZED_TURN_LIST:
|
|
control |= FC_SMTP_INFO_DOMAIN_ROUTING;
|
|
break;
|
|
|
|
case MD_SSL_CERT_HASH:
|
|
case MD_SSL_CERT_CONTAINER:
|
|
case MD_SSL_CERT_PROVIDER:
|
|
case MD_SSL_CERT_OPEN_FLAGS:
|
|
case MD_SSL_CERT_STORE_NAME:
|
|
case MD_SSL_CTL_IDENTIFIER:
|
|
case MD_SSL_CTL_CONTAINER:
|
|
case MD_SSL_CTL_PROVIDER:
|
|
case MD_SSL_CTL_PROVIDER_TYPE:
|
|
case MD_SSL_CTL_OPEN_FLAGS:
|
|
case MD_SSL_CTL_STORE_NAME:
|
|
fSslModified = TRUE;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
//We need to react to domains being deleted
|
|
// 9/29/98 - MikeSwa
|
|
if (MD_CHANGE_TYPE_DELETE_OBJECT == pco->dwMDChangeType) {
|
|
control |= FC_SMTP_INFO_DOMAIN_ROUTING;
|
|
}
|
|
|
|
//
|
|
// If anything related to SSL has changed, call the function used to flush
|
|
// the SSL/Schannel credential cache and reset the server certificate
|
|
//
|
|
if ( fSslModified && g_pSslKeysNotify ) {
|
|
(g_pSslKeysNotify) ( SIMSSL_NOTIFY_MAPPER_SSLKEYS_CHANGED, this );
|
|
|
|
ResetSSLInfo(this);
|
|
}
|
|
|
|
MdState = QueryServerState( );
|
|
|
|
if ( (MdState == MD_SERVER_STATE_STOPPING) || (MdState == MD_SERVER_STATE_STOPPED)) {
|
|
goto Done;
|
|
}
|
|
|
|
if ( control != 0 ) {
|
|
if (!ReadRegParams(control, FALSE)) {
|
|
err = GetLastError();
|
|
DBGPRINTF((
|
|
DBG_CONTEXT,
|
|
"SMTP_SERVER_INSTANCE::MDChangeNotify() cannot read config, error %lx\n",
|
|
err
|
|
));
|
|
|
|
}
|
|
}
|
|
|
|
// Handle deleting domains
|
|
if (control & FC_SMTP_INFO_DOMAIN_ROUTING)
|
|
{
|
|
// We are deleting objects
|
|
if (pco->dwMDChangeType == MD_CHANGE_TYPE_DELETE_OBJECT) {
|
|
if (!RemoveRegParams(NULL)) {
|
|
err = GetLastError();
|
|
DBGPRINTF((
|
|
DBG_CONTEXT,
|
|
"SMTP_SERVER_INSTANCE::MDChangeNotify() cannot remove config, error %lx\n",
|
|
err
|
|
));
|
|
}
|
|
}
|
|
}
|
|
|
|
Done:
|
|
m_pChangeObject = NULL;
|
|
UnlockThis();
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
}
|
|
|
|
|
|
IIS_SSL_INFO*
|
|
SMTP_SERVER_INSTANCE::QueryAndReferenceSSLInfoObj( VOID )
|
|
/*++
|
|
|
|
Description
|
|
|
|
Returns SSL info for this instance; calls Reference() before returning
|
|
We actually call GetCertificate( ) here, so the name is really incorrect,
|
|
but changing it will involve asking IIS to change IISTYPES to add the
|
|
new method as a vitual function.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
Ptr to SSL info object on success, NULL if failure
|
|
|
|
--*/
|
|
{
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE::QueryAndReferenceSSLInfoObj");
|
|
IIS_SSL_INFO *pPtr = NULL;
|
|
|
|
LockThisForRead();
|
|
|
|
//
|
|
// If it's null, we may have to create it - unlock, lock for write and make sure it's
|
|
// still NULL before creating it
|
|
//
|
|
if ( !m_pSSLInfo ) {
|
|
UnlockThis();
|
|
|
|
LockThisForWrite();
|
|
|
|
//
|
|
// Still null, so create it now
|
|
//
|
|
if ( !m_pSSLInfo ) {
|
|
m_pSSLInfo = new IIS_SSL_INFO( (LPTSTR) QueryMDPath(),
|
|
(IMDCOM *) g_pInetSvc->QueryMDObject() );
|
|
|
|
if ( m_pSSLInfo == NULL ) {
|
|
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
|
UnlockThis();
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Acquire an internal reference
|
|
//
|
|
m_pSSLInfo->Reference();
|
|
|
|
//
|
|
// Register for changes
|
|
//
|
|
IIS_SERVER_CERT *pCert = m_pSSLInfo->GetCertificate();
|
|
if ( pCert ) {
|
|
// Do logging if we fail to get the certificate
|
|
LogCertStatus();
|
|
}
|
|
|
|
//NIMISHK**** Do I need CTL - maybe I can get rid of this call
|
|
IIS_CTL *pCTL = m_pSSLInfo->GetCTL();
|
|
if ( pCTL ) {
|
|
//Do logging if we fail to get the CTL
|
|
LogCTLStatus();
|
|
}
|
|
|
|
if ( g_pCAPIStoreChangeNotifier ) {
|
|
if ( pCert && pCert->IsValid() ) {
|
|
if (!g_pCAPIStoreChangeNotifier->RegisterStoreForChange( pCert->QueryStoreName(),
|
|
pCert->QueryStoreHandle(),
|
|
ResetSSLInfo,
|
|
(PVOID) this ) ) {
|
|
DebugTrace((LPARAM)this,
|
|
"Failed to register for change event on store %s",
|
|
pCert->QueryStoreName());
|
|
}
|
|
}
|
|
|
|
if ( pCTL && pCTL->IsValid() ) {
|
|
if (!g_pCAPIStoreChangeNotifier->RegisterStoreForChange( pCTL->QueryStoreName(),
|
|
pCTL->QueryOriginalStore(),
|
|
ResetSSLInfo,
|
|
(PVOID) this ) ) {
|
|
DebugTrace((LPARAM)this,
|
|
"Failed to register for change event on store %s",
|
|
pCTL->QueryStoreName());
|
|
}
|
|
}
|
|
|
|
if ( ( pCert && pCert->IsValid()) ||
|
|
( pCTL && pCTL->IsValid() ) ) {
|
|
HCERTSTORE hRootStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_A,
|
|
0,
|
|
NULL,
|
|
CERT_SYSTEM_STORE_LOCAL_MACHINE,
|
|
"ROOT" );
|
|
|
|
if ( hRootStore ) {
|
|
//
|
|
// Watch for changes to the ROOT store
|
|
//
|
|
if ( !g_pCAPIStoreChangeNotifier->RegisterStoreForChange( "ROOT",
|
|
hRootStore,
|
|
ResetSSLInfo,
|
|
(PVOID) this ) ) {
|
|
DebugTrace((LPARAM)this,
|
|
"Failed to register for change event on root store");
|
|
}
|
|
|
|
CertCloseStore( hRootStore,
|
|
0 );
|
|
} else {
|
|
DebugTrace((LPARAM)this,
|
|
"Failed to open ROOT store, error 0x%d",
|
|
GetLastError());
|
|
|
|
}
|
|
} // if ( pCert || pCTL )
|
|
|
|
} // if (g_pCAPIStoreChangeNotifier)
|
|
|
|
} // if ( !m_pSSLInfo )
|
|
|
|
} //if ( !m_pSSLInfo )
|
|
|
|
//
|
|
// At this point, m_pSSLInfo should not be NULL anymore, so add the external reference
|
|
//
|
|
m_pSSLInfo->Reference();
|
|
|
|
pPtr = m_pSSLInfo;
|
|
|
|
UnlockThis();
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
|
|
return pPtr;
|
|
}
|
|
|
|
VOID SMTP_SERVER_INSTANCE::ResetSSLInfo( LPVOID pvParam )
|
|
/*++
|
|
Description:
|
|
|
|
Wrapper function for function to call to notify of SSL changes
|
|
|
|
Arguments:
|
|
|
|
pvParam - pointer to instance for which SSL keys have changed
|
|
|
|
Returns:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
{
|
|
TraceFunctEnterEx((LPARAM)NULL, "SMTP_SERVER_INSTANCE::ResetSSLInfo");
|
|
//
|
|
// Call function to flush credential cache etc
|
|
//
|
|
if ( g_pSslKeysNotify ) {
|
|
g_pSslKeysNotify( SIMSSL_NOTIFY_MAPPER_SSLKEYS_CHANGED,
|
|
pvParam );
|
|
}
|
|
|
|
SMTP_SERVER_INSTANCE *pInst = (SMTP_SERVER_INSTANCE *) pvParam;
|
|
|
|
pInst->LockThisForRead();
|
|
|
|
if ( pInst->m_pSSLInfo ) {
|
|
pInst->UnlockThis();
|
|
|
|
pInst->LockThisForWrite();
|
|
|
|
if ( pInst->m_pSSLInfo ) {
|
|
//
|
|
// Stop watching for change notifications
|
|
//
|
|
IIS_SERVER_CERT *pCert = pInst->m_pSSLInfo->QueryCertificate();
|
|
IIS_CTL *pCTL = pInst->m_pSSLInfo->QueryCTL();
|
|
|
|
if ( g_pCAPIStoreChangeNotifier ) {
|
|
//
|
|
// Stop watching the store the cert came out of
|
|
//
|
|
if ( pCert && pCert->IsValid() ) {
|
|
g_pCAPIStoreChangeNotifier->UnregisterStore( pCert->QueryStoreName(),
|
|
ResetSSLInfo,
|
|
(PVOID) pvParam );
|
|
}
|
|
|
|
//
|
|
// Stop watching the store the CTL came out of
|
|
//
|
|
if ( pCTL && pCTL->IsValid() ) {
|
|
g_pCAPIStoreChangeNotifier->UnregisterStore( pCTL->QueryStoreName(),
|
|
ResetSSLInfo,
|
|
(PVOID) pvParam );
|
|
}
|
|
|
|
//
|
|
// Stop watching the ROOT store
|
|
//
|
|
g_pCAPIStoreChangeNotifier->UnregisterStore( "ROOT",
|
|
ResetSSLInfo,
|
|
(PVOID) pvParam );
|
|
}
|
|
|
|
//
|
|
// Release internal reference
|
|
//
|
|
IIS_SSL_INFO::Release( pInst->m_pSSLInfo );
|
|
|
|
//
|
|
// Next call to QueryAndReferenceSSLObj() will create it again
|
|
//
|
|
pInst->m_pSSLInfo = NULL;
|
|
}
|
|
}
|
|
|
|
pInst->UnlockThis();
|
|
TraceFunctLeaveEx((LPARAM)NULL);
|
|
}
|
|
|
|
VOID SMTP_SERVER_INSTANCE::LogCertStatus()
|
|
/*++
|
|
Description:
|
|
|
|
Writes system log event about status of server certificate if the cert is in some
|
|
way not quite kosher eg expired, revoked, not signature-valid
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
Nothing
|
|
--*/
|
|
{
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE::LogCertStatus");
|
|
|
|
_ASSERT( m_pSSLInfo );
|
|
|
|
DWORD dwCertValidity = 0;
|
|
|
|
//
|
|
// If we didn't construct the cert fully, log an error
|
|
//
|
|
if ( !m_pSSLInfo->QueryCertificate()->IsValid() ) {
|
|
CONST CHAR *apszMsgs[2];
|
|
CHAR achInstance[20];
|
|
CHAR achErrorNumber[20];
|
|
wsprintf( achInstance,
|
|
"%lu",
|
|
QueryInstanceId() );
|
|
wsprintf( achErrorNumber,
|
|
"0x%x",
|
|
GetLastError() );
|
|
|
|
apszMsgs[0] = achInstance;
|
|
apszMsgs[1] = achErrorNumber;
|
|
|
|
DWORD dwStatus = m_pSSLInfo->QueryCertificate()->Status();
|
|
DWORD dwStringID = 0;
|
|
|
|
DebugTrace((LPARAM)this,
|
|
"Couldn't retrieve server cert; status : %d",
|
|
dwStatus);
|
|
|
|
switch ( dwStatus ) {
|
|
case CERT_ERR_MB:
|
|
dwStringID = SSL_MSG_CERT_MB_ERROR;
|
|
break;
|
|
|
|
case CERT_ERR_CAPI:
|
|
dwStringID = SSL_MSG_CERT_CAPI_ERROR;
|
|
break;
|
|
|
|
case CERT_ERR_CERT_NOT_FOUND:
|
|
dwStringID = SSL_MSG_CERT_NOT_FOUND;
|
|
break;
|
|
|
|
default:
|
|
dwStringID = SSL_MSG_CERT_INTERNAL_ERROR;
|
|
break;
|
|
}
|
|
|
|
SmtpLogEvent(dwStringID,
|
|
2,
|
|
apszMsgs,
|
|
0 );
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// If cert is invalid in some other way , write the appropriate log message
|
|
//
|
|
if ( m_pSSLInfo->QueryCertValidity( &dwCertValidity ) ) {
|
|
const CHAR *apszMsgs[1];
|
|
CHAR achInstance[20];
|
|
wsprintfA( achInstance,
|
|
"%lu",
|
|
QueryInstanceId() );
|
|
apszMsgs[0] = achInstance;
|
|
DWORD dwMsgID = 0;
|
|
|
|
if ( ( dwCertValidity & CERT_TRUST_IS_NOT_TIME_VALID ) ||
|
|
( dwCertValidity & CERT_TRUST_IS_NOT_TIME_NESTED ) ||
|
|
( dwCertValidity & CERT_TRUST_CTL_IS_NOT_TIME_VALID ) ) {
|
|
DebugTrace((LPARAM)this,
|
|
"Server cert/CTL is not time-valid or time-nested");
|
|
|
|
dwMsgID = SSL_MSG_TIME_INVALID_SERVER_CERT;
|
|
}
|
|
|
|
|
|
if ( dwCertValidity & CERT_TRUST_IS_REVOKED ) {
|
|
DebugTrace((LPARAM)this,
|
|
"Server Cert is revoked");
|
|
|
|
dwMsgID = SSL_MSG_REVOKED_SERVER_CERT;
|
|
}
|
|
|
|
if ( ( dwCertValidity & CERT_TRUST_IS_UNTRUSTED_ROOT ) ||
|
|
( dwCertValidity & CERT_TRUST_IS_PARTIAL_CHAIN ) ) {
|
|
DebugTrace((LPARAM)this,
|
|
"Server Cert doesn't chain up to a trusted root");
|
|
|
|
dwMsgID = SSL_MSG_UNTRUSTED_SERVER_CERT;
|
|
}
|
|
|
|
if ( ( dwCertValidity & CERT_TRUST_IS_NOT_SIGNATURE_VALID ) ||
|
|
( dwCertValidity & CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID ) ) {
|
|
DebugTrace((LPARAM)this,
|
|
"Server Cert/CTL is not signature valid");
|
|
|
|
dwMsgID = SSL_MSG_SIGNATURE_INVALID_SERVER_CERT;
|
|
}
|
|
|
|
if ( dwMsgID ) {
|
|
SmtpLogEvent( dwMsgID,
|
|
1,
|
|
apszMsgs,
|
|
0 );
|
|
}
|
|
}
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
|
|
}
|
|
|
|
|
|
VOID SMTP_SERVER_INSTANCE::LogCTLStatus()
|
|
/*++
|
|
Description:
|
|
|
|
Writes system log event about status of server CTL if CTL isn't valid
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
Nothing
|
|
--*/
|
|
{
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE::LogCTLStatus");
|
|
|
|
_ASSERT( m_pSSLInfo );
|
|
|
|
//
|
|
// If we didn't construct the CTL fully, log an error
|
|
//
|
|
if ( !m_pSSLInfo->QueryCTL()->IsValid() ) {
|
|
CONST CHAR *apszMsgs[2];
|
|
CHAR achInstance[20];
|
|
CHAR achErrorNumber[20];
|
|
wsprintf( achInstance,
|
|
"%lu",
|
|
QueryInstanceId() );
|
|
wsprintf( achErrorNumber,
|
|
"0x%x",
|
|
GetLastError() );
|
|
|
|
apszMsgs[0] = achInstance;
|
|
apszMsgs[1] = achErrorNumber;
|
|
|
|
DWORD dwStatus = m_pSSLInfo->QueryCTL()->QueryStatus();
|
|
DWORD dwStringID = 0;
|
|
|
|
DebugTrace((LPARAM)this,
|
|
"Couldn't retrieve server CTL; status : %d\n",
|
|
dwStatus);
|
|
|
|
switch ( dwStatus ) {
|
|
case CERT_ERR_MB:
|
|
dwStringID = SSL_MSG_CTL_MB_ERROR;
|
|
break;
|
|
|
|
case CERT_ERR_CAPI:
|
|
dwStringID = SSL_MSG_CTL_CAPI_ERROR;
|
|
break;
|
|
|
|
case CERT_ERR_CERT_NOT_FOUND:
|
|
dwStringID = SSL_MSG_CTL_NOT_FOUND;
|
|
break;
|
|
|
|
default:
|
|
dwStringID = SSL_MSG_CTL_INTERNAL_ERROR;
|
|
break;
|
|
}
|
|
|
|
SmtpLogEvent( dwStringID,
|
|
2,
|
|
apszMsgs,
|
|
0 );
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return;
|
|
}
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
}
|
|
|
|
|
|
BOOL
|
|
SmtpMappingSupportFunction(
|
|
PVOID pvInstance,
|
|
PVOID pData,
|
|
DWORD dwPropId)
|
|
{
|
|
if (dwPropId == SIMSSL_NOTIFY_MAPPER_SSLKEYS_CHANGED) {
|
|
return (SetSslKeysNotify( (PFN_SF_NOTIFY) pData));
|
|
} else if (dwPropId == SIMSSL_NOTIFY_MAPPER_CERT11_CHANGED ||
|
|
dwPropId == SIMSSL_NOTIFY_MAPPER_CERTW_CHANGED) {
|
|
return ( TRUE );
|
|
} else {
|
|
return ( FALSE );
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
SetSslKeysNotify(
|
|
PFN_SF_NOTIFY pFn
|
|
)
|
|
/*++
|
|
|
|
Description
|
|
|
|
Set the function called to notify SSL keys have changed
|
|
Can be called only once
|
|
|
|
Arguments:
|
|
|
|
pFn - function to call to notify SSL keys change
|
|
|
|
Returns:
|
|
|
|
TRUE if function reference stored, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
if ( g_pSslKeysNotify == NULL || pFn == NULL ) {
|
|
g_pSslKeysNotify = pFn;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
CAddr * SMTP_SERVER_INSTANCE::AppendLocalDomain (CAddr * OldAddress)
|
|
{
|
|
char ReWriteAddr [MAX_INTERNET_NAME + 1];
|
|
CAddr * NewAddress = NULL;
|
|
DWORD TotalSize = 0;
|
|
|
|
//If there is no domain on this address,
|
|
//then append the current domain to this
|
|
//address
|
|
|
|
m_GenLock.ShareLock();
|
|
|
|
TotalSize = lstrlen(OldAddress->GetAddress()) + lstrlen(GetDefaultDomain()) + 1; //+1 for the @
|
|
if ( TotalSize >= MAX_INTERNET_NAME) {
|
|
m_GenLock.ShareUnlock();
|
|
SetLastError(ERROR_INVALID_DATA);
|
|
return NULL;
|
|
}
|
|
|
|
lstrcpy(ReWriteAddr, OldAddress->GetAddress());
|
|
lstrcat(ReWriteAddr, "@");
|
|
|
|
lstrcat(ReWriteAddr, GetDefaultDomain());
|
|
m_GenLock.ShareUnlock();
|
|
|
|
//create a new CAddr
|
|
NewAddress = CAddr::CreateKnownAddress (ReWriteAddr);
|
|
|
|
return NewAddress;
|
|
}
|
|
|
|
BOOL SMTP_SERVER_INSTANCE::AppendLocalDomain(char * Address)
|
|
{
|
|
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE::AppendLocalDomain");
|
|
|
|
m_GenLock.ShareLock();
|
|
|
|
if ((lstrlen(Address) + lstrlen(GetDefaultDomain()) + 1) > MAX_INTERNET_NAME) {
|
|
//Our concatanated name will be larger than allowed name
|
|
ErrorTrace((LPARAM)this, "Generated address longer than allowed max");
|
|
m_GenLock.ShareUnlock();
|
|
return FALSE;
|
|
}
|
|
lstrcat(Address, "@");
|
|
lstrcat(Address, GetDefaultDomain());
|
|
|
|
m_GenLock.ShareUnlock();
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return TRUE;
|
|
}
|
|
|
|
CAddr * SMTP_SERVER_INSTANCE::MasqueradeDomain (CAddr * OldAddress)
|
|
{
|
|
char ReWriteAddr [MAX_INTERNET_NAME + 1];
|
|
CAddr * NewAddress = NULL;
|
|
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE::MasqueradeDomain");
|
|
|
|
m_GenLock.ShareLock();
|
|
|
|
if (m_fMasquerade) {
|
|
//if there is a domain in the name, get rid of it
|
|
//we are going to replace it with the masquerade
|
|
if (OldAddress->GetDomainOffset()) {
|
|
*(OldAddress->GetDomainOffset()) = '\0';
|
|
}
|
|
|
|
lstrcpy(ReWriteAddr, OldAddress->GetAddress());
|
|
lstrcat(ReWriteAddr, "@");
|
|
|
|
lstrcat(ReWriteAddr, m_szMasqueradeName);
|
|
|
|
//create a new CAddr
|
|
NewAddress = CAddr::CreateKnownAddress (ReWriteAddr);
|
|
}
|
|
|
|
m_GenLock.ShareUnlock();
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return NewAddress;
|
|
}
|
|
|
|
BOOL SMTP_SERVER_INSTANCE::MasqueradeDomain(char * Address, char * DomainPtr)
|
|
{
|
|
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE::MasqueradeDomain");
|
|
|
|
m_GenLock.ShareLock();
|
|
|
|
if (m_fMasquerade) {
|
|
//if there is a domain in the name, get rid of it
|
|
//we are going to replace it with the masquerade
|
|
if (DomainPtr) {
|
|
|
|
if ((DomainPtr - Address + lstrlen(m_szMasqueradeName)) > MAX_INTERNET_NAME) {
|
|
//Our concatanated name will be larger than allowed name
|
|
ErrorTrace((LPARAM)this, "Generated address longer than allowed max");
|
|
m_GenLock.ShareUnlock();
|
|
return FALSE;
|
|
}
|
|
lstrcpy(DomainPtr, m_szMasqueradeName);
|
|
} else {
|
|
if ((lstrlen(Address) + lstrlen(m_szMasqueradeName) + 1) > MAX_INTERNET_NAME) {
|
|
//Our concatanated name will be larger than allowed name
|
|
ErrorTrace((LPARAM)this, "Generated address longer than allowed max");
|
|
m_GenLock.ShareUnlock();
|
|
return FALSE;
|
|
}
|
|
lstrcat(Address, "@");
|
|
lstrcat(Address, m_szMasqueradeName);
|
|
}
|
|
|
|
}
|
|
|
|
m_GenLock.ShareUnlock();
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return TRUE;
|
|
}
|
|
|
|
extern BOOL IsIpInGlobalList(DWORD IpAddress);
|
|
|
|
BOOL SMTP_SERVER_INSTANCE::CompareIpAddress(DWORD IpAddress)
|
|
{
|
|
BOOL fRet = TRUE;
|
|
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE::CompareIpAddress");
|
|
|
|
if (IpAddress != g_LoopBackAddr) {
|
|
fRet = IsIpInGlobalList(IpAddress);
|
|
} else {
|
|
FatalTrace((LPARAM) this, "IpAddress %d is loopback - Failing connection", IpAddress);
|
|
}
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return fRet;
|
|
}
|
|
|
|
//Note : When connected port is passed in 0, it only does IP address comparison
|
|
//
|
|
BOOL SMTP_SERVER_INSTANCE::IsAddressMine(DWORD IpAddress, DWORD ConnectedPort)
|
|
{
|
|
char * Ptr = NULL;
|
|
const char * StartPtr = NULL;
|
|
const CHAR * ipAddressString = NULL;
|
|
const CHAR * ipPortString = NULL;
|
|
const CHAR * hostNameString = NULL;
|
|
const CHAR * end = NULL;
|
|
DWORD InetAddr = 0;
|
|
DWORD CharIpSize = 0;
|
|
CHAR temp[sizeof("123.123.123.123")];
|
|
INT length;
|
|
LONG tempPort;
|
|
BOOL BindingMatchFound = FALSE;
|
|
BOOL IpSame = FALSE;
|
|
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE::IsAddressMine");
|
|
|
|
//grab the sharing lock
|
|
|
|
m_GenLock.ShareLock();
|
|
|
|
if (m_ServerBindings.IsEmpty()) {
|
|
DebugTrace((LPARAM) this, "Server bindings is emtpy - checking all addresses");
|
|
|
|
m_GenLock.ShareUnlock();
|
|
|
|
IpSame = CompareIpAddress(IpAddress);
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return IpSame;
|
|
} else {
|
|
for (StartPtr = m_ServerBindings.First(); StartPtr != NULL; StartPtr = m_ServerBindings.Next( StartPtr )) {
|
|
ipAddressString = StartPtr;
|
|
|
|
ipPortString = strchr(StartPtr, ':');
|
|
|
|
if (ipPortString == NULL) {
|
|
goto out;
|
|
}
|
|
|
|
ipPortString++;
|
|
|
|
hostNameString = strchr( ipPortString, ':' );
|
|
|
|
if ( hostNameString == NULL ) {
|
|
goto out;
|
|
}
|
|
|
|
hostNameString++;
|
|
|
|
//
|
|
// Validate and parse the IP address portion.
|
|
//
|
|
|
|
if ( *ipAddressString == ':' ) {
|
|
InetAddr = INADDR_ANY;
|
|
|
|
} else {
|
|
length = DIFF(ipPortString - ipAddressString) - 1;
|
|
|
|
if ( length > sizeof(temp) ) {
|
|
goto out;
|
|
}
|
|
|
|
CopyMemory( temp, ipAddressString, length);
|
|
|
|
temp[length] = '\0';
|
|
|
|
InetAddr = (DWORD)inet_addr( temp );
|
|
|
|
if ( InetAddr == INADDR_NONE ) {
|
|
goto out;
|
|
}
|
|
|
|
}//end else of if( *ipAddressString == ':' )
|
|
|
|
//
|
|
// Validate and parse the port.
|
|
//
|
|
|
|
if ( *ipPortString == ':' ) {
|
|
goto out;
|
|
}
|
|
|
|
length = (INT)(hostNameString - ipPortString);
|
|
|
|
if ( length > sizeof(temp) ) {
|
|
goto out;
|
|
}
|
|
|
|
CopyMemory(temp,ipPortString, length);
|
|
|
|
temp[length] = '\0';
|
|
|
|
tempPort = strtol( temp, (CHAR **)&end, 0 );
|
|
|
|
if ( tempPort <= 0 || tempPort > 0xFFFF ) {
|
|
goto out;
|
|
}
|
|
|
|
if ( *end != ':' ) {
|
|
goto out;
|
|
}
|
|
|
|
if (InetAddr == INADDR_ANY) {
|
|
IpSame = CompareIpAddress(IpAddress);
|
|
|
|
if (IpSame && ((DWORD) tempPort == ConnectedPort) && (ConnectedPort > 0)) {
|
|
BindingMatchFound = TRUE;
|
|
goto out;
|
|
} else if (IpSame && (ConnectedPort == 0)) {
|
|
BindingMatchFound = TRUE;
|
|
goto out;
|
|
}
|
|
} else if ( (IpAddress == InetAddr) && ((DWORD) tempPort == ConnectedPort) && (ConnectedPort > 0)) {
|
|
FatalTrace((LPARAM) this, "IpAddress %d is one of mine - Failing connection", IpAddress);
|
|
BindingMatchFound = TRUE;
|
|
goto out;
|
|
} else if ( (IpAddress == InetAddr) && (ConnectedPort == 0)) {
|
|
BindingMatchFound = TRUE;
|
|
goto out;
|
|
}
|
|
|
|
}//end for
|
|
}//end else
|
|
|
|
out:
|
|
|
|
m_GenLock.ShareUnlock();
|
|
|
|
if (!BindingMatchFound)
|
|
DebugTrace((LPARAM) this, "IpAddress %d is not one of mine", IpAddress);
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return BindingMatchFound;
|
|
}
|
|
|
|
BOOL SMTP_SERVER_INSTANCE::MoveToBadMail ( IMailMsgProperties *pIMsg, BOOL fUseIMsg, char * MailFile, char * FilePath)
|
|
{
|
|
TCHAR BadMailDir[MAX_PATH + 1];
|
|
TCHAR MailPath [MAX_PATH + 1];
|
|
TCHAR StreamPath[MAX_PATH + 1];
|
|
char * pszSearch = NULL;
|
|
BOOL f = TRUE;
|
|
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE::MoveToBadMail");
|
|
|
|
//concatenate the name of the stream to the file
|
|
lstrcpy(MailPath, FilePath);
|
|
lstrcat(MailPath, MailFile);
|
|
|
|
m_GenLock.ShareLock();
|
|
f = SUCCEEDED(m_IAQ->HandleFailedMessage(pIMsg, fUseIMsg, MailPath, MESSAGE_FAILURE_BAD_PICKUP_DIR_FILE, E_FAIL));
|
|
m_GenLock.ShareUnlock();
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return f;
|
|
}
|
|
|
|
#define NTFS_STORE_DIRECTORY_REG_PATH _T("Software\\Microsoft\\Exchange\\StoreDriver\\Ntfs\\%u")
|
|
#define NTFS_STORE_DIRECTORY_REG_NAME _T("StoreDir")
|
|
#define NTFS_STORE_BACKSLASH _T("\\")
|
|
#define NTFS_QUEUE_DIRECTORY_SUFFIX _T("\\Queue")
|
|
#define NTFS_DROP_DIRECTORY_SUFFIX _T("\\Drop")
|
|
|
|
/*++
|
|
Description:
|
|
Initializes server configuration data from registry for SMTP Service.
|
|
Some values are also initialized with constants.
|
|
If invalid registry key or load data from registry fails,
|
|
then use default values.
|
|
|
|
Arguments: None
|
|
|
|
Returns:
|
|
|
|
TRUE if there are no errors.
|
|
|
|
Limitations:
|
|
|
|
No validity check is performed on the data present in registry.
|
|
--*/
|
|
BOOL SMTP_SERVER_INSTANCE::InitFromRegistry(void)
|
|
{
|
|
LONG err = 0;
|
|
DWORD dwErr = 0;
|
|
DWORD SizeOfBuffer = 0;
|
|
HKEY hkeyTcpipParam = NULL;
|
|
BOOL fRet = FALSE;
|
|
|
|
//char szHostName[MAX_PATH + 1];
|
|
// const CHAR * apszSubStrings[2];
|
|
|
|
CHAR pchAddr1[32] = "";
|
|
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE::InitFromRegistry");
|
|
|
|
_itoa(QueryInstanceId(), pchAddr1, 10);
|
|
|
|
//
|
|
// This is added by KeithLau on 7/15/96
|
|
// This method loads the registry values that cannot be accessed
|
|
// through the RPC's
|
|
//
|
|
if (!ReadStartupRegParams()) {
|
|
ErrorTrace((LPARAM) this, "Read startup params failed.");
|
|
goto Exit;
|
|
}
|
|
|
|
if (!StartAdvancedQueueing()) {
|
|
DebugTrace((LPARAM)this, "Unable to load Advanced Queueing module\n");
|
|
goto Exit;
|
|
}
|
|
|
|
fInitializedAQ = TRUE;
|
|
|
|
//
|
|
// Metabase Structures... can change at runtime
|
|
// Turn off FC_SMTP_INFO_DEFAULT_DROP_DIR since
|
|
// we already read it in ReadStartupRegParams()
|
|
|
|
if (!ReadRegParams(FC_SMTP_INFO_ALL & ~FC_SMTP_INFO_DEFAULT_DROP_DIR, TRUE, FALSE))
|
|
{
|
|
ErrorTrace((LPARAM) this, "Read params failed.");
|
|
goto Exit;
|
|
}
|
|
|
|
if (!InitQueues()) {
|
|
err= GetLastError();
|
|
ErrorTrace((LPARAM) this, "can't init queue err = %d", err);
|
|
if (err == NO_ERROR)
|
|
err = ERROR_INVALID_PARAMETER;
|
|
|
|
SetLastError(err);
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
fRet = TRUE;
|
|
|
|
Exit:
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return fRet;
|
|
}
|
|
|
|
/*++
|
|
|
|
Adds the new client connection to the list
|
|
of client connections and increments the count of
|
|
clients currently connected to server.
|
|
If the count of max connections is exceeded, then the
|
|
new connection is rejected.
|
|
|
|
Arguments:
|
|
|
|
pcc pointer to client connection to be added
|
|
|
|
Returns:
|
|
TRUE on success and
|
|
FALSE if there is max Connections exceeded.
|
|
--*/
|
|
CLIENT_CONNECTION * SMTP_SERVER_INSTANCE::CreateNewConnection( IN OUT PCLIENT_CONN_PARAMS ClientParam)
|
|
{
|
|
|
|
SMTP_CONNECTION * NewConnection = NULL;
|
|
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE::InsertNewConnection");
|
|
|
|
// We will not accept new connections until the intial queue is built
|
|
if (!m_fShouldStartAcceptingConnections || IsShuttingDown()) {
|
|
return (NULL);
|
|
}
|
|
|
|
NewConnection = SMTP_CONNECTION::CreateSmtpConnection (ClientParam, this);
|
|
if (NewConnection != NULL) {
|
|
|
|
BUMP_COUNTER(this, NumConnInOpen);
|
|
|
|
LockConfig();
|
|
|
|
// Increment the count of connected users
|
|
m_cCurrentConnections++;
|
|
|
|
// Update the current maximum connections
|
|
if ( m_cCurrentConnections > m_cMaxCurrentConnections) {
|
|
m_cMaxCurrentConnections = m_cCurrentConnections;
|
|
}
|
|
|
|
//set the client unique ID
|
|
NewConnection->SetClientId(m_dwNextInboundClientId);
|
|
|
|
m_dwNextInboundClientId++;
|
|
|
|
//
|
|
// Insert into the list of connected users.
|
|
//
|
|
InsertTailList( &m_ConnectionsList, &NewConnection->QueryListEntry());
|
|
|
|
DebugTrace((LPARAM) this, "SMTP_SERVER_INSTANCE:InsertNewConnection succeeded");
|
|
|
|
UnLockConfig();
|
|
}
|
|
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return ( NewConnection);
|
|
|
|
}
|
|
|
|
|
|
void SMTP_SERVER_INSTANCE::StopHint()
|
|
{
|
|
if ( g_pInetSvc && g_pInetSvc->QueryCurrentServiceState() == SERVICE_STOP_PENDING) {
|
|
|
|
// 10/28/98 - MikeSwa
|
|
//Use stop hint 30 seconds to avoid problems with commiting many
|
|
//messages on shutdown. (the previous limit of 10 seconds seemed
|
|
//to cause problems with the service control manager).
|
|
g_pInetSvc->UpdateServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, m_dwStopHint,
|
|
30000 ) ;
|
|
|
|
m_dwStopHint++ ;
|
|
}
|
|
}
|
|
|
|
/*++
|
|
|
|
Disconnects all user connections.
|
|
|
|
--*/
|
|
VOID SMTP_SERVER_INSTANCE::DisconnectAllConnections( VOID)
|
|
{
|
|
int iteration = 0;
|
|
int i = 0;
|
|
int Count = 0;
|
|
LONG cLastThreadCount = 0;
|
|
DWORD dwLastAllocCount = 0;
|
|
DWORD dwAllocCount;
|
|
int AfterSleepCount = 0;
|
|
DWORD dwStopHint = 2;
|
|
DWORD dwTickCount;
|
|
DWORD dwError = 0;
|
|
PLIST_ENTRY pEntry = NULL;
|
|
SMTP_CONNECTION * pConn = NULL;
|
|
|
|
TraceFunctEnter("SMTP_SERVER_INSTANCE::DisconnectAllConnections( VOID)");
|
|
|
|
if (m_fShutdownCalled) {
|
|
DebugTrace((LPARAM)this, "m_fShutdownCalled already -- leaving");
|
|
TraceFunctLeaveEx((LPARAM) this);
|
|
}
|
|
|
|
//set the global termination flag
|
|
m_IsShuttingDown = TRUE;
|
|
|
|
LockConfig();
|
|
|
|
TriggerStoreServerEvent(SMTP_STOREDRV_PREPSHUTDOWN_EVENT);
|
|
m_fStoreDrvPrepShutDownEventCalled = TRUE;
|
|
|
|
//close down all the active sockets.
|
|
for ( pEntry = m_ConnectionsList.Flink; pEntry != &m_ConnectionsList; pEntry = pEntry->Flink) {
|
|
|
|
//get the next connection object
|
|
pConn = (SMTP_CONNECTION *) CONTAINING_RECORD( pEntry, CLIENT_CONNECTION, m_listEntry);
|
|
_ASSERT( pConn != NULL);
|
|
|
|
//call the disconnect routine. DisconnectClient() just closes the socket.
|
|
//This will cause all pending I/Os to fail, and have the connections
|
|
//bubble up to the completion routine where they will be removed from
|
|
//the connection list and then distroyed
|
|
pConn->DisconnectClient( ERROR_SERVER_DISABLED);
|
|
}
|
|
|
|
UnLockConfig();
|
|
|
|
DebugTrace((LPARAM)this, "Cancelling all outstanding SQL queries");
|
|
|
|
|
|
//
|
|
// Wait for the users to die.
|
|
// The connection objects should be automatically freed because the
|
|
// socket has been closed. Subsequent requests will fail
|
|
// and cause a blowaway of the connection objects.
|
|
// looping is used to get out as early as possible when m_cCurrentConn == 0
|
|
//
|
|
|
|
//
|
|
// need to check Pool.GetAllocCount instead of InUseList.Empty
|
|
// because alloc goes to zero during the delete operator
|
|
// instead of during the destructor
|
|
//
|
|
// We sleep at most 120 seconds for a fixed user count.
|
|
//
|
|
|
|
dwTickCount = GetTickCount();
|
|
cLastThreadCount = GetProcessClientThreads();
|
|
for (i = 0; i < 180; i++) {
|
|
DebugTrace((LPARAM)this, "Waiting for connections to die, i = %u", i);
|
|
// dwAllocCount = SMTP_CONNECTION::Pool.GetAllocCount();
|
|
dwAllocCount = (DWORD) GetConnInAllocCount();
|
|
if (dwAllocCount == 0 && GetProcessClientThreads() == 0) {
|
|
DebugTrace((LPARAM)this, "All SMTP_CONNECTIONs connections are gone!");
|
|
break;
|
|
}
|
|
|
|
Sleep(1000);
|
|
|
|
// Update the stop hint checkpoint when we get within 1 second (1000 ms), of the timeout...
|
|
if ((SERVICE_STOP_WAIT_HINT - 1000) < (GetTickCount() - dwTickCount) && g_pInetSvc &&
|
|
g_pInetSvc->QueryCurrentServiceState() == SERVICE_STOP_PENDING) {
|
|
DebugTrace((LPARAM)this, "Updating stop hint, checkpoint = %u", dwStopHint);
|
|
|
|
g_pInetSvc->UpdateServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, dwStopHint,
|
|
SERVICE_STOP_WAIT_HINT ) ;
|
|
|
|
dwStopHint++ ;
|
|
dwTickCount = GetTickCount();
|
|
}
|
|
|
|
DebugTrace((LPARAM)this, "Alloc counts: current = %u, last = %u; Thread counts: current = %d, last = %d",
|
|
dwAllocCount, dwLastAllocCount, GetProcessClientThreads(), cLastThreadCount);
|
|
if (dwAllocCount < dwLastAllocCount || GetProcessClientThreads() < cLastThreadCount) {
|
|
DebugTrace((LPARAM)this, "SMTP_CONNECTION Connections are going away, reseting i");
|
|
i = 0;
|
|
}
|
|
|
|
dwLastAllocCount = dwAllocCount;
|
|
cLastThreadCount = GetProcessClientThreads();
|
|
}
|
|
|
|
if (i == 180) {
|
|
ErrorTrace((LPARAM) this, "%d users won't die", m_cCurrentConnections);
|
|
//
|
|
// once we're thru do it again to find any stray clients
|
|
//
|
|
LockConfig();
|
|
|
|
for (pEntry = m_ConnectionsList.Flink;
|
|
pEntry != &m_ConnectionsList;
|
|
pEntry = pEntry->Flink ) {
|
|
//
|
|
// get the next connection object
|
|
//
|
|
pConn = (SMTP_CONNECTION *)CONTAINING_RECORD(pEntry, CLIENT_CONNECTION, m_listEntry);
|
|
_ASSERT(pConn != NULL);
|
|
|
|
ErrorTrace( (LPARAM)pConn, "Stray client" );
|
|
}
|
|
UnLockConfig();
|
|
}
|
|
|
|
|
|
DebugTrace( (LPARAM)this, "SMTP_CONNECTION Count at end is: %d", SMTP_CONNECTION::Pool.GetAllocCount() );
|
|
|
|
TraceFunctLeaveEx((LPARAM) this);
|
|
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Removes the current connection from the list of conenctions
|
|
and decrements count of connected users
|
|
|
|
Arguments:
|
|
|
|
pcc pointer to client connection to be removed
|
|
|
|
--*/
|
|
VOID SMTP_SERVER_INSTANCE::RemoveConnection( IN OUT CLIENT_CONNECTION * pConn)
|
|
{
|
|
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE::RemoveConnection");
|
|
|
|
_ASSERT( pConn != NULL);
|
|
|
|
LockConfig();
|
|
|
|
// Remove from list of connections
|
|
RemoveEntryList( &pConn->QueryListEntry());
|
|
|
|
// Decrement count of current users
|
|
m_cCurrentConnections--;
|
|
|
|
BUMP_COUNTER(this, NumConnInClose);
|
|
|
|
UnLockConfig();
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
|
|
} // SMTP_SERVER_INSTANCE::RemoveConnection()
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Adds the new client connection to the list
|
|
of outbound client connections and increments the count of
|
|
outbound clients currently connected to server.
|
|
|
|
Arguments:
|
|
|
|
pcc pointer to client connection to be added
|
|
|
|
Returns:
|
|
TRUE on success and
|
|
FALSE if there is max Connections exceeded.
|
|
--*/
|
|
BOOL SMTP_SERVER_INSTANCE::InsertNewOutboundConnection( IN OUT CLIENT_CONNECTION * pcc, BOOL ByPassLimitCheck)
|
|
{
|
|
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE::InsertNewOutboundConnection");
|
|
|
|
_ASSERT( pcc != NULL);
|
|
|
|
m_OutLock.ExclusiveLock();
|
|
|
|
// Increment the count of connected users
|
|
m_cCurrentOutConnections++;
|
|
|
|
//set the client unique ID
|
|
pcc->SetClientId(m_dwNextOutboundClientId);
|
|
|
|
m_dwNextInboundClientId++;
|
|
|
|
// Insert into the list of connected outbound users.
|
|
InsertTailList( &m_OutConnectionsList, &pcc->QueryListEntry());
|
|
|
|
m_OutLock.ExclusiveUnlock();
|
|
|
|
BUMP_COUNTER(this, NumConnOutOpen);
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL SMTP_SERVER_INSTANCE::InsertAsyncDnsObject( IN OUT CAsyncSmtpDns *pcc)
|
|
{
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE::InsertAsyncDnsObj");
|
|
|
|
_ASSERT( pcc != NULL);
|
|
|
|
EnterCriticalSection( &m_csAsyncDns ) ;
|
|
|
|
IncAsyncDnsObjs();
|
|
|
|
BUMP_COUNTER(this, RoutingTableLookups);
|
|
|
|
// Insert into the list of connected outbound users.
|
|
InsertTailList( &m_AsyncDnsList, &pcc->QueryListEntry());
|
|
|
|
LeaveCriticalSection( &m_csAsyncDns ) ;
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return TRUE;
|
|
}
|
|
|
|
VOID SMTP_SERVER_INSTANCE::RemoveAsyncDnsObject( IN OUT CAsyncSmtpDns * pConn)
|
|
{
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE::RemoveAsyncDnsObject");
|
|
|
|
_ASSERT( pConn != NULL);
|
|
|
|
EnterCriticalSection( &m_csAsyncDns ) ;
|
|
|
|
// Remove from list of connections
|
|
RemoveEntryList( &pConn->QueryListEntry());
|
|
|
|
DecAsyncDnsObjs();
|
|
|
|
DROP_COUNTER(this, RoutingTableLookups);
|
|
|
|
LeaveCriticalSection( &m_csAsyncDns ) ;
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
|
|
} // SMTP_SERVER_INSTANCE::RemoveAsyncObject()
|
|
|
|
|
|
VOID SMTP_SERVER_INSTANCE::DisconnectAllAsyncDnsConnections( VOID)
|
|
{
|
|
|
|
int iteration = 0;
|
|
int i = 0;
|
|
int Count = 0;
|
|
DWORD dwLastAllocCount = 0;
|
|
DWORD dwAllocCount;
|
|
int AfterSleepCount = 0;
|
|
DWORD dwStopHint = 2;
|
|
DWORD dwTickCount;
|
|
DWORD dwError = 0;
|
|
PLIST_ENTRY pEntry = NULL;
|
|
CAsyncSmtpDns * pConn = NULL;
|
|
|
|
TraceFunctEnter("SMTP_SERVER_INSTANCE::DisconnectAllAsyncDnsConnections( VOID)");
|
|
|
|
if (m_fShutdownCalled) {
|
|
DebugTrace((LPARAM)this, "m_fShutdownCalled already -- leaving");
|
|
TraceFunctLeaveEx((LPARAM) this);
|
|
}
|
|
|
|
EnterCriticalSection( &m_csAsyncDns ) ;
|
|
|
|
//close down all the active sockets.
|
|
for ( pEntry = m_AsyncDnsList.Flink; pEntry != &m_AsyncDnsList; pEntry = pEntry->Flink) {
|
|
|
|
//get the next connection object
|
|
pConn = (CAsyncSmtpDns *) CONTAINING_RECORD( pEntry, CAsyncSmtpDns, m_ListEntry);
|
|
_ASSERT( pConn != NULL);
|
|
|
|
//call the disconnect routine. DisconnectClient() just closes the socket.
|
|
//This will cause all pending I/Os to fail, and have the connections
|
|
//"bubble up to the completion routine where they will be removed from
|
|
//the connection list and then distroyed
|
|
pConn->DisconnectClient();
|
|
}
|
|
|
|
LeaveCriticalSection( &m_csAsyncDns ) ;
|
|
|
|
|
|
//
|
|
// Wait for the users to die.
|
|
// The connection objects should be automatically freed because the
|
|
// socket has been closed. Subsequent requests will fail
|
|
// and cause a blowaway of the connection objects.
|
|
// looping is used to get out as early as possible when m_cCurrentConn == 0
|
|
//
|
|
|
|
//
|
|
// need to check Pool.GetAllocCount instead of InUseList.Empty
|
|
// because alloc goes to zero during the delete operator
|
|
// instead of during the destructor
|
|
//
|
|
// We sleep at most 120 seconds for a fixed user count.
|
|
//
|
|
|
|
dwTickCount = GetTickCount();
|
|
for (i = 0; i < 500; i++) {
|
|
DebugTrace((LPARAM)this, "Waiting for connections to die, i = %u", i);
|
|
dwAllocCount = (DWORD) GetAsyncDnsAllocCount ();
|
|
if (dwAllocCount == 0) {
|
|
DebugTrace((LPARAM)this, "All SMTP DNS connections are gone!");
|
|
break;
|
|
}
|
|
|
|
Sleep(1000);
|
|
|
|
// Update the stop hint checkpoint when we get within 1 second (1000 ms), of the timeout...
|
|
if ((SERVICE_STOP_WAIT_HINT - 1000) < (GetTickCount() - dwTickCount) && g_pInetSvc &&
|
|
g_pInetSvc->QueryCurrentServiceState() == SERVICE_STOP_PENDING) {
|
|
DebugTrace((LPARAM)this, "Updating stop hint, checkpoint = %u", dwStopHint);
|
|
|
|
g_pInetSvc->UpdateServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, dwStopHint,
|
|
SERVICE_STOP_WAIT_HINT ) ;
|
|
|
|
dwStopHint++ ;
|
|
dwTickCount = GetTickCount();
|
|
}
|
|
|
|
DebugTrace((LPARAM)this, "Alloc counts: current = %u, last = %u",
|
|
dwAllocCount, dwLastAllocCount);
|
|
if (dwAllocCount < dwLastAllocCount) {
|
|
DebugTrace((LPARAM)this, "SMTP DNS Connections are going away, reseting i");
|
|
i = 0;
|
|
}
|
|
|
|
dwLastAllocCount = dwAllocCount;
|
|
}
|
|
|
|
if (i == 500) {
|
|
ErrorTrace((LPARAM) this, "%d users won't die", m_cCurrentConnections);
|
|
//
|
|
// once we're thru do it again to find any stray clients
|
|
//
|
|
EnterCriticalSection( &m_csAsyncDns ) ;
|
|
|
|
for (pEntry = m_AsyncDnsList.Flink;
|
|
pEntry != &m_AsyncDnsList;
|
|
pEntry = pEntry->Flink ) {
|
|
//
|
|
// get the next connection object
|
|
//
|
|
pConn = (CAsyncSmtpDns *)CONTAINING_RECORD(pEntry, CAsyncSmtpDns, m_ListEntry);
|
|
_ASSERT(pConn != NULL);
|
|
|
|
ErrorTrace( (LPARAM)pConn, "Stray client" );
|
|
}
|
|
LeaveCriticalSection( &m_csAsyncDns ) ;
|
|
|
|
}
|
|
|
|
|
|
DebugTrace( (LPARAM)this, "SMTP DNS Count at end is: %d", CAsyncSmtpDns::Pool.GetAllocCount() );
|
|
TraceFunctLeaveEx((LPARAM) this);
|
|
}
|
|
|
|
BOOL SMTP_SERVER_INSTANCE::InsertAsyncObject( IN OUT CAsyncMx *pcc)
|
|
{
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE::InsertNewAsyncConnection");
|
|
|
|
_ASSERT( pcc != NULL);
|
|
|
|
m_OutLock.ExclusiveLock();
|
|
|
|
IncAsyncMxOutObjs();
|
|
|
|
// Insert into the list of connected outbound users.
|
|
InsertTailList( &m_AsynConnectList, &pcc->QueryListEntry());
|
|
|
|
m_OutLock.ExclusiveUnlock();
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return TRUE;
|
|
}
|
|
|
|
VOID SMTP_SERVER_INSTANCE::RemoveAsyncObject( IN OUT CAsyncMx * pConn)
|
|
{
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE::RemoveAsyncObject");
|
|
|
|
_ASSERT( pConn != NULL);
|
|
|
|
m_OutLock.ExclusiveLock();
|
|
|
|
// Remove from list of connections
|
|
RemoveEntryList( &pConn->QueryListEntry());
|
|
|
|
DecAsyncMxOutObjs();
|
|
|
|
m_OutLock.ExclusiveUnlock();
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
|
|
} // SMTP_SERVER_INSTANCE::RemoveAsyncObject()
|
|
|
|
VOID SMTP_SERVER_INSTANCE::DisconnectAllAsyncConnections( VOID)
|
|
{
|
|
PLIST_ENTRY pEntry = NULL;
|
|
CAsyncMx * pConn = NULL;
|
|
int iteration = 0;
|
|
int i = 0;
|
|
int Count = 0;
|
|
LONG cLastThreadCount = 0;
|
|
DWORD dwLastAllocCount = 0;
|
|
DWORD dwAllocCount;
|
|
int AfterSleepCount = 0;
|
|
DWORD dwStopHint = 2;
|
|
DWORD dwTickCount;
|
|
DWORD dwError = 0;
|
|
|
|
TraceFunctEnter("SMTP_SERVER_INSTANCE::DisconnectAllAsynConnections( VOID)");
|
|
|
|
#if 0
|
|
|
|
//close down all the active sockets.
|
|
for ( pEntry = m_AsynConnectList.Flink; pEntry != &m_AsynConnectList; pEntry = pEntry->Flink) {
|
|
//get the next connection object
|
|
pConn = (CAsyncMx *) CONTAINING_RECORD( pEntry, CAsyncMx, m_ListEntry);
|
|
_ASSERT( pConn != NULL);
|
|
|
|
pConn->SignalObject( );
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Wait for the users to die.
|
|
// The connection objects should be automatically freed because the
|
|
// socket has been closed. Subsequent requests will fail
|
|
// and cause a blowaway of the connection objects.
|
|
// looping is used to get out as early as possible when m_cCurrentConn == 0
|
|
//
|
|
|
|
//
|
|
// need to check Pool.GetAllocCount instead of InUseList.Empty
|
|
// because alloc goes to zero during the delete operator
|
|
// instead of during the destructor
|
|
//
|
|
// We sleep at most 120 seconds for a fixed user count.
|
|
//
|
|
|
|
dwTickCount = GetTickCount();
|
|
for (i = 0; i < 500; i++) {
|
|
DebugTrace((LPARAM)this, "Waiting for async connections to die, i = %u", i);
|
|
dwAllocCount = (DWORD) GetAsyncMxOutAllocCount();
|
|
if (dwAllocCount == 0) {
|
|
DebugTrace((LPARAM)this, "All CASYNCMXs connections are gone!");
|
|
break;
|
|
}
|
|
|
|
Sleep(1000);
|
|
|
|
// Update the stop hint checkpoint when we get within 1 second (1000 ms), of the timeout...
|
|
if ((SERVICE_STOP_WAIT_HINT - 1000) < (GetTickCount() - dwTickCount) && g_pInetSvc &&
|
|
g_pInetSvc->QueryCurrentServiceState() == SERVICE_STOP_PENDING) {
|
|
DebugTrace((LPARAM)this, "Updating stop hint, checkpoint = %u", dwStopHint);
|
|
|
|
g_pInetSvc->UpdateServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, dwStopHint,
|
|
SERVICE_STOP_WAIT_HINT ) ;
|
|
|
|
dwStopHint++ ;
|
|
dwTickCount = GetTickCount();
|
|
}
|
|
|
|
DebugTrace((LPARAM)this, "Alloc counts: current = %u, last = %u; Thread counts: current = %d, last = %d",
|
|
dwAllocCount, dwLastAllocCount, GetProcessClientThreads(), cLastThreadCount);
|
|
if (dwAllocCount < dwLastAllocCount) {
|
|
DebugTrace((LPARAM)this, "CASYNCMX Connections are going away, resetting i");
|
|
i = 0;
|
|
}
|
|
|
|
dwLastAllocCount = dwAllocCount;
|
|
}
|
|
|
|
if (i == 500) {
|
|
ErrorTrace((LPARAM) this, "%d users won't die", m_cNumAsyncObjsAlloced);
|
|
//
|
|
// once we're thru do it again to find any stray clients
|
|
//
|
|
m_OutLock.ExclusiveLock();
|
|
|
|
for (pEntry = m_ConnectionsList.Flink;
|
|
pEntry != &m_ConnectionsList;
|
|
pEntry = pEntry->Flink ) {
|
|
//
|
|
// get the next connection object
|
|
//
|
|
pConn = (CAsyncMx *)CONTAINING_RECORD(pEntry, CAsyncMx, m_ListEntry);
|
|
_ASSERT(pConn != NULL);
|
|
|
|
ErrorTrace( (LPARAM)pConn, "Stray client" );
|
|
}
|
|
|
|
m_OutLock.ExclusiveUnlock();
|
|
}
|
|
|
|
|
|
DebugTrace( (LPARAM)this, "CASYNCMX Count at end is: %d", m_cNumAsyncObjsAlloced);
|
|
TraceFunctLeaveEx((LPARAM) this);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Disconnects all user connections.
|
|
|
|
--*/
|
|
VOID SMTP_SERVER_INSTANCE::DisconnectAllOutboundConnections( VOID)
|
|
{
|
|
int iteration = 0;
|
|
int i = 0;
|
|
int Count = 0;
|
|
DWORD dwLastAllocCount = 0;
|
|
DWORD dwAllocCount;
|
|
int AfterSleepCount = 0;
|
|
DWORD dwStopHint = 2;
|
|
DWORD dwTickCount;
|
|
PLIST_ENTRY pEntry = NULL;
|
|
CLIENT_CONNECTION * pConn = NULL;
|
|
|
|
TraceFunctEnterEx((LPARAM)this, "SMTP_SERVER_INSTANCE::DisconnectAllOutboundConnections( VOID)");
|
|
|
|
if (m_fShutdownCalled) {
|
|
DebugTrace((LPARAM)this, "m_fShutdownCalled already -- leaving");
|
|
TraceFunctLeaveEx((LPARAM) this);
|
|
}
|
|
|
|
m_OutLock.ExclusiveLock();
|
|
|
|
|
|
//close down all the active sockets.
|
|
for ( pEntry = m_OutConnectionsList.Flink; pEntry != &m_OutConnectionsList; pEntry = pEntry->Flink) {
|
|
|
|
//get the next connection object
|
|
pConn = CONTAINING_RECORD( pEntry, CLIENT_CONNECTION, m_listEntry);
|
|
_ASSERT( pConn != NULL);
|
|
|
|
//call the disconnect routine. DisconnectClient() just closes the socket.
|
|
//This will cause all pending I/Os to fail, and have the connections
|
|
//"bubble up to the completion routine where they will be removed from
|
|
//the connection list and then distroyed
|
|
pConn->DisconnectClient( ERROR_SERVER_DISABLED);
|
|
}
|
|
|
|
m_OutLock.ExclusiveUnlock();
|
|
|
|
//
|
|
// Wait for the users to die.
|
|
// The connection objects should be automatically freed because the
|
|
// socket has been closed. Subsequent requests will fail
|
|
// and cause a blowaway of the connection objects.
|
|
// looping is used to get out as early as possible when m_cCurrentConn == 0
|
|
//
|
|
|
|
|
|
//
|
|
// Wait for the users to die.
|
|
// The connection objects should be automatically freed because the
|
|
// socket has been closed. Subsequent requests will fail
|
|
// and cause a blowaway of the connection objects.
|
|
// looping is used to get out as early as possible when m_cCurrentConn == 0
|
|
//
|
|
|
|
//
|
|
// need to check Pool.GetAllocCount instead of InUseList.Empty
|
|
// because alloc goes to zero during the delete operator
|
|
// instead of during the destructor
|
|
//
|
|
// We sleep at most 180 seconds for a fixed user count.
|
|
//
|
|
dwTickCount = GetTickCount();
|
|
for (i = 0; i < 180; i++) {
|
|
DebugTrace((LPARAM)this, "Waiting for connections to die, i = %u", i);
|
|
dwAllocCount = (DWORD) GetConnOutAllocCount();
|
|
if (dwAllocCount == 0) {
|
|
DebugTrace((LPARAM)this, "All SMTP_CONNOUTs connections are gone!");
|
|
break;
|
|
}
|
|
|
|
Sleep(1000);
|
|
|
|
// Update the stop hint checkpoint when we get within 1 second (1000 ms), of the timeout...
|
|
if ((SERVICE_STOP_WAIT_HINT - 1000) < (GetTickCount() - dwTickCount) && g_pInetSvc &&
|
|
g_pInetSvc->QueryCurrentServiceState() == SERVICE_STOP_PENDING) {
|
|
DebugTrace((LPARAM)this, "Updating stop hint, checkpoint = %u", dwStopHint);
|
|
|
|
g_pInetSvc->UpdateServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, dwStopHint,
|
|
SERVICE_STOP_WAIT_HINT ) ;
|
|
|
|
dwStopHint++ ;
|
|
dwTickCount = GetTickCount();
|
|
}
|
|
|
|
DebugTrace((LPARAM)this, "Alloc counts: current = %u, last = %u", dwAllocCount, dwLastAllocCount);
|
|
if (dwAllocCount < dwLastAllocCount) {
|
|
DebugTrace((LPARAM)this, "SMTP_CONNECTION Connections are going away, resetting i");
|
|
i = 0;
|
|
}
|
|
|
|
dwLastAllocCount = dwAllocCount;
|
|
}
|
|
|
|
|
|
DebugTrace( (LPARAM)this, "SMTP_CONNOUT Count at end is: %d", SMTP_CONNECTION::Pool.GetAllocCount() );
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Removes the current connection from the list of conenctions
|
|
and decrements count of connected users
|
|
|
|
Arguments:
|
|
|
|
pcc pointer to client connection to be removed
|
|
|
|
--*/
|
|
VOID SMTP_SERVER_INSTANCE::RemoveOutboundConnection( IN OUT CLIENT_CONNECTION * pConn)
|
|
{
|
|
_ASSERT( pConn != NULL);
|
|
|
|
m_OutLock.ExclusiveLock();
|
|
|
|
// Remove from list of connections
|
|
RemoveEntryList( &pConn->QueryListEntry());
|
|
|
|
// Decrement count of current users
|
|
m_cCurrentOutConnections--;
|
|
|
|
BUMP_COUNTER(this, NumConnOutClose);
|
|
|
|
m_OutLock.ExclusiveUnlock();
|
|
|
|
|
|
} // SMTP_SERVER_INSTANCE::RemoveConnection()
|
|
|
|
BOOL SMTP_SERVER_INSTANCE::InitDirectoryNotification(void)
|
|
{
|
|
char MailPickUp[MAX_PATH + 1];
|
|
|
|
TraceFunctEnterEx((LPARAM)this, "InitDirectoryNotification");
|
|
|
|
lstrcpy(MailPickUp, GetMailPickupDir());
|
|
|
|
//get rid of the \\ at the end of the name
|
|
if (MailPickUp [GetMailPickupDirLength() - 1] == '\\')
|
|
MailPickUp [GetMailPickupDirLength() - 1] = '\0';
|
|
|
|
//create an outbound connectiong_SmtpConfig->GetMailPickupDir()
|
|
SmtpDir = SMTP_DIRNOT::CreateSmtpDirNotification(MailPickUp, SMTP_DIRNOT::ReadDirectoryCompletion, this);
|
|
if (SmtpDir == NULL) {
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return FALSE;
|
|
}
|
|
|
|
//now that both queues are initialized, create the
|
|
//thread that goes off and finds any mail files
|
|
//that were not sent and builds up both queues
|
|
DWORD ThreadId;
|
|
DWORD error;
|
|
DirPickupThreadHandle = CreateThread (NULL, 0, SMTP_DIRNOT::PickupInitialFiles, SmtpDir, 0, &ThreadId);
|
|
if (DirPickupThreadHandle == NULL) {
|
|
error = GetLastError();
|
|
ErrorTrace((LPARAM)this, "CreateThread failed for SMTP_DIRNOT::PickupInitialFiles. err: %u", error);
|
|
}
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return TRUE;
|
|
}
|
|
|
|
void SMTP_SERVER_INSTANCE::DestroyDirectoryNotification(void)
|
|
{
|
|
TraceFunctEnterEx((LPARAM)this, "DestroyDirectoryNotification(void)");
|
|
|
|
//wait for the initial pickup thread
|
|
//to die
|
|
if (DirPickupThreadHandle != NULL) {
|
|
if (SmtpDir)
|
|
SmtpDir->SetPickupRetryQueueEvent();
|
|
|
|
WaitForSingleObject(DirPickupThreadHandle, INFINITE);
|
|
ErrorTrace((LPARAM)this, "Initial pickup thread is dead");
|
|
CloseHandle(DirPickupThreadHandle);
|
|
DirPickupThreadHandle = NULL;
|
|
}
|
|
|
|
//Just close the handle to the
|
|
//directory. This will cause
|
|
//the notification to come back
|
|
//with an error, and it will be
|
|
//deleted.
|
|
if (SmtpDir) {
|
|
SmtpDir->CloseDirHandle();
|
|
}
|
|
|
|
if (SmtpDir) {
|
|
delete SmtpDir;
|
|
SmtpDir = NULL;
|
|
CloseHandle(StopHandle);
|
|
StopHandle = NULL;
|
|
}
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
}
|
|
|
|
extern char g_UserName[];
|
|
extern char g_DomainName[];
|
|
extern char g_Password[];
|
|
|
|
|
|
void SMTP_SERVER_INSTANCE::SinkSmtpServerStartHintFunc(void)
|
|
{
|
|
if (g_pInetSvc) {
|
|
((PSMTP_IIS_SERVICE) g_pInetSvc)->StartHintFunction();
|
|
}
|
|
}
|
|
|
|
void SMTP_SERVER_INSTANCE::SinkSmtpServerStopHintFunc(void)
|
|
{
|
|
StopHint();
|
|
}
|
|
|
|
void SmtpServerStartHintFunc(PVOID ThisPtr)
|
|
{
|
|
((PSMTP_IIS_SERVICE) g_pInetSvc)->StartHintFunction();
|
|
}
|
|
|
|
void SmtpServerStopHintFunc(PVOID ThisPtr)
|
|
{
|
|
((SMTP_SERVER_INSTANCE *) ThisPtr)->StopHint();
|
|
}
|
|
|
|
BOOL SMTP_SERVER_INSTANCE::StartAdvancedQueueing(void)
|
|
{
|
|
TraceFunctEnterEx((LPARAM) this, "LoadAdvancedQueueing");
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
((PSMTP_IIS_SERVICE) g_pInetSvc)->StartHintFunction();
|
|
|
|
hr = (g_pfnInitializeAQ)(m_ComSmtpServer, QueryInstanceId(),
|
|
g_UserName, g_DomainName, g_Password, SmtpServerStartHintFunc,
|
|
(PVOID) this, &m_IAQ, &m_ICM,
|
|
&m_pIAdvQueueConfig, &m_pvAQInstanceContext);
|
|
|
|
ErrorTrace((LPARAM)this, "Advanced Queuing returned status code %x", hr);
|
|
|
|
TraceFunctLeaveEx((LPARAM) this);
|
|
return !FAILED(hr);
|
|
|
|
}
|
|
|
|
BOOL SMTP_SERVER_INSTANCE::StopQDrivers(void)
|
|
{
|
|
TraceFunctEnterEx((LPARAM) this, "StopQDrivers");
|
|
|
|
if (m_pIAdvQueueConfig) {
|
|
m_pIAdvQueueConfig->Release();
|
|
m_pIAdvQueueConfig = NULL;
|
|
}
|
|
|
|
if (m_IAQ != NULL) {
|
|
m_IAQ->Release();
|
|
m_IAQ = NULL;
|
|
}
|
|
|
|
if (m_ICM != NULL) {
|
|
m_ICM->Release();
|
|
m_ICM = NULL;
|
|
}
|
|
|
|
if (fInitializedAQ && g_pfnDeinitializeAQ && m_pvAQInstanceContext) {
|
|
(g_pfnDeinitializeAQ)(m_pvAQInstanceContext, SmtpServerStopHintFunc, (PVOID) this);
|
|
m_pvAQInstanceContext = NULL;
|
|
fInitializedAQ = FALSE;
|
|
}
|
|
|
|
TraceFunctLeaveEx((LPARAM) this);
|
|
return TRUE;
|
|
}
|
|
|
|
extern void VerifyFQDNWithGlobalIp(DWORD InstanceId,char * szFQDomainName);
|
|
void SMTP_SERVER_INSTANCE::VerifyFQDNWithBindings(void)
|
|
{
|
|
|
|
CONST CHAR *apszMsgs[2];
|
|
CHAR achInstance[20];
|
|
CHAR achIPAddr[20];
|
|
|
|
char * FQDNValue = NULL;
|
|
char * IpAddress = NULL;
|
|
in_addr UNALIGNED * P_Addr = NULL;
|
|
|
|
PHOSTENT pH = NULL;
|
|
|
|
char * Ptr = NULL;
|
|
const char * StartPtr = NULL;
|
|
const CHAR * ipAddressString = NULL;
|
|
const CHAR * ipPortString = NULL;
|
|
const CHAR * end = NULL;
|
|
DWORD InetAddr = 0;
|
|
DWORD CharIpSize = 0;
|
|
CHAR temp[sizeof("123.123.123.123")];
|
|
INT length;
|
|
|
|
BOOL fGlobalListChecked = FALSE;
|
|
|
|
//Get the current instnace id
|
|
wsprintf( achInstance,
|
|
"%lu",
|
|
QueryInstanceId() );
|
|
apszMsgs[1] = achInstance;
|
|
|
|
//grab the sharing lock
|
|
|
|
if (m_ServerBindings.IsEmpty()) {
|
|
if (!fGlobalListChecked) {
|
|
VerifyFQDNWithGlobalIp(QueryInstanceId(), m_szFQDomainName);
|
|
fGlobalListChecked = TRUE;
|
|
}
|
|
} else {
|
|
for (StartPtr = m_ServerBindings.First(); StartPtr != NULL; StartPtr = m_ServerBindings.Next( StartPtr )) {
|
|
ipAddressString = StartPtr;
|
|
ipPortString = strchr(StartPtr, ':');
|
|
if (ipPortString == NULL) {
|
|
wsprintf( achIPAddr,"%s","0.0.0.0");
|
|
apszMsgs[0] = achIPAddr;
|
|
SmtpLogEvent( SMTP_EVENT_UNRESOLVED_FQDN,2,apszMsgs,0 );
|
|
}
|
|
|
|
// Validate and parse the IP address portion.
|
|
//
|
|
if ( *ipAddressString == ':' ) {
|
|
if (!fGlobalListChecked) {
|
|
VerifyFQDNWithGlobalIp(QueryInstanceId(),m_szFQDomainName);
|
|
fGlobalListChecked = TRUE;
|
|
}
|
|
} else {
|
|
length = DIFF(ipPortString - ipAddressString) - 1;
|
|
if ( length > sizeof(temp) ) {
|
|
wsprintf( achIPAddr,"%s", temp);
|
|
apszMsgs[0] = achIPAddr;
|
|
SmtpLogEvent( SMTP_EVENT_UNRESOLVED_FQDN,1,apszMsgs,0 );
|
|
}
|
|
CopyMemory( temp, ipAddressString, length);
|
|
temp[length] = '\0';
|
|
InetAddr = inet_addr( temp );
|
|
if ( InetAddr != INADDR_NONE ) {
|
|
//For IP address find the host name
|
|
((PSMTP_IIS_SERVICE) g_pInetSvc)->StartHintFunction();
|
|
pH = gethostbyaddr((char*)(&InetAddr), 4, PF_INET );
|
|
if (pH && pH->h_name) {
|
|
if (_strcmpi(pH->h_name,m_szFQDomainName)) {
|
|
wsprintf( achIPAddr,"%s",temp);
|
|
apszMsgs[0] = achIPAddr;
|
|
SmtpLogEvent( SMTP_EVENT_UNRESOLVED_FQDN,2,apszMsgs,0 );
|
|
}
|
|
} else {
|
|
wsprintf( achIPAddr,"%s",temp);
|
|
apszMsgs[0] = achIPAddr;
|
|
SmtpLogEvent( SMTP_EVENT_UNRESOLVED_FQDN,2,apszMsgs,0 );
|
|
}
|
|
|
|
} else {
|
|
wsprintf( achIPAddr,"%s", temp);
|
|
apszMsgs[0] = achIPAddr;
|
|
SmtpLogEvent( SMTP_EVENT_UNRESOLVED_FQDN,2,apszMsgs,0 );
|
|
}
|
|
}//end else of if( *ipAddressString == ':' )
|
|
}//end for
|
|
}//end else
|
|
|
|
return;
|
|
}
|
|
|
|
BOOL SMTP_SERVER_INSTANCE::RegisterServicePrincipalNames(BOOL fLock)
|
|
{
|
|
if (fLock)
|
|
m_GenLock.ExclusiveLock();
|
|
|
|
if (!m_fHaveRegisteredPrincipalNames) {
|
|
|
|
PSMTP_IIS_SERVICE pService = (PSMTP_IIS_SERVICE) g_pInetSvc;
|
|
|
|
if (pService->ResetServicePrincipalNames()) {
|
|
|
|
m_fHaveRegisteredPrincipalNames =
|
|
CSecurityCtx::RegisterServicePrincipalNames(
|
|
SMTP_SERVICE_NAME, m_szFQDomainName);
|
|
}
|
|
}
|
|
|
|
if (fLock)
|
|
m_GenLock.ExclusiveUnlock();
|
|
|
|
return( m_fHaveRegisteredPrincipalNames );
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: SMTP_SERVER_INSTANCE::HrSetWellKnownIServerProps
|
|
//
|
|
// Synopsis: Take info from member variables and set them in the
|
|
// IServer property bag
|
|
//
|
|
// Arguments: NONE
|
|
//
|
|
// Returns:
|
|
// S_OK: Success
|
|
// error from CMailMsgLoggingPropertyBag
|
|
//
|
|
// History:
|
|
// jstamerj 1998/11/17 16:41:08: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
HRESULT SMTP_SERVER_INSTANCE::HrSetWellKnownIServerProps()
|
|
{
|
|
HRESULT hr;
|
|
|
|
TraceFunctEnterEx((LPARAM)this,
|
|
"SMTP_SERVER_INSTANCE::HrSetWellKnownIServerProps");
|
|
|
|
_ASSERT(m_pSmtpInfo);
|
|
|
|
hr = m_InstancePropertyBag.PutDWORD(
|
|
PE_ISERVID_DW_INSTANCE,
|
|
m_pSmtpInfo->dwInstanceId);
|
|
|
|
if(FAILED(hr))
|
|
goto CLEANUP;
|
|
|
|
hr = m_InstancePropertyBag.PutStringA(
|
|
PE_ISERVID_SZ_DEFAULTDOMAIN,
|
|
m_szDefaultDomain);
|
|
|
|
if(FAILED(hr))
|
|
goto CLEANUP;
|
|
|
|
CLEANUP:
|
|
DebugTrace((LPARAM)this, "returning hr %08lx", hr);
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//---[ SMTP_SERVER_INSTANCE::IsDropDirQuotaExceeded ]--------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Checks to see if we are past our drop dir quota (if enforced). The
|
|
// quota is defined to be 11 times the max messages size (or 22 MB if
|
|
// there is no max message size). If we are within 1 max message size
|
|
// of the quota (2MB is no max message size), we will assume that this
|
|
// message will push us over the quota.
|
|
// Parameters:
|
|
// -
|
|
// Returns:
|
|
// TRUE We are past our quota (or this message will do it)
|
|
// FALSE We are still under drop dir quota.
|
|
// History:
|
|
// 10/28/1999 - MikeSwa Created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL SMTP_SERVER_INSTANCE::IsDropDirQuotaExceeded()
|
|
{
|
|
TraceFunctEnterEx((LPARAM) this, "SMTP_SERVER_INSTANCE::IsDropDirQuotaExceeded");
|
|
DWORD cbMaxMsgSize = GetMaxMsgSize();
|
|
BOOL fQuotaExceeded = FALSE;
|
|
HANDLE hDropDirFind = INVALID_HANDLE_VALUE;
|
|
LARGE_INTEGER LIntDropDirSize;
|
|
LARGE_INTEGER LIntDropQuota;
|
|
LARGE_INTEGER LIntCurrentFile;
|
|
WIN32_FIND_DATA FileInfo;
|
|
CHAR szDropDirSearch[sizeof(m_szMailDropDir) + sizeof("*")];
|
|
|
|
ZeroMemory(&FileInfo, sizeof(FileInfo));
|
|
LIntDropDirSize.QuadPart = 0;
|
|
LIntDropQuota.QuadPart = 0;
|
|
|
|
if (!IsDropDirQuotaCheckingEnabled() || !GetMailDropDir(szDropDirSearch))
|
|
{
|
|
fQuotaExceeded = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
if (!cbMaxMsgSize)
|
|
cbMaxMsgSize = 2*1024*1024; //Default to 2 MB
|
|
|
|
//Set drop dir quota to be 10 times the max message size, if we
|
|
//exceed this, then we are within 1 max message size of the "true" quota
|
|
LIntDropQuota.QuadPart = 10*cbMaxMsgSize;
|
|
|
|
//Build up a search so we can loop over the file names
|
|
lstrcat(szDropDirSearch, "*");
|
|
hDropDirFind = FindFirstFileEx(szDropDirSearch,
|
|
FindExInfoStandard,
|
|
&FileInfo,
|
|
FindExSearchNameMatch,
|
|
NULL,
|
|
0);
|
|
|
|
if (INVALID_HANDLE_VALUE == hDropDirFind)
|
|
{
|
|
ErrorTrace((LPARAM) this,
|
|
"Unable to open drop dir for quota checking - 0x%X", GetLastError());
|
|
|
|
//If we cannot open the directory assume we are over quota
|
|
fQuotaExceeded = TRUE;
|
|
goto Exit;
|
|
}
|
|
|
|
//Loop over all the files we have found
|
|
do
|
|
{
|
|
LIntCurrentFile.LowPart = FileInfo.nFileSizeLow;
|
|
LIntCurrentFile.HighPart = FileInfo.nFileSizeHigh;
|
|
|
|
LIntDropDirSize.QuadPart += LIntCurrentFile.QuadPart;
|
|
|
|
if (LIntDropQuota.QuadPart <= LIntDropDirSize.QuadPart)
|
|
{
|
|
fQuotaExceeded = TRUE;
|
|
goto Exit;
|
|
}
|
|
} while (FindNextFile(hDropDirFind, &FileInfo));
|
|
|
|
if (LIntDropQuota.QuadPart <= LIntDropDirSize.QuadPart)
|
|
fQuotaExceeded = TRUE;
|
|
else
|
|
fQuotaExceeded = FALSE;
|
|
|
|
Exit:
|
|
if (INVALID_HANDLE_VALUE != hDropDirFind)
|
|
FindClose(hDropDirFind);
|
|
|
|
TraceFunctLeave();
|
|
return fQuotaExceeded;
|
|
}
|
|
|