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.
2608 lines
72 KiB
2608 lines
72 KiB
//+------------------------------------------------------------
|
|
//
|
|
// Copyright (C) 1999, Microsoft Corporation
|
|
//
|
|
// File: cnfgmgr.cpp
|
|
//
|
|
// Contents: Implementation of the classes defined in cnfgmgr.h
|
|
//
|
|
// Classes:
|
|
// CLdapCfgMgr
|
|
// CLdapCfg
|
|
// CLdapHost
|
|
// CCfgConnectionCache
|
|
// CCfgConnection
|
|
//
|
|
// Functions:
|
|
//
|
|
// History:
|
|
// jstamerj 1999/06/16 14:41:45: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
#include "precomp.h"
|
|
#include "cnfgmgr.h"
|
|
|
|
//
|
|
// Globals
|
|
//
|
|
CExShareLock CLdapServerCfg::m_listlock;
|
|
LIST_ENTRY CLdapServerCfg::m_listhead;
|
|
|
|
DWORD CLdapServerCfg::m_dwCostConnectedLocal = DEFAULT_COST_CONNECTED_LOCAL;
|
|
DWORD CLdapServerCfg::m_dwCostConnectedRemote = DEFAULT_COST_CONNECTED_REMOTE;
|
|
DWORD CLdapServerCfg::m_dwCostInitialLocal = DEFAULT_COST_INITIAL_LOCAL;
|
|
DWORD CLdapServerCfg::m_dwCostInitialRemote = DEFAULT_COST_INITIAL_REMOTE;
|
|
DWORD CLdapServerCfg::m_dwCostRetryLocal = DEFAULT_COST_RETRY_LOCAL;
|
|
DWORD CLdapServerCfg::m_dwCostRetryRemote = DEFAULT_COST_RETRY_REMOTE;
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CLdapCfgMgr::CLdapCfgMgr
|
|
//
|
|
// Synopsis: Initialize member data
|
|
//
|
|
// Arguments: Optional:
|
|
// fAutomaticConfigUpdate: TRUE indicates that the object is to
|
|
// periodicly automaticly update the list of
|
|
// GCs.
|
|
// FALSE disables this functionality
|
|
//
|
|
// bt: Default bindtype to use
|
|
// pszAccount: Default account for LDAP bind
|
|
// pszPassword: Password of above account
|
|
// pszNamingContext: Naming context to use for all LDAP searches
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// History:
|
|
// jstamerj 1999/06/16 14:42:39: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
CLdapCfgMgr::CLdapCfgMgr(
|
|
ISMTPServerEx *pISMTPServerEx,
|
|
BOOL fAutomaticConfigUpdate,
|
|
ICategorizerParameters *pICatParams,
|
|
LDAP_BIND_TYPE bt,
|
|
LPSTR pszAccount,
|
|
LPSTR pszPassword,
|
|
LPSTR pszNamingContext) : m_LdapConnectionCache(pISMTPServerEx)
|
|
{
|
|
CatFunctEnterEx((LPARAM)this, "CLdapCfgMgr::CLdapCfgMgr");
|
|
|
|
m_dwSignature = SIGNATURE_CLDAPCFGMGR;
|
|
m_pCLdapCfg = NULL;
|
|
ZeroMemory(&m_ulLastUpdateTime, sizeof(m_ulLastUpdateTime));
|
|
m_dwUpdateInProgress = FALSE;
|
|
m_fAutomaticConfigUpdate = fAutomaticConfigUpdate;
|
|
m_pISMTPServerEx = pISMTPServerEx;
|
|
if(m_pISMTPServerEx)
|
|
m_pISMTPServerEx->AddRef();
|
|
|
|
//
|
|
// Copy default
|
|
//
|
|
m_bt = bt;
|
|
if(pszAccount)
|
|
lstrcpyn(m_szAccount, pszAccount, sizeof(m_szAccount));
|
|
else
|
|
m_szAccount[0] = '\0';
|
|
|
|
if(pszPassword)
|
|
lstrcpyn(m_szPassword, pszPassword, sizeof(m_szPassword));
|
|
else
|
|
m_szPassword[0] = '\0';
|
|
|
|
if(pszNamingContext)
|
|
lstrcpyn(m_szNamingContext, pszNamingContext, sizeof(m_szNamingContext));
|
|
else
|
|
m_szNamingContext[0] = '\0';
|
|
|
|
m_pICatParams = pICatParams;
|
|
m_pICatParams->AddRef();
|
|
|
|
m_LdapConnectionCache.AddRef();
|
|
|
|
m_dwRebuildGCListMaxInterval = DEFAULT_REBUILD_GC_LIST_MAX_INTERVAL;
|
|
m_dwRebuildGCListMaxFailures = DEFAULT_REBUILD_GC_LIST_MAX_FAILURES;
|
|
m_dwRebuildGCListMinInterval = DEFAULT_REBUILD_GC_LIST_MIN_INTERVAL;
|
|
|
|
InitializeFromRegistry();
|
|
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
} // CLdapCfgMgr::CLdapCfgMgr
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CLdapCfgMgr::InitializeFromRegistry
|
|
//
|
|
// Synopsis: Helper function that looks up parameters from the registry.
|
|
// Configurable parameters are:
|
|
// REBUILD_GC_LIST_MAX_INTERVAL_VALUE
|
|
// REBUILD_GC_LIST_MAX_FAILURES_VALUE
|
|
// REBUILD_GC_LIST_MIN_INTERVAL_VALUE
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: Nothing.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
VOID CLdapCfgMgr::InitializeFromRegistry()
|
|
{
|
|
HKEY hkey;
|
|
DWORD dwErr, dwType, dwValue, cbValue;
|
|
|
|
dwErr = RegOpenKey(HKEY_LOCAL_MACHINE, REBUILD_GC_LIST_PARAMETERS_KEY, &hkey);
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
cbValue = sizeof(dwValue);
|
|
|
|
dwErr = RegQueryValueEx(
|
|
hkey,
|
|
REBUILD_GC_LIST_MAX_INTERVAL_VALUE,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE) &dwValue,
|
|
&cbValue);
|
|
|
|
if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD && dwValue > 0) {
|
|
m_dwRebuildGCListMaxInterval = dwValue;
|
|
}
|
|
|
|
cbValue = sizeof(dwValue);
|
|
|
|
dwErr = RegQueryValueEx(
|
|
hkey,
|
|
REBUILD_GC_LIST_MAX_FAILURES_VALUE,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE) &dwValue,
|
|
&cbValue);
|
|
|
|
if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD && dwValue > 0) {
|
|
m_dwRebuildGCListMaxFailures = dwValue;
|
|
}
|
|
|
|
cbValue = sizeof(dwValue);
|
|
|
|
dwErr = RegQueryValueEx(
|
|
hkey,
|
|
REBUILD_GC_LIST_MIN_INTERVAL_VALUE,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE) &dwValue,
|
|
&cbValue);
|
|
|
|
if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD && dwValue > 0) {
|
|
m_dwRebuildGCListMinInterval = dwValue;
|
|
}
|
|
|
|
RegCloseKey( hkey );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CLdapCfgMgr::~CLdapCfgMgr
|
|
//
|
|
// Synopsis: Release member data/pointers
|
|
//
|
|
// Arguments: NONE
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// History:
|
|
// jstamerj 1999/06/16 14:44:28: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
CLdapCfgMgr::~CLdapCfgMgr()
|
|
{
|
|
CatFunctEnterEx((LPARAM)this, "CLdapCfgMgr::~CLdapCfgMgr");
|
|
|
|
if(m_pCLdapCfg) {
|
|
//
|
|
// Release it
|
|
//
|
|
m_pCLdapCfg->Release();
|
|
m_pCLdapCfg = NULL;
|
|
}
|
|
|
|
if(m_pICatParams) {
|
|
|
|
m_pICatParams->Release();
|
|
m_pICatParams = NULL;
|
|
}
|
|
//
|
|
// This will not return until all ldap connections have been released/destroyed
|
|
//
|
|
m_LdapConnectionCache.Release();
|
|
|
|
if(m_pISMTPServerEx)
|
|
m_pISMTPServerEx->Release();
|
|
|
|
_ASSERT(m_dwSignature == SIGNATURE_CLDAPCFGMGR);
|
|
m_dwSignature = SIGNATURE_CLDAPCFGMGR_INVALID;
|
|
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
} // CLdapCfgMgr::~CLdapCfgMgr
|
|
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CLdapCfgMgr::HrInit
|
|
//
|
|
// Synopsis: Initialize with a list of available GCs
|
|
//
|
|
// Arguments:
|
|
// fRediscoverGCs: TRUE: pass in the force rediscovery flag to DsGetDcName
|
|
// FALSE: Attempt to call DsGetDcName first without
|
|
// passing in the force rediscovery flag.
|
|
//
|
|
// Returns:
|
|
// S_OK: Success
|
|
// error from NT5 (DsGetDcName)
|
|
// CAT_E_NO_GC_SERVERS: THere are no GC servers available to build
|
|
// the list of GCs
|
|
//
|
|
// History:
|
|
// jstamerj 1999/06/16 14:48:11: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
HRESULT CLdapCfgMgr::HrInit(
|
|
BOOL fRediscoverGCs)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwcServerConfig = 0;
|
|
DWORD dwCount = 0;
|
|
PLDAPSERVERCONFIG prgServerConfig = NULL;
|
|
ICategorizerLdapConfig *pICatLdapConfigInterface = NULL;
|
|
ICategorizerParametersEx *pIPhatCatParams = NULL;
|
|
|
|
CatFunctEnterEx((LPARAM)this, "CLdapCfgMgr::HrInit");
|
|
|
|
if(m_pICatParams)
|
|
{
|
|
hr = m_pICatParams->QueryInterface(IID_ICategorizerParametersEx, (LPVOID *)&pIPhatCatParams);
|
|
_ASSERT(SUCCEEDED(hr) && "Unable to get phatcatparams interface");
|
|
|
|
pIPhatCatParams->GetLdapConfigInterface(&pICatLdapConfigInterface);
|
|
}
|
|
|
|
if(pICatLdapConfigInterface)
|
|
{
|
|
DebugTrace((LPARAM)this, "Getting GC list from sink supplied interface");
|
|
//
|
|
// Get GC servers from sink supplied interface
|
|
//
|
|
hr = HrGetGCServers(
|
|
pICatLdapConfigInterface,
|
|
m_bt,
|
|
m_szAccount,
|
|
m_szPassword,
|
|
m_szNamingContext,
|
|
&dwcServerConfig,
|
|
&prgServerConfig);
|
|
if(FAILED(hr))
|
|
{
|
|
ERROR_LOG("HrGetGCServers");
|
|
hr = CAT_E_NO_GC_SERVERS;
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DebugTrace((LPARAM)this, "Getting internal GC list");
|
|
//
|
|
// Build an array of server configs consisting of available GCs
|
|
//
|
|
hr = HrBuildGCServerArray(
|
|
m_bt,
|
|
m_szAccount,
|
|
m_szPassword,
|
|
m_szNamingContext,
|
|
fRediscoverGCs,
|
|
&dwcServerConfig,
|
|
&prgServerConfig);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
ERROR_LOG("HrBuildGCServerArray");
|
|
if(fRediscoverGCs == FALSE)
|
|
{
|
|
//
|
|
// Attempt to build the array again. This time, force
|
|
// rediscovery of available GCs. This is expensive which is
|
|
// why we initially try to find all available GCs without
|
|
// forcing rediscovery.
|
|
//
|
|
hr = HrBuildGCServerArray(
|
|
m_bt,
|
|
m_szAccount,
|
|
m_szPassword,
|
|
m_szNamingContext,
|
|
TRUE, // fRediscoverGCs
|
|
&dwcServerConfig,
|
|
&prgServerConfig);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
ERROR_LOG("HrBuildGCServerArray - 2nd time");
|
|
hr = CAT_E_NO_GC_SERVERS;
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We already forced rediscovery and failed
|
|
//
|
|
hr = CAT_E_NO_GC_SERVERS;
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
}
|
|
|
|
LogCnfgInit();
|
|
for(dwCount = 0; dwCount < dwcServerConfig; dwCount++)
|
|
{
|
|
LogCnfgEntry(& (prgServerConfig[dwCount]));
|
|
}
|
|
|
|
if(dwcServerConfig == 0)
|
|
{
|
|
ErrorTrace((LPARAM)this, "No GC servers found.");
|
|
ERROR_LOG("--dwcServerConfig == 0 --");
|
|
hr = CAT_E_NO_GC_SERVERS;
|
|
goto CLEANUP;
|
|
}
|
|
//
|
|
// Call the other init function with the array
|
|
//
|
|
hr = HrInit(
|
|
dwcServerConfig,
|
|
prgServerConfig);
|
|
ERROR_CLEANUP_LOG("HrInit");
|
|
|
|
CLEANUP:
|
|
if(pIPhatCatParams)
|
|
pIPhatCatParams->Release();
|
|
|
|
if(prgServerConfig != NULL)
|
|
delete prgServerConfig;
|
|
|
|
DebugTrace((LPARAM)this, "returning %08lx", hr);
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
return hr;
|
|
} // CLdapCfgMgr::HrInit
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CLdapCfgMgr::HrGetGCServers
|
|
//
|
|
// Synopsis: Get the list of GCs from dsaccess.dll
|
|
//
|
|
// Arguments:
|
|
// bt: Bind type to use for each server
|
|
// pszAccount: Account to use for each server
|
|
// pszPassword: password of above account
|
|
// pszNamingContext: naming context to use for each server
|
|
// fRediscoverGCs: Attempt to rediscover GCs -- this is expensive and should
|
|
// only be TRUE after the function has failed once
|
|
// pdwcServerConfig: Out parameter for the size of the array
|
|
// pprgServerConfig: Out parameter for the array pointer -- this
|
|
// should be free'd with the delete operator
|
|
//
|
|
// Returns:
|
|
// S_OK: Success
|
|
// E_OUTOFMEMORY
|
|
// CAT_E_NO_GC_SERVERS: There are no available GC servers to build
|
|
// the list of GCs
|
|
// error from ntdsapi
|
|
//
|
|
// History:
|
|
// jstamerj 1999/07/01 17:53:02: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
HRESULT CLdapCfgMgr::HrGetGCServers(
|
|
IN ICategorizerLdapConfig *pICatLdapConfigInterface,
|
|
IN LDAP_BIND_TYPE bt,
|
|
IN LPSTR pszAccount,
|
|
IN LPSTR pszPassword,
|
|
IN LPSTR pszNamingContext,
|
|
OUT DWORD *pdwcServerConfig,
|
|
OUT PLDAPSERVERCONFIG *pprgServerConfig)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwNumGCs = 0;
|
|
DWORD dwIdx = 0;
|
|
IServersListInfo *pIServersList = NULL;
|
|
|
|
CatFunctEnterEx((LPARAM)this, "CLdapCfgMgr::HrBuildArrayFromDCInfo");
|
|
|
|
_ASSERT(pdwcServerConfig);
|
|
_ASSERT(pprgServerConfig);
|
|
_ASSERT(m_pICatParams);
|
|
|
|
*pdwcServerConfig = 0;
|
|
|
|
hr = pICatLdapConfigInterface->GetGCServers(&pIServersList);
|
|
if(FAILED(hr)) {
|
|
|
|
ErrorTrace((LPARAM)this, "Unable to get the list of GC servers");
|
|
//$$BUGBUG: Why are we asserting here?
|
|
_ASSERT(0 && "Failed to get GC servers!");
|
|
ERROR_LOG("pICatLdapConfigInterface->GetGCServers");
|
|
goto CLEANUP;
|
|
}
|
|
|
|
hr = pIServersList->GetNumGC(&dwNumGCs);
|
|
_ASSERT(SUCCEEDED(hr) && "GetNumGC should always succeed!");
|
|
|
|
DebugTrace((LPARAM)this, "Got %d GCs", dwNumGCs);
|
|
if(dwNumGCs == 0) {
|
|
|
|
DebugTrace((LPARAM)this, "There are no GC servers");
|
|
hr = CAT_E_NO_GC_SERVERS;
|
|
ERROR_LOG("--dwNumGCs == 0 --");
|
|
goto CLEANUP;
|
|
}
|
|
//
|
|
// Allocate array
|
|
//
|
|
*pprgServerConfig = new LDAPSERVERCONFIG[dwNumGCs];
|
|
|
|
if(*pprgServerConfig == NULL) {
|
|
|
|
ErrorTrace((LPARAM)this, "Out of memory allocating array of %d LDAPSERVERCONFIGs", dwNumGCs);
|
|
hr = E_OUTOFMEMORY;
|
|
ERROR_LOG("new LDAPSERVERCONFIG[]");
|
|
goto CLEANUP;
|
|
}
|
|
//
|
|
// Fill in LDAPSERVERCONFIG structures
|
|
//
|
|
for(dwIdx = 0; dwIdx < dwNumGCs; dwIdx++) {
|
|
|
|
PLDAPSERVERCONFIG pServerConfig;
|
|
LPSTR pszName = NULL;
|
|
|
|
pServerConfig = &((*pprgServerConfig)[dwIdx]);
|
|
//
|
|
// Copy bindtype, account, password, naming context
|
|
//
|
|
pServerConfig->bt = bt;
|
|
|
|
if(pszNamingContext)
|
|
lstrcpyn(pServerConfig->szNamingContext, pszNamingContext,
|
|
sizeof(pServerConfig->szNamingContext));
|
|
else
|
|
pServerConfig->szNamingContext[0] = '\0';
|
|
|
|
if(pszAccount)
|
|
lstrcpyn(pServerConfig->szAccount, pszAccount,
|
|
sizeof(pServerConfig->szAccount));
|
|
else
|
|
pServerConfig->szAccount[0] = '\0';
|
|
|
|
if(pszPassword)
|
|
lstrcpyn(pServerConfig->szPassword, pszPassword,
|
|
sizeof(pServerConfig->szPassword));
|
|
else
|
|
pServerConfig->szPassword[0] = '\0';
|
|
|
|
//
|
|
// Initialize priority and TCP port
|
|
//
|
|
pServerConfig->pri = 0;
|
|
|
|
hr = pIServersList->GetItem(
|
|
dwIdx,
|
|
&pServerConfig->dwPort,
|
|
&pszName);
|
|
//
|
|
//$$BUGBUG: Why should this always succeed? It is a sink
|
|
// supplied interface, isn't it? If the last call fails, we
|
|
// will set *pdwcServerConfig below, but free the array.
|
|
//
|
|
_ASSERT(SUCCEEDED(hr) && "GetItem should always succeed");
|
|
|
|
//
|
|
// Copy the name
|
|
//
|
|
lstrcpyn(pServerConfig->szHost, pszName,
|
|
sizeof(pServerConfig->szHost));
|
|
|
|
DebugTrace((LPARAM)this, "GC: %s on Port: %d", pServerConfig->szHost, pServerConfig->dwPort);
|
|
}
|
|
//
|
|
// Set the out parameter for the array size
|
|
//
|
|
*pdwcServerConfig = dwNumGCs;
|
|
|
|
CLEANUP:
|
|
if(FAILED(hr)) {
|
|
//
|
|
// Free the allocated array if we're failing
|
|
//
|
|
if(*pprgServerConfig) {
|
|
delete *pprgServerConfig;
|
|
*pprgServerConfig = NULL;
|
|
}
|
|
}
|
|
|
|
if(pIServersList)
|
|
pIServersList->Release();
|
|
|
|
DebugTrace((LPARAM)this, "returning %08lx", hr);
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
return hr;
|
|
} // CLdapCfgMgr::HrBuildArrayFromDCInfo
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CLdapCfgMgr::HrBuildGCServerArray
|
|
//
|
|
// Synopsis: Allocate/build an array of LDAPSERVERCONFIG structures --
|
|
// one for each available GC
|
|
//
|
|
// Arguments:
|
|
// bt: Bind type to use for each server
|
|
// pszAccount: Account to use for each server
|
|
// pszPassword: password of above account
|
|
// pszNamingContext: naming context to use for each server
|
|
// fRediscoverGCs: Attempt to rediscover GCs -- this is expensive and should
|
|
// only be TRUE after the function has failed once
|
|
// pdwcServerConfig: Out parameter for the size of the array
|
|
// pprgServerConfig: Out parameter for the array pointer -- this
|
|
// should be free'd with the delete operator
|
|
//
|
|
// Returns:
|
|
// S_OK: Success
|
|
// E_OUTOFMEMORY
|
|
// CAT_E_NO_GC_SERVERS: There are no available GC servers to build
|
|
// the list of GCs
|
|
// error from ntdsapi
|
|
//
|
|
// History:
|
|
// jstamerj 1999/07/01 17:53:02: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
HRESULT CLdapCfgMgr::HrBuildGCServerArray(
|
|
IN LDAP_BIND_TYPE bt,
|
|
IN LPSTR pszAccount,
|
|
IN LPSTR pszPassword,
|
|
IN LPSTR pszNamingContext,
|
|
IN BOOL fRediscoverGCs,
|
|
OUT DWORD *pdwcServerConfig,
|
|
OUT PLDAPSERVERCONFIG *pprgServerConfig)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwErr;
|
|
ULONG ulFlags;
|
|
PDOMAIN_CONTROLLER_INFO pDCInfo = NULL;
|
|
HANDLE hDS = INVALID_HANDLE_VALUE;
|
|
DWORD cDSDCInfo;
|
|
PDS_DOMAIN_CONTROLLER_INFO_2 prgDSDCInfo = NULL;
|
|
|
|
CatFunctEnterEx((LPARAM)this, "CLdapCfgMgr::HrBuildGCServerArray");
|
|
//
|
|
// Find one GC using DsGetDcName()
|
|
//
|
|
ulFlags = DS_DIRECTORY_SERVICE_REQUIRED | DS_GC_SERVER_REQUIRED;
|
|
if(fRediscoverGCs)
|
|
ulFlags |= DS_FORCE_REDISCOVERY;
|
|
|
|
dwErr = DsGetDcName(
|
|
NULL, // Computername to process this function -- local computer
|
|
NULL, // Domainname -- primary domain of this computer
|
|
NULL, // Domain GUID
|
|
NULL, // Sitename -- site of this computer
|
|
ulFlags, // Flags; we want a GC
|
|
&pDCInfo); // Out parameter for the returned info
|
|
|
|
hr = HRESULT_FROM_WIN32(dwErr);
|
|
|
|
if(FAILED(hr)) {
|
|
|
|
ERROR_LOG("DGetDcName");
|
|
//
|
|
// Map one error code
|
|
//
|
|
if(hr == HRESULT_FROM_WIN32(ERROR_NO_SUCH_DOMAIN))
|
|
hr = CAT_E_NO_GC_SERVERS;
|
|
|
|
pDCInfo = NULL;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
DebugTrace((LPARAM)this, "Binding to DC %s",
|
|
pDCInfo->DomainControllerName);
|
|
|
|
//
|
|
// Bind to the DC
|
|
//
|
|
dwErr = DsBind(
|
|
pDCInfo->DomainControllerName, // DomainControllerAddress
|
|
NULL, // DnsDomainName
|
|
&hDS); // Out param -- handle to DS
|
|
|
|
hr = HRESULT_FROM_WIN32(dwErr);
|
|
|
|
if(FAILED(hr)) {
|
|
|
|
ERROR_LOG("DsBind");
|
|
hDS = INVALID_HANDLE_VALUE;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//
|
|
// Prefix says we need to check this case too
|
|
//
|
|
if ((NULL == hDS) || (INVALID_HANDLE_VALUE == hDS)) {
|
|
FatalTrace((LPARAM)this, "DsBind returned invalid handle");
|
|
hDS = INVALID_HANDLE_VALUE;
|
|
hr = E_FAIL;
|
|
ERROR_LOG("--DsBind returned invalid handle--");
|
|
goto CLEANUP;
|
|
}
|
|
|
|
DebugTrace((LPARAM)this, "Finding all domain controllers for %s", pDCInfo->DomainName);
|
|
//
|
|
// Get information about all the domain controllers
|
|
//
|
|
dwErr = DsGetDomainControllerInfo(
|
|
hDS, // Handle to the DS
|
|
pDCInfo->DomainName, // Domain name -- use the same domain
|
|
// as the GC found above
|
|
2, // Retrive struct version 2
|
|
&cDSDCInfo, // Out param for array size
|
|
(PVOID *) &prgDSDCInfo); // Out param for array ptr
|
|
|
|
hr = HRESULT_FROM_WIN32(dwErr);
|
|
|
|
if(FAILED(hr)) {
|
|
|
|
ERROR_LOG("DsGetDomainControllerInfo");
|
|
prgDSDCInfo = NULL;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
hr = HrBuildArrayFromDCInfo(
|
|
bt,
|
|
pszAccount,
|
|
pszPassword,
|
|
pszNamingContext,
|
|
cDSDCInfo,
|
|
prgDSDCInfo,
|
|
pdwcServerConfig,
|
|
pprgServerConfig);
|
|
ERROR_CLEANUP_LOG("HrBuildArrayFromDCInfo");
|
|
|
|
CLEANUP:
|
|
if(prgDSDCInfo != NULL)
|
|
DsFreeDomainControllerInfo(
|
|
2, // Free struct version 2
|
|
cDSDCInfo, // size of array
|
|
prgDSDCInfo); // array ptr
|
|
|
|
if(hDS != INVALID_HANDLE_VALUE)
|
|
DsUnBind(&hDS);
|
|
|
|
if(pDCInfo != NULL)
|
|
NetApiBufferFree(pDCInfo);
|
|
|
|
DebugTrace((LPARAM)this, "returning %08lx", hr);
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
return hr;
|
|
} // CLdapCfgMgr::HrBuildGCServerArray
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CLdapCfgMgr::HrBuildArrayFromDCInfo
|
|
//
|
|
// Synopsis: Allocate/build an array of LDAPSERVERCONFIG structures --
|
|
// one for each available GC in the array
|
|
//
|
|
// Arguments:
|
|
// bt: Bind type to use for each server
|
|
// pszAccount: Account to use for each server
|
|
// pszPassword: password of above account
|
|
// pszNamingContext: naming context to use for each server
|
|
// dwDSDCInfo: size of the prgDSDCInfo array
|
|
// prgDSDCInfo: array of domain controller info structures
|
|
// pdwcServerConfig: Out parameter for the size of the array
|
|
// pprgServerConfig: Out parameter for the array pointer -- this
|
|
// should be free'd with the delete operator
|
|
//
|
|
// Returns:
|
|
// S_OK: Success
|
|
// E_OUTOFMEMORY
|
|
// CAT_E_NO_GC_SERVERS: There were no GCs in the array
|
|
//
|
|
// History:
|
|
// jstamerj 1999/06/17 10:40:46: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
HRESULT CLdapCfgMgr::HrBuildArrayFromDCInfo(
|
|
IN LDAP_BIND_TYPE bt,
|
|
IN LPSTR pszAccount,
|
|
IN LPSTR pszPassword,
|
|
IN LPSTR pszNamingContext,
|
|
IN DWORD dwcDSDCInfo,
|
|
IN PDS_DOMAIN_CONTROLLER_INFO_2 prgDSDCInfo,
|
|
OUT DWORD *pdwcServerConfig,
|
|
OUT PLDAPSERVERCONFIG *pprgServerConfig)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwNumGCs = 0;
|
|
DWORD dwSrcIdx;
|
|
DWORD dwDestIdx;
|
|
CatFunctEnterEx((LPARAM)this, "CLdapCfgMgr::HrBuildArrayFromDCInfo");
|
|
|
|
_ASSERT(pdwcServerConfig);
|
|
_ASSERT(pprgServerConfig);
|
|
|
|
for(dwSrcIdx = 0; dwSrcIdx < dwcDSDCInfo; dwSrcIdx++) {
|
|
|
|
LPSTR pszName;
|
|
|
|
pszName = SzConnectNameFromDomainControllerInfo(
|
|
&(prgDSDCInfo[dwSrcIdx]));
|
|
|
|
if(pszName == NULL) {
|
|
|
|
ErrorTrace((LPARAM)this, "DC \"%s\" has no dns/netbios names",
|
|
prgDSDCInfo[dwSrcIdx].ServerObjectName ?
|
|
prgDSDCInfo[dwSrcIdx].ServerObjectName :
|
|
"unknown");
|
|
|
|
} else if(prgDSDCInfo[dwSrcIdx].fIsGc) {
|
|
|
|
dwNumGCs++;
|
|
DebugTrace((LPARAM)this, "Discovered GC #%d: %s",
|
|
dwNumGCs, pszName);
|
|
|
|
} else {
|
|
|
|
DebugTrace((LPARAM)this, "Discarding non-GC: %s",
|
|
pszName);
|
|
}
|
|
}
|
|
//
|
|
// Allocate array
|
|
//
|
|
*pprgServerConfig = new LDAPSERVERCONFIG[dwNumGCs];
|
|
|
|
if(*pprgServerConfig == NULL) {
|
|
|
|
ErrorTrace((LPARAM)this, "Out of memory alloacting array of %d LDAPSERVERCONFIGs", dwNumGCs);
|
|
hr = E_OUTOFMEMORY;
|
|
ERROR_LOG("new LDAPSERVERCONFIG[]");
|
|
goto CLEANUP;
|
|
}
|
|
//
|
|
// Fill in LDAPSERVERCONFIG structures
|
|
//
|
|
for(dwSrcIdx = 0, dwDestIdx = 0; dwSrcIdx < dwcDSDCInfo; dwSrcIdx++) {
|
|
|
|
LPSTR pszName;
|
|
|
|
pszName = SzConnectNameFromDomainControllerInfo(
|
|
&(prgDSDCInfo[dwSrcIdx]));
|
|
|
|
if((pszName != NULL) && (prgDSDCInfo[dwSrcIdx].fIsGc)) {
|
|
|
|
PLDAPSERVERCONFIG pServerConfig;
|
|
|
|
_ASSERT(dwDestIdx < dwNumGCs);
|
|
|
|
pServerConfig = &((*pprgServerConfig)[dwDestIdx]);
|
|
//
|
|
// Copy bindtype, account, password, naming context
|
|
//
|
|
pServerConfig->bt = bt;
|
|
|
|
if(pszNamingContext)
|
|
lstrcpyn(pServerConfig->szNamingContext, pszNamingContext,
|
|
sizeof(pServerConfig->szNamingContext));
|
|
else
|
|
pServerConfig->szNamingContext[0] = '\0';
|
|
|
|
if(pszAccount)
|
|
lstrcpyn(pServerConfig->szAccount, pszAccount,
|
|
sizeof(pServerConfig->szAccount));
|
|
else
|
|
pServerConfig->szAccount[0] = '\0';
|
|
|
|
if(pszPassword)
|
|
lstrcpyn(pServerConfig->szPassword, pszPassword,
|
|
sizeof(pServerConfig->szPassword));
|
|
else
|
|
pServerConfig->szPassword[0] = '\0';
|
|
|
|
//
|
|
// Initialize priority and TCP port
|
|
//
|
|
pServerConfig->pri = 0;
|
|
pServerConfig->dwPort = LDAP_GC_PORT;
|
|
|
|
//
|
|
// Copy the name
|
|
//
|
|
lstrcpyn(pServerConfig->szHost, pszName,
|
|
sizeof(pServerConfig->szHost));
|
|
|
|
dwDestIdx++;
|
|
}
|
|
}
|
|
//
|
|
// Assert check -- we should have filled in the entire array
|
|
//
|
|
_ASSERT(dwDestIdx == dwNumGCs);
|
|
//
|
|
// Set the out parameter for the array size
|
|
//
|
|
*pdwcServerConfig = dwNumGCs;
|
|
|
|
CLEANUP:
|
|
if(FAILED(hr)) {
|
|
//
|
|
// Free the allocated array if we're failing
|
|
//
|
|
if(*pprgServerConfig) {
|
|
delete *pprgServerConfig;
|
|
*pprgServerConfig = NULL;
|
|
}
|
|
}
|
|
|
|
DebugTrace((LPARAM)this, "returning %08lx", hr);
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
return hr;
|
|
} // CLdapCfgMgr::HrBuildArrayFromDCInfo
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CLdapCfgMgr::HrInit
|
|
//
|
|
// Synopsis: Initialize given an array of LDAPSERVERCONFIG structs
|
|
//
|
|
// Arguments:
|
|
// dwcServers: Size of the array
|
|
// prgServerConfig: Array of LDAPSERVERCONFIG structs
|
|
//
|
|
// Returns:
|
|
// S_OK: Success
|
|
// E_OUTOFMEMORY
|
|
//
|
|
// History:
|
|
// jstamerj 1999/06/17 12:32:11: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
HRESULT CLdapCfgMgr::HrInit(
|
|
DWORD dwcServers,
|
|
PLDAPSERVERCONFIG prgServerConfig)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CLdapCfg *pCLdapCfgOld = NULL;
|
|
CLdapCfg *pCLdapCfg = NULL;
|
|
BOOL fHaveLock = FALSE;
|
|
CatFunctEnterEx((LPARAM)this, "CLdapCfgMgr::HrInit");
|
|
|
|
pCLdapCfg = new (dwcServers) CLdapCfg(GetISMTPServerEx());
|
|
|
|
if(pCLdapCfg == NULL) {
|
|
hr = E_OUTOFMEMORY;
|
|
ERROR_LOG("new CLdapCfg");
|
|
goto CLEANUP;
|
|
}
|
|
//
|
|
// Allow only one config change at a time
|
|
//
|
|
m_sharelock.ExclusiveLock();
|
|
fHaveLock = TRUE;
|
|
|
|
//
|
|
// Grab the current m_pCLdapCfg into pCLdapCfgOld
|
|
//
|
|
pCLdapCfgOld = m_pCLdapCfg;
|
|
|
|
hr = pCLdapCfg->HrInit(
|
|
dwcServers,
|
|
prgServerConfig,
|
|
pCLdapCfgOld);
|
|
ERROR_CLEANUP_LOG("pCLdapCfg->HrInit");
|
|
|
|
//
|
|
// Put the new configuration in place
|
|
// Swap pointers
|
|
//
|
|
m_pCLdapCfg = pCLdapCfg;
|
|
|
|
//
|
|
// Set the last update time
|
|
//
|
|
GetSystemTimeAsFileTime((LPFILETIME)&m_ulLastUpdateTime);
|
|
|
|
CLEANUP:
|
|
|
|
if(fHaveLock)
|
|
m_sharelock.ExclusiveUnlock();
|
|
|
|
if(pCLdapCfgOld)
|
|
pCLdapCfgOld->Release();
|
|
|
|
DebugTrace((LPARAM)this, "returning %08lx", hr);
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
return hr;
|
|
} // CLdapCfgMgr::HrInit
|
|
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CLdapCfgMgr::HrGetConnection
|
|
//
|
|
// Synopsis: Select/return a connection
|
|
//
|
|
// Arguments:
|
|
// ppConn: Out parameter to receive ptr to connection
|
|
//
|
|
// Returns:
|
|
// S_OK: Success
|
|
// E_FAIL: not initialized
|
|
// error from CLdapConnectionCache
|
|
//
|
|
// History:
|
|
// jstamerj 1999/06/17 15:25:51: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
HRESULT CLdapCfgMgr::HrGetConnection(
|
|
CCfgConnection **ppConn)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CatFunctEnterEx((LPARAM)this, "CLdapCfgMgr::HrGetConnection");
|
|
|
|
hr = HrUpdateConfigurationIfNecessary();
|
|
ERROR_CLEANUP_LOG("HrUpdateConfigurationIfNecessary");
|
|
|
|
m_sharelock.ShareLock();
|
|
|
|
if(m_pCLdapCfg) {
|
|
|
|
DWORD dwcAttempts = 0;
|
|
do {
|
|
dwcAttempts++;
|
|
hr = m_pCLdapCfg->HrGetConnection(ppConn, &m_LdapConnectionCache);
|
|
|
|
} while((hr == HRESULT_FROM_WIN32(ERROR_RETRY)) &&
|
|
(dwcAttempts <= m_pCLdapCfg->DwNumServers()));
|
|
//
|
|
// If we retried DwNumServers() times and still couldn't get a
|
|
// connection, fail with E_DBCONNECTION.
|
|
//
|
|
if(FAILED(hr))
|
|
{
|
|
ERROR_LOG("m_pCLdapCfg->HrGetConnection");
|
|
if(hr == HRESULT_FROM_WIN32(ERROR_RETRY))
|
|
hr = CAT_E_DBCONNECTION;
|
|
}
|
|
|
|
} else {
|
|
hr = E_FAIL;
|
|
_ASSERT(0 && "HrInit not called or did not succeed");
|
|
}
|
|
|
|
m_sharelock.ShareUnlock();
|
|
|
|
CLEANUP:
|
|
DebugTrace((LPARAM)this, "returning %08lx", hr);
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
return hr;
|
|
} // CLdapCfgMgr::HrGetConnection
|
|
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CLdapCfgMgr::LogCnfgInit
|
|
//
|
|
// Synopsis: Log cnfgmgr init event
|
|
//
|
|
// Arguments: none
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
// History:
|
|
// jstamerj 2001/12/13 00:57:18: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
VOID CLdapCfgMgr::LogCnfgInit()
|
|
{
|
|
CatLogEvent(
|
|
GetISMTPServerEx(),
|
|
CAT_EVENT_CNFGMGR_INIT,
|
|
0,
|
|
NULL,
|
|
S_OK,
|
|
"",
|
|
LOGEVENT_FLAG_ALWAYS,
|
|
LOGEVENT_LEVEL_MEDIUM);
|
|
}
|
|
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CLdapCfgMgr::LogCnfgEntry
|
|
//
|
|
// Synopsis: Log cnfgmgr entry event
|
|
//
|
|
// Arguments: pConfig: entry to log
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
// History:
|
|
// jstamerj 2001/12/13 00:57:30: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
VOID CLdapCfgMgr::LogCnfgEntry(
|
|
PLDAPSERVERCONFIG pConfig)
|
|
{
|
|
LPCSTR rgSubStrings[6];
|
|
CHAR szPort[16], szPri[16], szBindType[16];
|
|
|
|
_snprintf(szPort, sizeof(szPort), "%d", pConfig->dwPort);
|
|
_snprintf(szPri, sizeof(szPri), "%d", pConfig->pri);
|
|
_snprintf(szBindType, sizeof(szBindType), "%d", pConfig->bt);
|
|
|
|
rgSubStrings[0] = pConfig->szHost;
|
|
rgSubStrings[1] = szPort;
|
|
rgSubStrings[2] = szPri;
|
|
rgSubStrings[3] = szBindType;
|
|
rgSubStrings[4] = pConfig->szNamingContext;
|
|
rgSubStrings[5] = pConfig->szAccount;
|
|
|
|
CatLogEvent(
|
|
GetISMTPServerEx(),
|
|
CAT_EVENT_CNFGMGR_ENTRY,
|
|
6,
|
|
rgSubStrings,
|
|
S_OK,
|
|
pConfig->szHost,
|
|
LOGEVENT_FLAG_ALWAYS,
|
|
LOGEVENT_LEVEL_MEDIUM);
|
|
}
|
|
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CLdapCfg::operator new
|
|
//
|
|
// Synopsis: Allocate memory for a CLdapCfg object
|
|
//
|
|
// Arguments:
|
|
// size: size of C++ object
|
|
// dwcServers: Number of servers in this configuration
|
|
//
|
|
// Returns:
|
|
// void pointer to the new object
|
|
//
|
|
// History:
|
|
// jstamerj 1999/06/17 13:40:56: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
void * CLdapCfg::operator new(
|
|
size_t size,
|
|
DWORD dwcServers)
|
|
{
|
|
CLdapCfg *pCLdapCfg;
|
|
DWORD dwAllocatedSize;
|
|
CatFunctEnterEx((LPARAM)0, "CLdapCfg::operator new");
|
|
|
|
_ASSERT(size == sizeof(CLdapCfg));
|
|
|
|
//
|
|
// Allocate space fo the CLdapServerCfg * array contigously after
|
|
// the memory for the C++ object
|
|
//
|
|
dwAllocatedSize = sizeof(CLdapCfg) + (dwcServers *
|
|
sizeof(CLdapServerCfg));
|
|
|
|
pCLdapCfg = (CLdapCfg *) new BYTE[dwAllocatedSize];
|
|
|
|
if(pCLdapCfg) {
|
|
pCLdapCfg->m_dwSignature = SIGNATURE_CLDAPCFG;
|
|
pCLdapCfg->m_dwcServers = dwcServers;
|
|
pCLdapCfg->m_prgpCLdapServerCfg = (CLdapServerCfg **) (pCLdapCfg + 1);
|
|
}
|
|
|
|
CatFunctLeaveEx((LPARAM)pCLdapCfg);
|
|
return pCLdapCfg;
|
|
} // CLdapCfg::operator new
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CLdapCfg::CLdapCfg
|
|
//
|
|
// Synopsis: Initialize member data
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// History:
|
|
// jstamerj 1999/06/17 13:46:50: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
CLdapCfg::CLdapCfg(
|
|
ISMTPServerEx *pISMTPServerEx)
|
|
{
|
|
CatFunctEnterEx((LPARAM)this, "CLdapCfg::CLdapCfg");
|
|
//
|
|
// signature and number of servers should be set by the new operator
|
|
//
|
|
_ASSERT(m_dwSignature == SIGNATURE_CLDAPCFG);
|
|
|
|
//
|
|
// Zero out the array of pointers to CLdapServerCfg objects
|
|
//
|
|
ZeroMemory(m_prgpCLdapServerCfg, m_dwcServers * sizeof(CLdapServerCfg *));
|
|
|
|
m_dwInc = 0;
|
|
m_dwcConnectionFailures = 0;
|
|
m_pISMTPServerEx = pISMTPServerEx;
|
|
if(m_pISMTPServerEx)
|
|
m_pISMTPServerEx->AddRef();
|
|
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
} // CLdapCfg::CLdapCfg
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CLdapCfg::~CLdapCfg
|
|
//
|
|
// Synopsis: Clean up
|
|
//
|
|
// Arguments: NONE
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// History:
|
|
// jstamerj 1999/06/17 14:47:25: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
CLdapCfg::~CLdapCfg()
|
|
{
|
|
DWORD dwCount;
|
|
|
|
CatFunctEnterEx((LPARAM)this, "CLdapCfg::~CLdapCfg");
|
|
|
|
//
|
|
// Release all connections configurations
|
|
//
|
|
for(dwCount = 0; dwCount < m_dwcServers; dwCount++) {
|
|
CLdapServerCfg *pCLdapServerCfg;
|
|
|
|
pCLdapServerCfg = m_prgpCLdapServerCfg[dwCount];
|
|
m_prgpCLdapServerCfg[dwCount] = NULL;
|
|
|
|
if(pCLdapServerCfg)
|
|
pCLdapServerCfg->Release();
|
|
}
|
|
if(m_pISMTPServerEx)
|
|
m_pISMTPServerEx->Release();
|
|
|
|
_ASSERT(m_dwSignature == SIGNATURE_CLDAPCFG);
|
|
m_dwSignature = SIGNATURE_CLDAPCFG_INVALID;
|
|
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
} // CLdapCfg::~CLdapCfg
|
|
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CLdapCfg::HrInit
|
|
//
|
|
// Synopsis: Initialize the configuration
|
|
//
|
|
// Arguments:
|
|
// dwcServers: Size of config array
|
|
// prgSeverConfig: LDAPSERVERCONFIG array
|
|
// pCLdapCfgOld: The previous configuration
|
|
//
|
|
// Returns:
|
|
// S_OK: Success
|
|
// E_OUTOFMEMORY
|
|
//
|
|
// History:
|
|
// jstamerj 1999/06/17 13:52:20: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
HRESULT CLdapCfg::HrInit(
|
|
DWORD dwcServers,
|
|
PLDAPSERVERCONFIG prgServerConfig,
|
|
CLdapCfg *pCLdapCfgOld)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwCount;
|
|
CatFunctEnterEx((LPARAM)this, "CLdapCfg::HrInit");
|
|
//
|
|
// m_dwcServers should be initialized by the new operator
|
|
//
|
|
_ASSERT(dwcServers == m_dwcServers);
|
|
|
|
m_sharelock.ExclusiveLock();
|
|
//
|
|
// Zero out the array of pointers to CLdapServerCfg objects
|
|
//
|
|
ZeroMemory(m_prgpCLdapServerCfg, m_dwcServers * sizeof(CLdapServerCfg *));
|
|
|
|
for(dwCount = 0; dwCount < m_dwcServers; dwCount++) {
|
|
|
|
DebugTrace((LPARAM)this, "GC list entry: %s (%u)", prgServerConfig[dwCount].szHost, prgServerConfig[dwCount].dwPort);
|
|
|
|
CLdapServerCfg *pServerCfg = NULL;
|
|
|
|
hr = CLdapServerCfg::GetServerCfg(
|
|
GetISMTPServerEx(),
|
|
&(prgServerConfig[dwCount]),
|
|
&pServerCfg);
|
|
ERROR_CLEANUP_LOG("CLdapServerCfg::GetServerCfg");
|
|
|
|
m_prgpCLdapServerCfg[dwCount] = pServerCfg;
|
|
}
|
|
|
|
ShuffleArray();
|
|
|
|
CLEANUP:
|
|
m_sharelock.ExclusiveUnlock();
|
|
|
|
DebugTrace((LPARAM)this, "returning %08lx", hr);
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
return hr;
|
|
} // CLdapCfg::HrInit
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CLdapCfg::HrGetConnection
|
|
//
|
|
// Synopsis: Select a connection and return it
|
|
//
|
|
// Arguments:
|
|
// ppConn: Set to a pointer to the selected connection
|
|
// pLdapConnectionCache: Cache to get connection from
|
|
//
|
|
// Returns:
|
|
// S_OK: Success
|
|
// E_FAIL: We are shutting down
|
|
// error from ldapconn
|
|
//
|
|
// History:
|
|
// jstamerj 1999/06/17 14:49:37: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
HRESULT CLdapCfg::HrGetConnection(
|
|
CCfgConnection **ppConn,
|
|
CCfgConnectionCache *pLdapConnectionCache)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LDAPSERVERCOST Cost, BestCost;
|
|
DWORD dwCount;
|
|
CLdapServerCfg *pCLdapServerCfg = NULL;
|
|
BOOL fFirstServer = TRUE;
|
|
DWORD dwStart, dwCurrent;
|
|
|
|
CatFunctEnterEx((LPARAM)this, "CLdapCfg::HrGetConnection");
|
|
//
|
|
// Get the cost of the first connection
|
|
//
|
|
m_sharelock.ShareLock();
|
|
|
|
//
|
|
// Round robin where we start searching the array
|
|
// Do this so we will use connections with the same cost
|
|
// approximately the same amount of time.
|
|
//
|
|
dwStart = InterlockedIncrement((PLONG) &m_dwInc) % m_dwcServers;
|
|
|
|
for(dwCount = 0; dwCount < m_dwcServers; dwCount++) {
|
|
|
|
dwCurrent = (dwStart + dwCount) % m_dwcServers;
|
|
|
|
if(m_prgpCLdapServerCfg[dwCurrent]) {
|
|
|
|
m_prgpCLdapServerCfg[dwCurrent]->Cost(GetISMTPServerEx(), &Cost);
|
|
if(fFirstServer) {
|
|
pCLdapServerCfg = m_prgpCLdapServerCfg[dwCurrent];
|
|
fFirstServer = FALSE;
|
|
BestCost = Cost;
|
|
|
|
} else if(Cost < BestCost) {
|
|
pCLdapServerCfg = m_prgpCLdapServerCfg[dwCurrent];
|
|
BestCost = Cost;
|
|
}
|
|
}
|
|
}
|
|
if(pCLdapServerCfg == NULL) {
|
|
ErrorTrace((LPARAM)this, "HrGetConnection can not find any connections");
|
|
hr = E_FAIL;
|
|
_ASSERT(0 && "HrInit not called or did not succeed");
|
|
ERROR_LOG("--pCLdapServerCfg == NULL--");
|
|
goto CLEANUP;
|
|
}
|
|
|
|
if(BestCost >= COST_TOO_HIGH_TO_CONNECT) {
|
|
DebugTrace((LPARAM)this, "BestCost is too high to attempt connection");
|
|
hr = CAT_E_DBCONNECTION;
|
|
ERROR_LOG("-- BestCost >= COST_TOO_HIGH_TO_CONNECT --");
|
|
goto CLEANUP;
|
|
}
|
|
|
|
hr = pCLdapServerCfg->HrGetConnection(GetISMTPServerEx(), ppConn, pLdapConnectionCache);
|
|
|
|
// If we fail to connect to a GC --- there may be other GCs which
|
|
// are still up. Therefore we should try to connect to them (till
|
|
// we run out of GCs (BestCost >= COST_TOO_HIGH_TO_CONNECT)
|
|
|
|
if(FAILED(hr)) {
|
|
DebugTrace((LPARAM)this, "Failed to connect. hr = 0x%08x", hr);
|
|
ERROR_LOG("pCLdapServerCfg->HrGetConnection");
|
|
hr = HRESULT_FROM_WIN32(ERROR_RETRY);
|
|
}
|
|
|
|
CLEANUP:
|
|
m_sharelock.ShareUnlock();
|
|
|
|
if(FAILED(hr))
|
|
InterlockedIncrement((PLONG)&m_dwcConnectionFailures);
|
|
|
|
DebugTrace((LPARAM)this, "returning %08lx", hr);
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
return hr;
|
|
} // CLdapCfg::HrGetConnection
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CLdapCfg::ShuffleArray
|
|
//
|
|
// Synopsis: Randomize the order of the CLdapServerCfg array
|
|
//
|
|
// Arguments: NONE
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// History:
|
|
// jstamerj 1999/06/17 19:10:06: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
VOID CLdapCfg::ShuffleArray()
|
|
{
|
|
DWORD dwCount;
|
|
DWORD dwSwap;
|
|
CLdapServerCfg *pTmp;
|
|
CatFunctEnterEx((LPARAM)this, "CLdapCfg::ShuffleArray");
|
|
|
|
srand((int)(GetCurrentThreadId() * time(NULL)));
|
|
|
|
for(dwCount = 0; dwCount < (m_dwcServers - 1); dwCount++) {
|
|
//
|
|
// Choose an integer between dwCount and m_dwcServers - 1
|
|
//
|
|
dwSwap = dwCount + (rand() % (m_dwcServers - dwCount));
|
|
//
|
|
// Swap pointers
|
|
//
|
|
pTmp = m_prgpCLdapServerCfg[dwCount];
|
|
m_prgpCLdapServerCfg[dwCount] = m_prgpCLdapServerCfg[dwSwap];
|
|
m_prgpCLdapServerCfg[dwSwap] = pTmp;
|
|
}
|
|
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
} // CLdapCfg::ShuffleArray
|
|
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CLdapServerCfg::CLdapServerCfg
|
|
//
|
|
// Synopsis: Initialize member variables
|
|
//
|
|
// Arguments: NONE
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// History:
|
|
// jstamerj 1999/06/17 15:30:32: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
CLdapServerCfg::CLdapServerCfg()
|
|
{
|
|
CatFunctEnterEx((LPARAM)this, "CLdapServerCfg::CLdapServerCfg");
|
|
|
|
m_dwSignature = SIGNATURE_CLDAPSERVERCFG;
|
|
|
|
m_ServerConfig.dwPort = 0;
|
|
m_ServerConfig.pri = 0;
|
|
m_ServerConfig.bt = BIND_TYPE_NONE;
|
|
m_ServerConfig.szHost[0] = '\0';
|
|
m_ServerConfig.szNamingContext[0] = '\0';
|
|
m_ServerConfig.szAccount[0] = '\0';
|
|
m_ServerConfig.szPassword[0] = '\0';
|
|
|
|
m_connstate = CONN_STATE_INITIAL;
|
|
ZeroMemory(&m_ftLastStateUpdate, sizeof(m_ftLastStateUpdate));
|
|
m_dwcPendingSearches = 0;
|
|
m_lRefCount = 1;
|
|
m_fLocalServer = FALSE;
|
|
m_dwcCurrentConnectAttempts = 0;
|
|
m_dwcFailedConnectAttempts = 0;
|
|
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
} // CLdapServerCfg::CLdapServerCfg
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CLdapServerCfg::InitializeFromRegistry
|
|
//
|
|
// Synopsis: Helper function that looks up parameters from the registry.
|
|
// Configurable parameters are:
|
|
// GC_COST_CONNECTED_LOCAL
|
|
// GC_COST_CONNECTED_REMOTE
|
|
// GC_COST_INITIAL_LOCAL
|
|
// GC_COST_INITIAL_REMOTE
|
|
// GC_COST_RETRY_LOCAL
|
|
// GC_COST_RETRY_REMOTE
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: Nothing.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
VOID CLdapServerCfg::InitializeFromRegistry()
|
|
{
|
|
HKEY hkey;
|
|
DWORD dwErr, dwType, dwValue, cbValue;
|
|
|
|
dwErr = RegOpenKey(HKEY_LOCAL_MACHINE, GC_COST_PARAMETERS_KEY, &hkey);
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
cbValue = sizeof(dwValue);
|
|
|
|
dwErr = RegQueryValueEx(
|
|
hkey,
|
|
GC_COST_CONNECTED_LOCAL_VALUE,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE) &dwValue,
|
|
&cbValue);
|
|
|
|
if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
|
|
m_dwCostConnectedLocal = dwValue;
|
|
}
|
|
|
|
cbValue = sizeof(dwValue);
|
|
|
|
dwErr = RegQueryValueEx(
|
|
hkey,
|
|
GC_COST_CONNECTED_REMOTE_VALUE,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE) &dwValue,
|
|
&cbValue);
|
|
|
|
if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
|
|
m_dwCostConnectedRemote = dwValue;
|
|
}
|
|
|
|
cbValue = sizeof(dwValue);
|
|
|
|
dwErr = RegQueryValueEx(
|
|
hkey,
|
|
GC_COST_INITIAL_LOCAL_VALUE,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE) &dwValue,
|
|
&cbValue);
|
|
|
|
if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
|
|
m_dwCostInitialLocal = dwValue;
|
|
}
|
|
|
|
cbValue = sizeof(dwValue);
|
|
|
|
dwErr = RegQueryValueEx(
|
|
hkey,
|
|
GC_COST_INITIAL_REMOTE_VALUE,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE) &dwValue,
|
|
&cbValue);
|
|
|
|
if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
|
|
m_dwCostInitialRemote = dwValue;
|
|
}
|
|
|
|
cbValue = sizeof(dwValue);
|
|
|
|
dwErr = RegQueryValueEx(
|
|
hkey,
|
|
GC_COST_RETRY_LOCAL_VALUE,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE) &dwValue,
|
|
&cbValue);
|
|
|
|
if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
|
|
m_dwCostRetryLocal = dwValue;
|
|
}
|
|
|
|
cbValue = sizeof(dwValue);
|
|
|
|
dwErr = RegQueryValueEx(
|
|
hkey,
|
|
GC_COST_RETRY_REMOTE_VALUE,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE) &dwValue,
|
|
&cbValue);
|
|
|
|
if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
|
|
m_dwCostRetryRemote = dwValue;
|
|
}
|
|
|
|
RegCloseKey( hkey );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CLdapServerCfg::~CLdapServerCfg
|
|
//
|
|
// Synopsis: object destructor. Check and invalidate signature
|
|
//
|
|
// Arguments: NONE
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// History:
|
|
// jstamerj 1999/06/22 11:09:03: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
CLdapServerCfg::~CLdapServerCfg()
|
|
{
|
|
CatFunctEnterEx((LPARAM)this, "CLdapServerCfg::~CLdapServerCfg");
|
|
|
|
_ASSERT(m_dwSignature == SIGNATURE_CLDAPSERVERCFG);
|
|
m_dwSignature = SIGNATURE_CLDAPSERVERCFG_INVALID;
|
|
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
} // CLdapServerCfg::~CLdapServerCfg
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CLdapServerCfg::HrInit
|
|
//
|
|
// Synopsis: Initialize with the passed in config
|
|
//
|
|
// Arguments:
|
|
// pCLdapCfg: the cfg object to notify when servers go down
|
|
// pServerConfig: The server config struct to use
|
|
//
|
|
// Returns:
|
|
// S_OK: Success
|
|
//
|
|
// History:
|
|
// jstamerj 1999/06/17 15:43:25: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
HRESULT CLdapServerCfg::HrInit(
|
|
PLDAPSERVERCONFIG pServerConfig)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CatFunctEnterEx((LPARAM)this, "CLdapServerCfg::HrInit");
|
|
|
|
CopyMemory(&m_ServerConfig, pServerConfig, sizeof(m_ServerConfig));
|
|
//
|
|
// Check if this is the local computer
|
|
//
|
|
if(fIsLocalComputer(pServerConfig))
|
|
m_fLocalServer = TRUE;
|
|
|
|
DebugTrace((LPARAM)this, "returning %08lx", hr);
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
return hr;
|
|
} // CLdapServerCfg::HrInit
|
|
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CLdapServerCfg::fIsLocalComputer
|
|
//
|
|
// Synopsis: Determine if pServerConfig is the local computer or not
|
|
//
|
|
// Arguments:
|
|
// pServerConfig: the server config info structure
|
|
//
|
|
// Returns:
|
|
// TRUE: Server is the local computer
|
|
// FALSE: Sevrver is a remote computer
|
|
//
|
|
// History:
|
|
// jstamerj 1999/06/22 15:26:53: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
BOOL CLdapServerCfg::fIsLocalComputer(
|
|
PLDAPSERVERCONFIG pServerConfig)
|
|
{
|
|
BOOL fLocal = FALSE;
|
|
DWORD dwSize;
|
|
CHAR szHost[CAT_MAX_DOMAIN];
|
|
CatFunctEnterEx((LPARAM)NULL, "CLdapServerCfg::fIsLocalComputer");
|
|
|
|
//
|
|
// Check the FQ name
|
|
//
|
|
dwSize = sizeof(szHost);
|
|
if(GetComputerNameEx(
|
|
ComputerNameDnsFullyQualified,
|
|
szHost,
|
|
&dwSize) &&
|
|
(lstrcmpi(szHost, pServerConfig->szHost) == 0)) {
|
|
|
|
fLocal = TRUE;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//
|
|
// Check the DNS name
|
|
//
|
|
dwSize = sizeof(szHost);
|
|
if(GetComputerNameEx(
|
|
ComputerNameDnsHostname,
|
|
szHost,
|
|
&dwSize) &&
|
|
(lstrcmpi(szHost, pServerConfig->szHost) == 0)) {
|
|
|
|
fLocal = TRUE;
|
|
goto CLEANUP;
|
|
}
|
|
//
|
|
// Check the netbios name
|
|
//
|
|
dwSize = sizeof(szHost);
|
|
if(GetComputerNameEx(
|
|
ComputerNameNetBIOS,
|
|
szHost,
|
|
&dwSize) &&
|
|
(lstrcmpi(szHost, pServerConfig->szHost) == 0)) {
|
|
|
|
fLocal = TRUE;
|
|
goto CLEANUP;
|
|
|
|
}
|
|
|
|
CLEANUP:
|
|
DebugTrace((LPARAM)NULL, "returning %08lx", fLocal);
|
|
CatFunctLeaveEx((LPARAM)NULL);
|
|
return fLocal;
|
|
} // CLdapServerCfg::fIsLocalComputer
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CLdapServerCfg::Cost
|
|
//
|
|
// Synopsis: Return the cost of choosing this connection
|
|
//
|
|
// Arguments:
|
|
// pCost: Cost sturcture to fill in
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// History:
|
|
// jstamerj 1999/06/17 16:08:23: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
VOID CLdapServerCfg::Cost(
|
|
IN ISMTPServerEx *pISMTPServerEx,
|
|
OUT PLDAPSERVERCOST pCost)
|
|
{
|
|
BOOL fShareLock = FALSE;
|
|
CatFunctEnterEx((LPARAM)this, "CLdapServerCfg::Cost");
|
|
//
|
|
// The smallest unit of cost is the number of pending searches.
|
|
// The next factor of cost is the connection state.
|
|
// States:
|
|
// Connected = + COST_CONNECTED
|
|
// Initially state (unconnected) = + COST_INITIAL
|
|
// Connection down = + COST_RETRY
|
|
// Connection recently went down = + COST_DOWN
|
|
//
|
|
// A configurable priority is always added to the cost.
|
|
// Also, COST_REMOTE is added to the cost of all non-local servers.
|
|
//
|
|
*pCost = m_ServerConfig.pri + m_dwcPendingSearches;
|
|
//
|
|
// Protect the connection state variables with a spinlock
|
|
//
|
|
m_sharelock.ShareLock();
|
|
fShareLock = TRUE;
|
|
|
|
switch(m_connstate) {
|
|
|
|
case CONN_STATE_INITIAL:
|
|
(*pCost) += (m_fLocalServer) ? m_dwCostInitialLocal : m_dwCostInitialRemote;
|
|
break;
|
|
|
|
case CONN_STATE_RETRY:
|
|
if(m_dwcCurrentConnectAttempts >= MAX_CONNECT_THREADS)
|
|
(*pCost) += COST_TOO_HIGH_TO_CONNECT;
|
|
else
|
|
(*pCost) += (m_fLocalServer) ? m_dwCostRetryLocal : m_dwCostRetryRemote;
|
|
break;
|
|
|
|
case CONN_STATE_DOWN:
|
|
//
|
|
// Check if the state should be changed to CONN_STATE_RETRY
|
|
//
|
|
if(fReadyForRetry()) {
|
|
(*pCost) += (m_fLocalServer) ? m_dwCostRetryLocal : m_dwCostRetryRemote;
|
|
//
|
|
// Change state
|
|
//
|
|
fShareLock = FALSE;
|
|
m_sharelock.ShareUnlock();
|
|
m_sharelock.ExclusiveLock();
|
|
//
|
|
// Double check in the exclusive lock
|
|
//
|
|
if((m_connstate == CONN_STATE_DOWN) &&
|
|
fReadyForRetry()) {
|
|
|
|
LogStateChangeEvent(
|
|
pISMTPServerEx,
|
|
CONN_STATE_RETRY,
|
|
m_ServerConfig.szHost,
|
|
m_ServerConfig.dwPort);
|
|
|
|
m_connstate = CONN_STATE_RETRY;
|
|
}
|
|
m_sharelock.ExclusiveUnlock();
|
|
|
|
} else {
|
|
//
|
|
// Server is probably still down (don't retry yet)
|
|
//
|
|
(*pCost) += (m_fLocalServer) ? COST_DOWN_LOCAL : COST_DOWN_REMOTE;
|
|
|
|
}
|
|
break;
|
|
|
|
case CONN_STATE_CONNECTED:
|
|
(*pCost) += (m_fLocalServer) ? m_dwCostConnectedLocal : m_dwCostConnectedRemote;
|
|
break;
|
|
|
|
default:
|
|
// Nothing to add
|
|
break;
|
|
}
|
|
if(fShareLock)
|
|
m_sharelock.ShareUnlock();
|
|
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
} // CLdapServerCfg::Cost
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CLdapServerCfg::HrGetConnection
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
// S_OK: Success
|
|
//
|
|
// History:
|
|
// jstamerj 1999/06/18 10:49:04: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
HRESULT CLdapServerCfg::HrGetConnection(
|
|
ISMTPServerEx *pISMTPServerEx,
|
|
CCfgConnection **ppConn,
|
|
CCfgConnectionCache *pLdapConnectionCache)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwcConnectAttempts = 0;
|
|
CatFunctEnterEx((LPARAM)this, "CLdapServerCfg::HrGetConnection");
|
|
|
|
dwcConnectAttempts = (DWORD) InterlockedIncrement((PLONG) &m_dwcCurrentConnectAttempts);
|
|
|
|
m_sharelock.ShareLock();
|
|
if((m_connstate == CONN_STATE_RETRY) &&
|
|
(dwcConnectAttempts > MAX_CONNECT_THREADS)) {
|
|
|
|
m_sharelock.ShareUnlock();
|
|
|
|
ErrorTrace((LPARAM)this, "Over max connect thread limit");
|
|
hr = HRESULT_FROM_WIN32(ERROR_RETRY);
|
|
ERROR_LOG_STATIC(
|
|
"--over max connect thread limit--",
|
|
this,
|
|
pISMTPServerEx);
|
|
goto CLEANUP;
|
|
}
|
|
m_sharelock.ShareUnlock();
|
|
|
|
DebugTrace((LPARAM)this, "Attempting to connect to %s:%d",
|
|
m_ServerConfig.szHost,
|
|
m_ServerConfig.dwPort);
|
|
|
|
hr = pLdapConnectionCache->GetConnection(
|
|
ppConn,
|
|
&m_ServerConfig,
|
|
this);
|
|
ERROR_CLEANUP_LOG_STATIC(
|
|
"pLdapConnectionCache->GetConnection",
|
|
this,
|
|
pISMTPServerEx);
|
|
|
|
//
|
|
// CCfgConnection::Connect will update the connection state
|
|
//
|
|
CLEANUP:
|
|
InterlockedDecrement((PLONG) &m_dwcCurrentConnectAttempts);
|
|
DebugTrace((LPARAM)this, "returning %08lx", hr);
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
return hr;
|
|
} // CLdapServerCfg::HrGetConnection
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CLdapServerCfg::UpdateConnectionState
|
|
//
|
|
// Synopsis: Update the connection state.
|
|
//
|
|
// Arguments:
|
|
// pft: Time of update -- if this time is before the last update done,
|
|
// then this update will be ignored.
|
|
// If NULL, the function will assume the current time.
|
|
// connstate: The new connection state.
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// History:
|
|
// jstamerj 1999/06/18 13:22:25: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
VOID CLdapServerCfg::UpdateConnectionState(
|
|
ISMTPServerEx *pISMTPServerEx,
|
|
ULARGE_INTEGER *pft_IN,
|
|
CONN_STATE connstate)
|
|
{
|
|
ULARGE_INTEGER ft, *pft;
|
|
CatFunctEnterEx((LPARAM)this, "CLdapServerCfg::UpdateConnectionState");
|
|
|
|
if(pft_IN != NULL) {
|
|
pft = pft_IN;
|
|
} else {
|
|
ft = GetCurrentTime();
|
|
pft = &ft;
|
|
}
|
|
|
|
//
|
|
// Protect connection state variables with a sharelock
|
|
//
|
|
m_sharelock.ShareLock();
|
|
//
|
|
// If we have the latest information about the connection state,
|
|
// then update the state if the connection state changed.
|
|
// Also update m_ftLastStateUpdate to the latest ft when the
|
|
// connection state is down -- m_ftLastStateUpdate is assumed to
|
|
// be the last connection attempt time when connstate is down.
|
|
//
|
|
if( (pft->QuadPart > m_ftLastStateUpdate.QuadPart) &&
|
|
((m_connstate != connstate) ||
|
|
(connstate == CONN_STATE_DOWN))) {
|
|
//
|
|
// We'd like to update the connection state
|
|
//
|
|
m_sharelock.ShareUnlock();
|
|
m_sharelock.ExclusiveLock();
|
|
//
|
|
// Double check
|
|
//
|
|
if( (pft->QuadPart > m_ftLastStateUpdate.QuadPart) &&
|
|
((m_connstate != connstate) ||
|
|
(connstate == CONN_STATE_DOWN))) {
|
|
//
|
|
// Update
|
|
//
|
|
if(m_connstate != connstate) {
|
|
LogStateChangeEvent(
|
|
pISMTPServerEx,
|
|
connstate,
|
|
m_ServerConfig.szHost,
|
|
m_ServerConfig.dwPort);
|
|
}
|
|
|
|
m_ftLastStateUpdate = *pft;
|
|
m_connstate = connstate;
|
|
|
|
DebugTrace((LPARAM)this, "Updating state %d, conn %s:%d",
|
|
connstate,
|
|
m_ServerConfig.szHost,
|
|
m_ServerConfig.dwPort);
|
|
|
|
} else {
|
|
|
|
DebugTrace((LPARAM)this, "Ignoring state update %d, conn %s:%d",
|
|
connstate,
|
|
m_ServerConfig.szHost,
|
|
m_ServerConfig.dwPort);
|
|
}
|
|
m_sharelock.ExclusiveUnlock();
|
|
|
|
} else {
|
|
|
|
DebugTrace((LPARAM)this, "Ignoring state update %d, conn %s:%d",
|
|
connstate,
|
|
m_ServerConfig.szHost,
|
|
m_ServerConfig.dwPort);
|
|
|
|
m_sharelock.ShareUnlock();
|
|
}
|
|
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
} // CLdapServerCfg::UpdateConnectionState
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CLdapServerCfg::GetServerCfg
|
|
//
|
|
// Synopsis: Find or Create a CLdapServerCfg object with the specified
|
|
// configuration.
|
|
//
|
|
// Arguments:
|
|
// pServerConfig: desired configuration
|
|
// pCLdapServerCfg: return pointer for the CLdapServerCfg object
|
|
//
|
|
// Returns:
|
|
// S_OK: Success
|
|
// E_OUTOFMEMORY
|
|
//
|
|
// History:
|
|
// jstamerj 1999/06/21 11:26:49: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
HRESULT CLdapServerCfg::GetServerCfg(
|
|
IN ISMTPServerEx *pISMTPServerEx,
|
|
IN PLDAPSERVERCONFIG pServerConfig,
|
|
OUT CLdapServerCfg **ppCLdapServerCfg)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CLdapServerCfg *pCCfg;
|
|
CatFunctEnterEx((LPARAM)NULL, "CLdapServerCfg::GetServerCfg");
|
|
|
|
m_listlock.ShareLock();
|
|
|
|
pCCfg = FindServerCfg(pServerConfig);
|
|
if(pCCfg)
|
|
pCCfg->AddRef();
|
|
|
|
m_listlock.ShareUnlock();
|
|
|
|
if(pCCfg == NULL) {
|
|
//
|
|
// Check again for a server cfg object inside an exclusive
|
|
// lock
|
|
//
|
|
m_listlock.ExclusiveLock();
|
|
|
|
pCCfg = FindServerCfg(pServerConfig);
|
|
if(pCCfg) {
|
|
pCCfg->AddRef();
|
|
} else {
|
|
//
|
|
// Create a new object
|
|
//
|
|
pCCfg = new CLdapServerCfg();
|
|
if(pCCfg == NULL) {
|
|
|
|
hr = E_OUTOFMEMORY;
|
|
ERROR_LOG_STATIC(
|
|
"new CLdapServerCfg",
|
|
0,
|
|
pISMTPServerEx);
|
|
|
|
} else {
|
|
|
|
hr = pCCfg->HrInit(pServerConfig);
|
|
if(FAILED(hr)) {
|
|
ERROR_LOG_STATIC(
|
|
"pCCfg->HrInit",
|
|
pCCfg,
|
|
pISMTPServerEx);
|
|
delete pCCfg;
|
|
pCCfg = NULL;
|
|
} else {
|
|
//
|
|
// Add to global list
|
|
//
|
|
InsertTailList(&m_listhead, &(pCCfg->m_le));
|
|
}
|
|
}
|
|
}
|
|
m_listlock.ExclusiveUnlock();
|
|
}
|
|
//
|
|
// Set out parameter
|
|
//
|
|
*ppCLdapServerCfg = pCCfg;
|
|
|
|
DebugTrace((LPARAM)NULL, "returning hr %08lx", hr);
|
|
CatFunctLeaveEx((LPARAM)NULL);
|
|
return hr;
|
|
|
|
} // CLdapServerCfg::GetServerCfg
|
|
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CLdapServerCfg::FindServerCfg
|
|
//
|
|
// Synopsis: Find a server cfg object that matches the
|
|
// LDAPSERVERCONFIG structure. Note, m_listlock must be
|
|
// locked when calling this function.
|
|
//
|
|
// Arguments:
|
|
// pServerConfig: pointer to the LDAPSERVERCONFIG struct
|
|
//
|
|
// Returns:
|
|
// NULL: there is no such server cfg object
|
|
// else, ptr to the found CLdapServerCfg object
|
|
//
|
|
// History:
|
|
// jstamerj 1999/06/21 10:43:23: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
CLdapServerCfg * CLdapServerCfg::FindServerCfg(
|
|
PLDAPSERVERCONFIG pServerConfig)
|
|
{
|
|
CLdapServerCfg *pMatch = NULL;
|
|
PLIST_ENTRY ple;
|
|
CatFunctEnterEx((LPARAM)NULL, "CLdapServerCfg::FindServerCfg");
|
|
|
|
for(ple = m_listhead.Flink;
|
|
(ple != &m_listhead) && (pMatch == NULL);
|
|
ple = ple->Flink) {
|
|
|
|
CLdapServerCfg *pCandidate = NULL;
|
|
|
|
pCandidate = CONTAINING_RECORD(ple, CLdapServerCfg, m_le);
|
|
|
|
if(pCandidate->fMatch(
|
|
pServerConfig)) {
|
|
|
|
pMatch = pCandidate;
|
|
}
|
|
}
|
|
|
|
CatFunctLeaveEx((LPARAM)NULL);
|
|
return pMatch;
|
|
} // CLdapServerCfg::FindServerCfg
|
|
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CLdapServerCfg::fMatch
|
|
//
|
|
// Synopsis: Determine if this object matches the passed in config
|
|
//
|
|
// Arguments:
|
|
// pServerConfig: config to check against
|
|
//
|
|
// Returns:
|
|
// TRUE: match
|
|
// FALSE: no match
|
|
//
|
|
// History:
|
|
// jstamerj 1999/06/21 12:45:10: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
BOOL CLdapServerCfg::fMatch(
|
|
PLDAPSERVERCONFIG pServerConfig)
|
|
{
|
|
BOOL fRet;
|
|
CatFunctEnterEx((LPARAM)this, "CLdapServerCfg::fMatch");
|
|
|
|
if((pServerConfig->dwPort != m_ServerConfig.dwPort) ||
|
|
(pServerConfig->bt != m_ServerConfig.bt) ||
|
|
(lstrcmpi(pServerConfig->szHost,
|
|
m_ServerConfig.szHost) != 0) ||
|
|
(lstrcmpi(pServerConfig->szNamingContext,
|
|
m_ServerConfig.szNamingContext) != 0) ||
|
|
(lstrcmpi(pServerConfig->szAccount,
|
|
m_ServerConfig.szAccount) != 0) ||
|
|
(lstrcmpi(pServerConfig->szPassword,
|
|
m_ServerConfig.szPassword) != 0)) {
|
|
|
|
fRet = FALSE;
|
|
|
|
} else {
|
|
|
|
fRet = TRUE;
|
|
}
|
|
|
|
DebugTrace((LPARAM)this, "returning %08lx", fRet);
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
return fRet;
|
|
} // CLdapServerCfg::fMatch
|
|
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CLdapServerCfg::LogStateChangeEvent
|
|
//
|
|
// Synopsis: Log an eventlog for a state change event
|
|
//
|
|
// Arguments:
|
|
// pISMTPServerEx: interface for logging
|
|
// connstate: new connstate
|
|
// pszHost: host for connection
|
|
// dwPort: port of connection
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
// History:
|
|
// jstamerj 2001/12/13 01:43:13: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
VOID CLdapServerCfg::LogStateChangeEvent(
|
|
IN ISMTPServerEx *pISMTPServerEx,
|
|
IN CONN_STATE connstate,
|
|
IN LPSTR pszHost,
|
|
IN DWORD dwPort)
|
|
{
|
|
DWORD idEvent = 0;
|
|
LPCSTR rgSubStrings[2];
|
|
CHAR szPort[16];
|
|
|
|
_snprintf(szPort, sizeof(szPort), "%d", dwPort);
|
|
|
|
rgSubStrings[0] = pszHost;
|
|
rgSubStrings[1] = szPort;
|
|
|
|
switch(connstate)
|
|
{
|
|
case CONN_STATE_CONNECTED:
|
|
idEvent = CAT_EVENT_CNFGMGR_CONNECTED;
|
|
break;
|
|
|
|
case CONN_STATE_DOWN:
|
|
idEvent = CAT_EVENT_CNFGMGR_DOWN;
|
|
break;
|
|
|
|
case CONN_STATE_RETRY:
|
|
idEvent = CAT_EVENT_CNFGMGR_RETRY;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if(idEvent)
|
|
{
|
|
CatLogEvent(
|
|
pISMTPServerEx,
|
|
idEvent,
|
|
2,
|
|
rgSubStrings,
|
|
S_OK,
|
|
pszHost,
|
|
LOGEVENT_FLAG_ALWAYS,
|
|
LOGEVENT_LEVEL_MEDIUM);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CCfgConnection::Connect
|
|
//
|
|
// Synopsis: Cfg wrapper for the Connect call.
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns:
|
|
// S_OK: Success
|
|
// CAT_E_DBCONNECTION (or whatever CBatchLdapConnection::Connect returns)
|
|
//
|
|
// History:
|
|
// jstamerj 2000/04/13 17:44:43: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
HRESULT CCfgConnection::Connect()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ULARGE_INTEGER ft;
|
|
CONN_STATE connstate;
|
|
CatFunctEnterEx((LPARAM)this, "CCfgConnection::Connect");
|
|
|
|
connstate = m_pCLdapServerCfg->CurrentState();
|
|
if(connstate == CONN_STATE_DOWN) {
|
|
|
|
DebugTrace((LPARAM)this, "Not connecting because %s:%d is down",
|
|
m_szHost, m_dwPort);
|
|
hr = CAT_E_DBCONNECTION;
|
|
ERROR_LOG("m_pCLdapServerCfg->CurrentState");
|
|
goto CLEANUP;
|
|
}
|
|
|
|
ft = m_pCLdapServerCfg->GetCurrentTime();
|
|
|
|
hr = CBatchLdapConnection::Connect();
|
|
if(FAILED(hr)) {
|
|
connstate = CONN_STATE_DOWN;
|
|
m_pCLdapServerCfg->IncrementFailedCount();
|
|
ERROR_LOG("CBatchLdapConnection::Connect");
|
|
} else {
|
|
connstate = CONN_STATE_CONNECTED;
|
|
m_pCLdapServerCfg->ResetFailedCount();
|
|
}
|
|
//
|
|
// Update the connection state while inside CLdapConnectionCache's
|
|
// lock. This will prevent a succeeding thread from attempting
|
|
// another connection to the GC right after CLdapConnectionCache
|
|
// releases its lock. Contact msanna for more details.
|
|
//
|
|
m_pCLdapServerCfg->UpdateConnectionState(
|
|
GetISMTPServerEx(), &ft, connstate);
|
|
|
|
CLEANUP:
|
|
DebugTrace((LPARAM)this, "returning %08lx", hr);
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
return hr;
|
|
} // CCfgConnection::Connect
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CCfgConnection::AsyncSearch
|
|
//
|
|
// Synopsis: Wrapper around AsyncSearch -- keep track of the # of
|
|
// pending searches and connection state.
|
|
//
|
|
// Arguments: See CLdapConnection::AsyncSearch
|
|
//
|
|
// Returns:
|
|
// Value returned from CLdapConnection::AsyncSearch
|
|
//
|
|
// History:
|
|
// jstamerj 1999/06/18 13:49:45: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
HRESULT CCfgConnection::AsyncSearch(
|
|
LPCWSTR szBaseDN,
|
|
int nScope,
|
|
LPCWSTR szFilter,
|
|
LPCWSTR szAttributes[],
|
|
DWORD dwPageSize,
|
|
LPLDAPCOMPLETION fnCompletion,
|
|
LPVOID ctxCompletion)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CatFunctEnterEx((LPARAM)this, "CCfgConnection::AsyncSearch");
|
|
|
|
m_pCLdapServerCfg->IncrementPendingSearches();
|
|
|
|
hr = CBatchLdapConnection::AsyncSearch(
|
|
szBaseDN,
|
|
nScope,
|
|
szFilter,
|
|
szAttributes,
|
|
dwPageSize,
|
|
fnCompletion,
|
|
ctxCompletion);
|
|
|
|
if(FAILED(hr)) {
|
|
ERROR_LOG("CBatchLdapConnection::AsyncSearch");
|
|
m_pCLdapServerCfg->DecrementPendingSearches();
|
|
}
|
|
|
|
DebugTrace((LPARAM)this, "returning %08lx", hr);
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
return hr;
|
|
} // CCfgConnection::AsyncSearch
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CCfgConnection::CallCompletion
|
|
//
|
|
// Synopsis: Wrapper around CLdapConnection::CallCompletion. Checks
|
|
// for server down errors and keeps track of pending searches.
|
|
//
|
|
// Arguments: See CLdapConnection::CallCompletion
|
|
//
|
|
// Returns: See CLdapConnection::CallCompletion
|
|
//
|
|
// History:
|
|
// jstamerj 1999/06/18 13:58:28: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
VOID CCfgConnection::CallCompletion(
|
|
PPENDING_REQUEST preq,
|
|
PLDAPMessage pres,
|
|
HRESULT hrStatus,
|
|
BOOL fFinalCompletion)
|
|
{
|
|
CatFunctEnterEx((LPARAM)this, "CCfgConnection::CallCompletion");
|
|
|
|
//
|
|
// The user(s) of CLdapConnection normally try to get a new
|
|
// connection and reissue their search when AsyncSearch
|
|
// fails. When opening a new connection fails, CLdapServerCfg
|
|
// will be notified that the LDAP server is down. We do not
|
|
// want to call NotifyServerDown() here because the LDAP
|
|
// server may have just closed this connection due to idle
|
|
// time (the server may not actually be down).
|
|
//
|
|
if(fFinalCompletion) {
|
|
|
|
m_pCLdapServerCfg->DecrementPendingSearches();
|
|
}
|
|
|
|
CBatchLdapConnection::CallCompletion(
|
|
preq,
|
|
pres,
|
|
hrStatus,
|
|
fFinalCompletion);
|
|
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
} // CCfgConnection::CallCompletion
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CCfgConnection::NotifyServerDown
|
|
//
|
|
// Synopsis: Notify the server config that this connection is down.
|
|
// If we already notified it, don't do so again.
|
|
//
|
|
// Arguments: NONE
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// History:
|
|
// jstamerj 1999/06/18 14:07:48: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
VOID CCfgConnection::NotifyServerDown()
|
|
{
|
|
BOOL fNotify;
|
|
CatFunctEnterEx((LPARAM)this, "CCfgConnection::NotifyServerDown");
|
|
|
|
m_sharelock.ShareLock();
|
|
if(m_connstate == CONN_STATE_DOWN) {
|
|
//
|
|
// We already notified m_pCLdapServerCfg the server went
|
|
// down. Don't repeteadly call it
|
|
//
|
|
fNotify = FALSE;
|
|
|
|
m_sharelock.ShareUnlock();
|
|
|
|
} else {
|
|
|
|
m_sharelock.ShareUnlock();
|
|
m_sharelock.ExclusiveLock();
|
|
//
|
|
// Double check
|
|
//
|
|
if(m_connstate == CONN_STATE_DOWN) {
|
|
|
|
fNotify = FALSE;
|
|
|
|
} else {
|
|
m_connstate = CONN_STATE_DOWN;
|
|
fNotify = TRUE;
|
|
}
|
|
m_sharelock.ExclusiveUnlock();
|
|
}
|
|
if(fNotify)
|
|
m_pCLdapServerCfg->UpdateConnectionState(
|
|
GetISMTPServerEx(),
|
|
NULL, // Current time
|
|
CONN_STATE_DOWN);
|
|
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
} // CCfgConnection::NotifyServerDown
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CatStoreInitGlobals
|
|
//
|
|
// Synopsis: This is called to initialize global variables in the
|
|
// store layer.
|
|
//
|
|
// Arguments: NONE
|
|
//
|
|
// Returns:
|
|
// S_OK: Success
|
|
//
|
|
// History:
|
|
// jstamerj 1999/06/22 11:03:53: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
HRESULT CatStoreInitGlobals()
|
|
{
|
|
CatFunctEnterEx((LPARAM)NULL, "CatStoreInitGlobals");
|
|
|
|
CLdapServerCfg::GlobalInit();
|
|
CLdapConnection::GlobalInit();
|
|
|
|
CatFunctLeaveEx((LPARAM)NULL);
|
|
return S_OK;
|
|
} // CatStoreInitGlobals
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CatStoreDeinitGlobals
|
|
//
|
|
// Synopsis: Called to deinitialize store layer globals -- called once
|
|
// only when CatStoreInitGlobals succeeds
|
|
//
|
|
// Arguments: NONE
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// History:
|
|
// jstamerj 1999/06/22 11:05:44: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
VOID CatStoreDeinitGlobals()
|
|
{
|
|
CatFunctEnterEx((LPARAM)NULL, "CatStoreDeinitGlobals");
|
|
//
|
|
// Nothing to do
|
|
//
|
|
CatFunctLeaveEx((LPARAM)NULL);
|
|
} // CatStoreDeinitGlobals
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CCfgConnectionCache::GetConnection
|
|
//
|
|
// Synopsis: Same as CLdapConnectionCache::GetConnection, except
|
|
// retrieves a CCfgConnection instead of a CLdapConnection.
|
|
//
|
|
// Arguments:
|
|
// ppConn: out parameter for new connection
|
|
// pServerConfig: desired configuration
|
|
// pCLdapServerConfig: Pointer to config object
|
|
//
|
|
// Returns:
|
|
// S_OK: Success
|
|
//
|
|
// History:
|
|
// jstamerj 1999/12/20 16:49:12: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
HRESULT CCfgConnectionCache::GetConnection(
|
|
CCfgConnection **ppConn,
|
|
PLDAPSERVERCONFIG pServerConfig,
|
|
CLdapServerCfg *pCLdapServerConfig)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
CatFunctEnterEx((LPARAM)this, "CCfgConnectionCache::GetConnection");
|
|
|
|
hr = CBatchLdapConnectionCache::GetConnection(
|
|
(CBatchLdapConnection **)ppConn,
|
|
pServerConfig->szHost,
|
|
pServerConfig->dwPort,
|
|
pServerConfig->szNamingContext,
|
|
pServerConfig->szAccount,
|
|
pServerConfig->szPassword,
|
|
pServerConfig->bt,
|
|
(PVOID) pCLdapServerConfig); // pCreateContext
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
ERROR_LOG("CBatchldapConnection::GetConnection");
|
|
}
|
|
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
return hr;
|
|
} // CCfgConnectionCache::GetConnection
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CCfgConnectionCache::CreateCachedLdapConnection
|
|
//
|
|
// Synopsis: Create a CCfgConnection (Called by GetConnection only)
|
|
//
|
|
// Arguments: See CLdapConnectionCache::CreateCachedLdapConnection
|
|
//
|
|
// Returns:
|
|
// Connection ptr if successfull.
|
|
// NULL if unsuccessfull.
|
|
//
|
|
// History:
|
|
// jstamerj 1999/12/20 16:57:49: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
CCfgConnectionCache::CCachedLdapConnection * CCfgConnectionCache::CreateCachedLdapConnection(
|
|
LPSTR szHost,
|
|
DWORD dwPort,
|
|
LPSTR szNamingContext,
|
|
LPSTR szAccount,
|
|
LPSTR szPassword,
|
|
LDAP_BIND_TYPE bt,
|
|
PVOID pCreateContext)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CCfgConnection *pret;
|
|
|
|
CatFunctEnterEx((LPARAM)this, "CCfgConnectionCache::CreateCachedLdapConnection");
|
|
|
|
pret = new CCfgConnection(
|
|
szHost,
|
|
dwPort,
|
|
szNamingContext,
|
|
szAccount,
|
|
szPassword,
|
|
bt,
|
|
this,
|
|
(CLdapServerCfg *)pCreateContext);
|
|
|
|
if(pret) {
|
|
hr = pret->HrInitialize();
|
|
if(FAILED(hr)) {
|
|
ERROR_LOG("pret->HrInitialize");
|
|
pret->Release();
|
|
pret = NULL;
|
|
}
|
|
} else {
|
|
hr = E_OUTOFMEMORY;
|
|
ERROR_LOG("new CCfgConnection");
|
|
}
|
|
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
return pret;
|
|
} // CCfgConnectionCache::CreateCachedLdapConnection
|