windows-nt/Source/XPSP1/NT/inetsrv/iis/svcs/smtp/adminsso/binding.cpp
2020-09-26 16:20:57 +08:00

803 lines
16 KiB
C++

// binding.cpp : Implementation of CServerBinding & CServerBindings.
#include "stdafx.h"
#include "smtpadm.h"
#include "cmultisz.h"
#include "binding.h"
#include "oleutil.h"
#include "smtpcmn.h"
HRESULT CBinding::SetProperties (
BSTR strIpAddress,
long dwTcpPort,
long dwSslPort
)
{
_ASSERT ( IS_VALID_STRING ( strIpAddress ) );
m_strIpAddress = strIpAddress;
m_dwTcpPort = dwTcpPort;
m_dwSslPort = dwSslPort;
if ( !m_strIpAddress ) {
return E_OUTOFMEMORY;
}
return NOERROR;
}
// Must define THIS_FILE_* macros to use SmtpCreateException()
#define THIS_FILE_HELP_CONTEXT 0
#define THIS_FILE_PROG_ID _T("Smtpadm.VirtualServer.1")
#define THIS_FILE_IID IID_IServerBinding
/////////////////////////////////////////////////////////////////////////////
//
STDMETHODIMP CServerBinding::InterfaceSupportsErrorInfo(REFIID riid)
{
static const IID* arr[] =
{
&IID_IServerBinding,
};
for (int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
{
if (InlineIsEqualGUID(*arr[i],riid))
return S_OK;
}
return S_FALSE;
}
CServerBinding::CServerBinding ()
// CComBSTR's are initialized to NULL by default.
{
}
CServerBinding::~CServerBinding ()
{
// All CComBSTR's are freed automatically.
}
//////////////////////////////////////////////////////////////////////
// Properties:
//////////////////////////////////////////////////////////////////////
STDMETHODIMP CServerBinding::get_IpAddress ( BSTR * pstrIpAddress )
{
return StdPropertyGet ( m_binding.m_strIpAddress, pstrIpAddress );
}
STDMETHODIMP CServerBinding::put_IpAddress ( BSTR strIpAddress )
{
return StdPropertyPut ( &m_binding.m_strIpAddress, strIpAddress );
}
STDMETHODIMP CServerBinding::get_TcpPort ( long * pdwTcpPort )
{
return StdPropertyGet ( m_binding.m_dwTcpPort, pdwTcpPort );
}
STDMETHODIMP CServerBinding::put_TcpPort ( long dwTcpPort )
{
return StdPropertyPut ( &m_binding.m_dwTcpPort, dwTcpPort );
}
STDMETHODIMP CServerBinding::get_SslPort ( long * plSslPort )
{
return StdPropertyGet ( m_binding.m_dwSslPort, plSslPort );
}
STDMETHODIMP CServerBinding::put_SslPort ( long lSslPort )
{
return StdPropertyPut ( &m_binding.m_dwSslPort, lSslPort );
}
//
// Must define THIS_FILE_* macros to use SmtpCreateException()
//
#undef THIS_FILE_HELP_CONTEXT
#undef THIS_FILE_PROG_ID
#undef THIS_FILE_IID
#define THIS_FILE_HELP_CONTEXT 0
#define THIS_FILE_PROG_ID _T("smtpadm.VirtualServer.1")
#define THIS_FILE_IID IID_IServerBindings
/////////////////////////////////////////////////////////////////////////////
//
STDMETHODIMP CServerBindings::InterfaceSupportsErrorInfo(REFIID riid)
{
static const IID* arr[] =
{
&IID_IServerBindings,
};
for (int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
{
if (InlineIsEqualGUID(*arr[i],riid))
return S_OK;
}
return S_FALSE;
}
CServerBindings::CServerBindings () :
m_dwCount ( 0 ),
m_rgBindings ( NULL )
// CComBSTR's are initialized to NULL by default.
{
}
CServerBindings::~CServerBindings ()
{
// All CComBSTR's are freed automatically.
delete [] m_rgBindings;
}
//////////////////////////////////////////////////////////////////////
// Properties:
//////////////////////////////////////////////////////////////////////
STDMETHODIMP CServerBindings::get_Count ( long * pdwCount )
{
return StdPropertyGet ( m_dwCount, pdwCount );
}
//////////////////////////////////////////////////////////////////////
// Methods:
//////////////////////////////////////////////////////////////////////
STDMETHODIMP CServerBindings::Item (
long index,
IServerBinding ** ppBinding
)
{
TraceFunctEnter ( "CServerBindings::Item" );
_ASSERT ( IS_VALID_OUT_PARAM ( ppBinding ) );
*ppBinding = NULL;
HRESULT hr = NOERROR;
CComObject<CServerBinding> * pBinding = NULL;
if ( index < 0 || index >= m_dwCount ) {
hr = SmtpCreateException ( IDS_SMTPEXCEPTION_INVALID_INDEX );
goto Exit;
}
hr = CComObject<CServerBinding>::CreateInstance ( &pBinding );
if ( FAILED(hr) ) {
goto Exit;
}
_ASSERT ( pBinding );
hr = pBinding->SetProperties ( m_rgBindings[index] );
if ( FAILED(hr) ) {
goto Exit;
}
hr = pBinding->QueryInterface ( IID_IServerBinding, (void **) ppBinding );
_ASSERT ( SUCCEEDED(hr) );
Exit:
if ( FAILED(hr) && hr != DISP_E_EXCEPTION ) {
hr = SmtpCreateExceptionFromHresult ( hr );
}
if ( FAILED(hr) ) {
delete pBinding;
}
TraceFunctLeave ();
return hr;
}
STDMETHODIMP CServerBindings::ItemDispatch ( long index, IDispatch ** ppDispatch )
{
HRESULT hr;
CComPtr<IServerBinding> pBinding;
hr = Item ( index, &pBinding );
BAIL_ON_FAILURE ( hr );
hr = pBinding->QueryInterface ( IID_IDispatch, (void **) ppDispatch );
BAIL_ON_FAILURE ( hr );
Exit:
return hr;
}
STDMETHODIMP CServerBindings::Add (
BSTR strIpAddress,
long dwTcpPort,
long dwSslPort
)
{
TraceFunctEnter ( "CServerBindings::Add" );
_ASSERT ( IS_VALID_STRING ( strIpAddress ) );
HRESULT hr = NOERROR;
CBinding * rgNewBindings = NULL;
long i;
//
// Validate the new binding:
//
//
// See if we can merge this binding with an existing one:
//
if ( dwTcpPort == 0 || dwSslPort == 0 ) {
for ( i = 0; i < m_dwCount; i++ ) {
if ( (dwTcpPort == 0 && m_rgBindings[i].m_dwSslPort == 0) ||
(dwSslPort == 0 && m_rgBindings[i].m_dwTcpPort == 0) ) {
if ( lstrcmpi ( m_rgBindings[i].m_strIpAddress, strIpAddress ) == 0 ) {
if ( m_rgBindings[i].m_dwSslPort == 0 ) {
m_rgBindings[i].m_dwSslPort = dwSslPort;
}
else {
m_rgBindings[i].m_dwTcpPort = dwTcpPort;
}
hr = NOERROR;
goto Exit;
}
}
}
}
// Allocate the new binding array:
rgNewBindings = new CBinding [ m_dwCount + 1 ];
if ( !rgNewBindings ) {
hr = E_OUTOFMEMORY;
goto Exit;
}
// Copy the old bindings to the new array:
for ( i = 0; i < m_dwCount; i++ ) {
hr = rgNewBindings[i].SetProperties ( m_rgBindings[i] );
if ( FAILED (hr) ) {
goto Exit;
}
}
// Add the new binding to the end of the array:
hr = rgNewBindings[m_dwCount].SetProperties ( strIpAddress, dwTcpPort, dwSslPort );
if ( FAILED(hr) ) {
goto Exit;
}
_ASSERT ( SUCCEEDED(hr) );
delete [] m_rgBindings;
m_rgBindings = rgNewBindings;
rgNewBindings = NULL;
m_dwCount++;
Exit:
if (FAILED(hr) && rgNewBindings)
delete [] rgNewBindings;
TraceFunctLeave ();
return hr;
}
STDMETHODIMP CServerBindings::ChangeBinding (
long index,
IServerBinding * pBinding
)
{
TraceFunctEnter ( "CServerBindings::ChangeBinding" );
HRESULT hr = NOERROR;
CComBSTR strIpAddress;
long dwTcpPort;
long dwSslPort;
if ( index < 0 || index >= m_dwCount ) {
hr = SmtpCreateException ( IDS_SMTPEXCEPTION_INVALID_INDEX );
goto Exit;
}
hr = pBinding->get_IpAddress ( &strIpAddress );
if ( FAILED(hr) ) {
goto Exit;
}
hr = pBinding->get_TcpPort ( &dwTcpPort );
if ( FAILED(hr) ) {
goto Exit;
}
hr = pBinding->get_SslPort ( &dwSslPort );
if ( FAILED(hr) ) {
goto Exit;
}
hr = m_rgBindings[index].SetProperties ( strIpAddress, dwTcpPort, dwSslPort );
if ( FAILED(hr) ) {
goto Exit;
}
Exit:
TraceFunctLeave ();
return hr;
}
STDMETHODIMP CServerBindings::ChangeBindingDispatch ( long index, IDispatch * pDispatch )
{
HRESULT hr;
CComPtr<IServerBinding> pBinding;
hr = pDispatch->QueryInterface ( IID_IServerBinding, (void **) &pBinding );
BAIL_ON_FAILURE ( hr );
hr = ChangeBinding ( index, pBinding );
BAIL_ON_FAILURE ( hr );
Exit:
return hr;
}
STDMETHODIMP CServerBindings::Remove ( long index )
{
TraceFunctEnter ( "CServerBindings::Remove" );
HRESULT hr = NOERROR;
CBinding temp;
long cPositionsToSlide;
if ( index < 0 || index >= m_dwCount ) {
hr = SmtpCreateException ( IDS_SMTPEXCEPTION_INVALID_INDEX );
goto Exit;
}
// Slide the array down by one position:
_ASSERT ( m_rgBindings );
cPositionsToSlide = (m_dwCount - 1) - index;
_ASSERT ( cPositionsToSlide < m_dwCount );
if ( cPositionsToSlide > 0 ) {
// Save the deleted binding in temp:
CopyMemory ( &temp, &m_rgBindings[index], sizeof ( CBinding ) );
// Move the array down one:
MoveMemory ( &m_rgBindings[index], &m_rgBindings[index + 1], sizeof ( CBinding ) * cPositionsToSlide );
// Put the deleted binding on the end (so it gets destructed):
CopyMemory ( &m_rgBindings[m_dwCount - 1], &temp, sizeof ( CBinding ) );
// Zero out the temp binding:
ZeroMemory ( &temp, sizeof ( CBinding ) );
}
m_dwCount--;
Exit:
TraceFunctLeave ();
return hr;
}
STDMETHODIMP CServerBindings::Clear ( )
{
delete [] m_rgBindings;
m_rgBindings = NULL;
m_dwCount = 0;
return NOERROR;
}
//////////////////////////////////////////////////////////////////////
//
// Useful routines to go from IServerBindings to
// Metabase data types.
//
//////////////////////////////////////////////////////////////////////
static DWORD CountBindingChars ( LPCWSTR strIpAddress, DWORD dwPort )
{
_ASSERT ( IS_VALID_STRING ( strIpAddress ) );
DWORD cchResult = 0;
WCHAR wszPort [256];
wsprintf ( wszPort, _T("%u"), dwPort );
cchResult += lstrlen ( strIpAddress ); // <IPADDRESS>
cchResult += 1; // :
cchResult += lstrlen ( wszPort ); // <PORT>
cchResult += 1; // :
// cchResult += lstrlen ( strPathHeader ); // <PATHHEADER>
cchResult += 1; // For the terminating NULL
return cchResult;
}
static void ToBindingString ( LPCWSTR strIpAddress, DWORD dwPort, LPWSTR wszBinding )
{
_ASSERT ( IS_VALID_STRING ( strIpAddress ) );
_ASSERT ( dwPort != 0 );
_ASSERT ( !IsBadWritePtr ( wszBinding, CountBindingChars ( strIpAddress, dwPort ) ) );
wsprintf ( wszBinding, _T("%s:%u:"), strIpAddress, dwPort );
}
static HRESULT FromBindingString ( LPCWSTR wszBinding, LPWSTR wszIpAddressOut, DWORD * pdwPort )
{
HRESULT hr = NOERROR;
LPWSTR pchFirstColon;
LPWSTR pchSecondColon;
WCHAR wszIpAddress [ 256 ];
WCHAR wszPort [ 256 ];
long dwPort;
LPWSTR pchColon;
wszIpAddress[0] = NULL;
wszPort[0] = NULL;
pchFirstColon = wcschr ( wszBinding, _T(':') );
if ( pchFirstColon ) {
pchSecondColon = wcschr ( pchFirstColon + 1, _T(':') );
}
if ( !pchFirstColon || !pchSecondColon ) {
hr = E_FAIL;
goto Exit;
}
lstrcpyn ( wszIpAddress, wszBinding, 250 );
lstrcpyn ( wszPort, pchFirstColon + 1, 250 );
// Get the Port:
dwPort = _wtoi ( wszPort );
// Cutoff the IpAddress at the colon:
pchColon = wcschr ( wszIpAddress, _T(':') );
if ( pchColon ) {
*pchColon = NULL;
}
lstrcpy ( wszIpAddressOut, wszIpAddress );
*pdwPort = dwPort;
Exit:
return hr;
}
HRESULT
MDBindingsToIBindings (
CMultiSz * pmsz,
BOOL fTcpBindings,
IServerBindings * pBindings
)
{
HRESULT hr = NOERROR;
DWORD cBindings;
DWORD i;
LPCWSTR pchCurrent;
CBinding binding;
cBindings = pmsz->Count ();
for (
i = 0, pchCurrent = *pmsz;
i < cBindings;
i++, pchCurrent += lstrlen ( pchCurrent ) + 1
) {
WCHAR wszIpAddress[512];
DWORD dwPort;
hr = FromBindingString ( pchCurrent, wszIpAddress, &dwPort );
if ( FAILED(hr) ) {
// Skip bad binding strings:
hr = NOERROR;
continue;
}
if ( fTcpBindings ) {
hr = pBindings->Add ( wszIpAddress, dwPort, 0 );
}
else {
hr = pBindings->Add ( wszIpAddress, 0, dwPort );
}
BAIL_ON_FAILURE(hr);
}
Exit:
return hr;
}
HRESULT IBindingsToMDBindings (
IServerBindings * pBindings,
BOOL fTcpBindings,
CMultiSz * pmsz
)
{
HRESULT hr = NOERROR;
long cBindings;
long i;
DWORD cbCount = 0;
LPWSTR wszBindings = NULL;
// Count the characters of the regular bindings list:
cbCount = 0;
pBindings->get_Count ( &cBindings );
for ( i = 0; i < cBindings; i++ ) {
CComPtr<IServerBinding> pBinding;
CComBSTR strIpAddress;
long lTcpPort;
long lSslPort;
hr = pBindings->Item ( i, &pBinding );
BAIL_ON_FAILURE(hr);
pBinding->get_IpAddress ( &strIpAddress );
pBinding->get_TcpPort ( &lTcpPort );
pBinding->get_SslPort ( &lSslPort );
if ( fTcpBindings ) {
if ( lTcpPort != 0 ) {
cbCount += CountBindingChars ( strIpAddress, lTcpPort );
}
}
else {
if ( lSslPort != 0 ) {
cbCount += CountBindingChars ( strIpAddress, lSslPort );
}
}
}
if ( cbCount == 0 ) {
cbCount = 2;
wszBindings = new WCHAR [ cbCount ];
if ( !wszBindings ) {
hr = E_OUTOFMEMORY;
goto Exit;
}
wszBindings[0] = NULL;
wszBindings[1] = NULL;
}
else {
cbCount++; // For double null terminator
wszBindings = new WCHAR [ cbCount ];
if ( !wszBindings ) {
BAIL_WITH_FAILURE(hr, E_OUTOFMEMORY);
}
LPWSTR pchCurrent = wszBindings;
for ( i = 0; i < cBindings; i++ ) {
CComPtr<IServerBinding> pBinding;
CComBSTR strIpAddress;
long lTcpPort;
long lSslPort;
hr = pBindings->Item ( i, &pBinding );
BAIL_ON_FAILURE(hr);
pBinding->get_IpAddress ( &strIpAddress );
pBinding->get_TcpPort ( &lTcpPort );
pBinding->get_SslPort ( &lSslPort );
if ( fTcpBindings ) {
if ( lTcpPort != 0 ) {
ToBindingString ( strIpAddress, lTcpPort, pchCurrent );
pchCurrent += lstrlen ( pchCurrent ) + 1;
}
}
else {
if ( lSslPort != 0 ) {
ToBindingString ( strIpAddress, lSslPort, pchCurrent );
pchCurrent += lstrlen ( pchCurrent ) + 1;
}
}
}
*pchCurrent = NULL;
}
_ASSERT ( wszBindings[cbCount - 1] == NULL );
_ASSERT ( wszBindings[cbCount - 2] == NULL );
pmsz->Attach ( wszBindings );
Exit:
return hr;
}
#if 0
DWORD CBinding::SizeInChars ( )
{
DWORD cchResult = 0;
WCHAR wszTcpPort [256];
wsprintf ( wszTcpPort, _T("%d"), m_dwTcpPort );
cchResult += lstrlen ( m_strIpAddress ); // <IPADDRESS>
cchResult += 1; // :
cchResult += lstrlen ( wszTcpPort ); // <TCPPORT>
cchResult += 1; // :
// cchResult += lstrlen ( m_strPathHeader ); // <PATHHEADER>
return cchResult;
}
void CBinding::ToString ( LPWSTR wszBinding )
{
wsprintf ( wszBinding, _T("%s:%d:"), m_strIpAddress, m_dwTcpPort );
}
HRESULT CBinding::FromString ( LPCWSTR wszBinding )
{
HRESULT hr = NOERROR;
LPWSTR pchFirstColon;
LPWSTR pchSecondColon;
WCHAR wszIpAddress [ 256 ];
WCHAR wszTcpPort [ 256 ];
long dwTcpPort;
LPWSTR pchColon;
wszIpAddress[0] = NULL;
wszTcpPort[0] = NULL;
pchFirstColon = wcschr ( wszBinding, _T(':') );
if ( pchFirstColon ) {
pchSecondColon = wcschr ( pchFirstColon + 1, _T(':') );
}
if ( !pchFirstColon || !pchSecondColon ) {
hr = E_FAIL;
goto Exit;
}
lstrcpyn ( wszIpAddress, wszBinding, 250 );
lstrcpyn ( wszTcpPort, pchFirstColon + 1, 250 );
// Get the TcpPort:
dwTcpPort = _wtoi ( wszTcpPort );
// Cutoff the IpAddress at the colon:
pchColon = wcschr ( wszIpAddress, _T(':') );
if ( pchColon ) {
*pchColon = NULL;
}
m_strIpAddress = wszIpAddress;
m_dwTcpPort = dwTcpPort;
if ( !m_strIpAddress ) {
hr = E_OUTOFMEMORY;
goto Exit;
}
Exit:
return hr;
}
HRESULT CServerBindings::FromMultiSz ( CMultiSz * pmsz )
{
HRESULT hr;
DWORD cBindings;
DWORD i;
LPCWSTR pchCurrent;
CBinding binding;
hr = Clear ();
_ASSERT ( SUCCEEDED(hr) );
cBindings = pmsz->Count ();
for (
i = 0, pchCurrent = *pmsz;
i < cBindings;
i++, pchCurrent += lstrlen ( pchCurrent ) + 1
) {
hr = binding.FromString ( pchCurrent );
if ( FAILED(hr) ) {
if ( hr == E_FAIL ) {
// Skip the bad binding strings.
continue;
}
else {
goto Exit;
}
}
hr = Add ( binding.m_strIpAddress, binding.m_dwTcpPort );
if ( FAILED(hr) ) {
goto Exit;
}
}
Exit:
return hr;
}
HRESULT CServerBindings::ToMultiSz ( CMultiSz * pmsz )
{
HRESULT hr = NOERROR;
DWORD cchSize;
long i;
LPWSTR wszBindings;
LPWSTR pchCurrent;
// Special case - the empty binding list:
if ( m_dwCount == 0 ) {
cchSize = 2;
wszBindings = new WCHAR [ cchSize ];
if ( !wszBindings ) {
hr = E_OUTOFMEMORY;
goto Exit;
}
wszBindings[0] = NULL;
wszBindings[1] = NULL;
}
else {
cchSize = 0;
for ( i = 0; i < m_dwCount; i++ ) {
cchSize += m_rgBindings[i].SizeInChars ( ) + 1;
}
// Add the size of the final terminator:
cchSize += 1;
wszBindings = new WCHAR [ cchSize ];
if ( !wszBindings ) {
hr = E_OUTOFMEMORY;
goto Exit;
}
for ( i = 0, pchCurrent = wszBindings; i < m_dwCount; i++ ) {
m_rgBindings[i].ToString ( pchCurrent );
pchCurrent += lstrlen ( pchCurrent ) + 1;
}
// Add the final NULL terminator:
*pchCurrent = NULL;
}
_ASSERT ( wszBindings[cchSize - 1] == NULL );
_ASSERT ( wszBindings[cchSize - 2] == NULL );
pmsz->Attach ( wszBindings );
_ASSERT ( pmsz->Count () == (DWORD) m_dwCount );
Exit:
return hr;
}
#endif