Leaked source code of windows server 2003
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.
 
 
 
 
 
 

3757 lines
116 KiB

//***************************************************************
// IISSCO50.cpp : Implementation of CIISSCO50
// Author: Russ Gibfried
//***************************************************************
#include "stdafx.h"
#include "IISSCOv50.h"
#include "IISSCO50.h"
#include "macrohelpers.h"
#include "MessageFile\message.h"
/////////////////////////////////////////////////////////////////////////////
// CIISSCO50
// Provider Action handlers should be implemented here with the following prototypes:
// HRESULT CIISSCO50::Action();
// HRESULT CIISSCO50::ActionRollback();
HRESULT CIISSCO50::FinalConstruct( )
{
HRESULT hr = S_OK;
LONG lRes;
HKEY hkey = NULL;
WCHAR szLibReg[1024];
DWORD dwPathSize = 0;
// Open the registry key where IISScoMessageFile.dll (in EventLog)
lRes = RegOpenKeyEx( HKEY_LOCAL_MACHINE ,
L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\IISSCOv50",
0, KEY_ALL_ACCESS, &hkey );
if (lRes != ERROR_SUCCESS)
goto LocalCleanup;
// Get the Path size of EventMessageFile.
lRes = RegQueryValueEx( hkey, L"EventMessageFile", NULL,
NULL, NULL, &dwPathSize );
if (lRes != ERROR_SUCCESS)
goto LocalCleanup;
// Get the value of EventMessageFile. This is set when IISScoMessageFile.dll is registered
lRes = RegQueryValueEx( hkey, L"EventMessageFile", NULL,
NULL, (LPBYTE)szLibReg, &dwPathSize );
if (lRes != ERROR_SUCCESS)
goto LocalCleanup;
RegCloseKey( hkey );
g_ErrorModule = LoadLibrary( szLibReg );
if (g_ErrorModule == NULL)
{
hr = E_OUTOFMEMORY;
}
return hr;
LocalCleanup:
RegCloseKey( hkey );
return E_FAIL;
}
///////////////////////////////////////////////////////////////////////////////
// CIISSCO50::CreateWebSite_Execute
// Author: Russ Gibfried
// Params: [in] none
// [out] none
// Purpose: Called by MAPS framework when is encounters an action
// tag: CreateWebSite. Code creates and IIS 5 web site
//
//-------------------------------------------------------------
HRESULT CIISSCO50::CreateWebSite_Execute( IXMLDOMNode *pXMLNode )
{
TRACE_ENTER(L"CIISSCO50::CreateWebSite");
CComBSTR bWebADsPath; // adsPath: IIS://server/W3SVC
CComBSTR bstrRoot; // root directory path: c:/inetpub
CComBSTR bstrServer; // Server name; localhost if black
CComBSTR bstrSiteName; // site name; www.mysite.com
CComBSTR bstrHost; // Web Hostname
CComBSTR bstrPort; // Web port number
CComBSTR bstrIP; // Web IP address
CComBSTR bstrSBindings; // Server bindings: IP:Post:HostName
CComBSTR bServerNumber; // WebSite number: 3
//CComBSTR bFilePermissions; // File permissions: domain\user:F
CComBSTR bstrStart; // Start site when done? TRUE/FALSE
CComBSTR bstrConfigPath; // Created sites ADsPath: /W3SVC/3
CComPtr<IXMLDOMNode> pNode; // xml node <website>
HRESULT hr = S_OK;
// Get node in format: <executeData><Website number=''><Root />...
hr = pXMLNode->selectSingleNode( L"//executeXml/executeData", &pNode );
// Debug code to view passed in Node
CComBSTR bstrDebug;
hr = pNode->get_xml(&bstrDebug);
ATLTRACE(_T("\t>>> xml = : %ls\n"), bstrDebug.m_str);
// Get properties from XML
hr = GetInputAttr(pNode, L"./Website", L"number", bServerNumber);
hr = GetInputParam(pNode,L"./Website/Root", bstrRoot);
hr = GetInputParam(pNode,L"./Website/Server", bstrServer);
hr = GetInputParam(pNode,L"./Website/SiteName", bstrSiteName);
hr = GetInputParam(pNode,L"./Website/HostName", bstrHost);
hr = GetInputParam(pNode,L"./Website/PortNumber", bstrPort);
hr = GetInputParam(pNode,L"./Website/IPAddress", bstrIP);
hr = GetInputParam(pNode,L"./Website/StartOnCreate", bstrStart);
//hr = GetInputParam(pNode,L"./Website/FilePermissions", bFilePermissions);
// Create a IIS metabase path. ex. IIS://localhost/W3SVC
bWebADsPath = IIS_PREFIX;
if ( bstrServer.Length() == 0 )
bstrServer = IIS_LOCALHOST;
bWebADsPath.AppendBSTR(bstrServer);
bWebADsPath.Append(IIS_W3SVC);
// Step .5: If port number missing, set to default (ie, 80)
if ( bstrPort.Length() == 0 )
bstrPort = IIS_DEFAULT_WEB_PORT;
if ( IsPositiveInteger(bstrPort) )
{
// Step 1: Create the ServerBinding string then check bindings to make sure
// there is not a duplicate server
hr = CreateBindingString(bstrIP, bstrPort, bstrHost, bstrSBindings);
hr = CheckBindings(bWebADsPath, bstrSBindings);
if (SUCCEEDED(hr) )
{
// Step 2: Get Next available Server Number
if ( bServerNumber.Length() == 0 )
hr = GetNextIndex(bWebADsPath,bServerNumber);
// Step 3: Create the Web Site on given path, ServerNumber.
if (SUCCEEDED(hr)) hr = CreateIIs50Site(IIS_IISWEBSERVER,bWebADsPath, bServerNumber, bstrConfigPath);
IIsScoLogFailure();
// Step 4: Create a Virtual directory on new IIsWebServer configPath
if (SUCCEEDED(hr))
{
CComBSTR bstrVDirAdsPath;
hr = CreateIIs50VDir(IIS_IISWEBVIRTUALDIR,bstrConfigPath,L"ROOT", L"Default Application", bstrRoot, bstrVDirAdsPath);
IIsScoLogFailure();
// Step 5: set each property; ie, server bindings
// Bind to ADs object
CComPtr<IADs> pADs;
if (SUCCEEDED(hr)) hr = ADsGetObject(bstrConfigPath, IID_IADs, (void**) &pADs );
if ( FAILED(hr) )
{
hr = E_SCO_IIS_ADS_CREATE_FAILED;
IIsScoLogFailure();
}
// Set "ServerComment" property
if (SUCCEEDED(hr) && bstrSiteName.Length() > 0 )
{
hr = SetMetaPropertyValue(pADs, L"ServerComment", bstrSiteName);
IIsScoLogFailure();
}
// Set "ServerBindings" property
if (SUCCEEDED(hr)) hr = SetMetaPropertyValue(pADs, L"ServerBindings", bstrSBindings);
IIsScoLogFailure();
// Step 6: Start Server if required IIS_FALSE
bstrStart.ToUpper();
if ( SUCCEEDED(hr) && !StringCompare(bstrStart, IIS_FALSE) )
{
hr = SetMetaPropertyValue(pADs, L"ServerAutoStart", IIS_TRUE);
IIsScoLogFailure();
hr = IIsServerAction(bstrConfigPath,start);
IIsScoLogFailure();
}
else
{
hr = SetMetaPropertyValue(pADs, L"ServerAutoStart", IIS_FALSE);
IIsScoLogFailure();
}
// Step 7: write output to ConfigPath node <ConfigPath>/W3SVC/n</ConfigPath>
if (SUCCEEDED(hr) )
{
CComBSTR bstrXML1 = IIS_W3SVC;
bstrXML1.Append(L"/");
bstrXML1.AppendBSTR(bServerNumber.m_str);
// Helper function to write to DOM
hr = PutElement(pNode, L"./Website/ConfigPath", bstrXML1.m_str);
IIsScoLogFailure();
}
// If there is a failure, then deleted the web site created in step 3
else
{
// First delete any webseites that were created in the method. Do this here because a RollBack
// will only get called on a completed previous <step>, not a failed step.
DeleteIIs50Site(IIS_IISWEBSERVER,bWebADsPath,bServerNumber);
}
} // end if Step 4
} // end if 'CheckBindings'
}
else
{
hr = E_SCO_IIS_PORTNUMBER_NOT_VALID;
}
// If there is a failure.
if ( FAILED(hr) )
{
// Log failure.
IIsScoLogFailure();
}
else
{
// WebSite successfully created. Set Rollback data incase another step fails
// a a ROllBack is initiated.
CComVariant varData1(bWebADsPath);
CComVariant varData2(bServerNumber);
hr = m_pProvHelper->SetRollbackData(IIS_ROLL_ADSPATH, varData1);
hr = m_pProvHelper->SetRollbackData(IIS_ROLL_SERVERNUMBER, varData2);
}
TRACE_EXIT(L"CIISSCO50::CreateWebSite");
return hr;
}
///////////////////////////////////////////////////////////////////////////////
// CIISSCO50::CreateWebSite_Rollback
// Author: Russ Gibfried
// Params: [in] none
// [out] none
// Purpose: Called by MAPS framework when is encounters a failure during
// 'CreateWebSite'. The Rollback deletes the WebSite if it exists.
//-------------------------------------------------------------
HRESULT CIISSCO50::CreateWebSite_Rollback( IXMLDOMNode *pXMLNode )
{
TRACE_ENTER(L"CIISSCO50::CreateWebSiteRollback");
HRESULT hr = S_OK;
CComBSTR bWebADsPath; // AdsPath: IIS://server/W3SVC
CComBSTR bServerNumber; // Web server number
CComBSTR bstrConfigPath; // Complete ADsPath to check: IIS://localhost/W3SVC/1
CComVariant varWebADsPath;
CComVariant varServerNumber;
// Read ADsWebPath and ServerNumber to form: IIS://localhost/W3SVC/1
hr = m_pProvHelper->GetRollbackData(IIS_ROLL_ADSPATH, &varWebADsPath);
if (SUCCEEDED(hr) ) hr = m_pProvHelper->GetRollbackData(IIS_ROLL_SERVERNUMBER, &varServerNumber);
if (SUCCEEDED(hr) )
{
bServerNumber = varServerNumber.bstrVal;
bWebADsPath = varWebADsPath.bstrVal;
if ( bServerNumber.Length() > 0 )
{
bstrConfigPath = bWebADsPath.Copy();
bstrConfigPath.Append(L"/");
bstrConfigPath.AppendBSTR(bServerNumber.m_str);
// Step 1: ShutDown Server
hr = IIsServerAction(bstrConfigPath,stop);
// Step 2: Delete the server
if (SUCCEEDED(hr) ) hr = DeleteIIs50Site(IIS_IISWEBSERVER,bWebADsPath,bServerNumber);
IIsScoLogFailure();
}
else
{
hr = E_SCO_IIS_INVALID_INDEX;
}
}
else
{
hr = E_SCO_IIS_INVALID_INDEX;
}
// Log failure.
IIsScoLogFailure();
TRACE_EXIT(L"CIISSCO50::CreateWebSiteRollback");
return hr;
}
///////////////////////////////////////////////////////////////////////////////
// CIISSCO50::DeleteWebSite_Execute
// Author: Russ Gibfried
// Params: [in] none
// [out] none
// Purpose: Called by MAPS framework when is encounters an action
// tag: DeleteWebSite. Code deletes a IIS 5 web site
//
//-------------------------------------------------------------
HRESULT CIISSCO50::DeleteWebSite_Execute( IXMLDOMNode *pXMLNode )
{
TRACE_ENTER(L"CIISSCO50::DeleteWebSite");
CComBSTR bWebADsPath; // adsPath: IIS://server/W3SVC
CComBSTR bstrServer; // Server name; localhost if black
CComBSTR bServerNumber; // WebSite number: 3
CComBSTR bstrConfigPath; // Full configuartion path: IIS://localhost/W3SVC/3
CComPtr<IXMLDOMNode> pNode; // xml node <website>
HRESULT hr = S_OK;
// Get node in format: <executeData><Website number=''><Root />...
CComBSTR bstrDebug;
//hr = pXMLNode->get_xml(&bstrDebug);
hr = pXMLNode->selectSingleNode( L"//executeXml/executeData", &pNode );
hr = pNode->get_xml(&bstrDebug);
ATLTRACE(_T("\t>>> xml = : %ls\n"), bstrDebug.m_str);
// Get properties from XML
hr = GetInputAttr(pNode, L"./Website", L"number", bServerNumber);
hr = GetInputParam(pNode,L"./Website/Server", bstrServer);
// Create a IIS metabase path. ex. IIS://localhost/W3SVC
bWebADsPath = IIS_PREFIX;
if ( bstrServer.Length() == 0 )
bstrServer = IIS_LOCALHOST;
bWebADsPath.AppendBSTR(bstrServer);
bWebADsPath.Append(IIS_W3SVC);
// CreateFull configuartion path: IIS://localhost/W3SVC/3
bstrConfigPath = bWebADsPath.Copy();
bstrConfigPath.Append(L"/");
bstrConfigPath.AppendBSTR(bServerNumber.m_str);
if ( bServerNumber.Length() > 0 )
{
// Step 1: ShutDown Server
hr = IIsServerAction(bstrConfigPath,stop);
IIsScoLogFailure();
// Step 2: Delete the server
if (SUCCEEDED(hr) ) hr = DeleteIIs50Site(IIS_IISWEBSERVER,bWebADsPath,bServerNumber);
IIsScoLogFailure();
if ( SUCCEEDED(hr) )
{
// DeleteSite successfully. Set Rollback data to be whole xml node
// incase another step in SCO fails a RollBack is required.
CComBSTR webXML;
hr = pNode->get_xml(&webXML);
// convert BSTR to Variant and save in RollbackData
CComVariant varData(webXML);
hr = m_pProvHelper->SetRollbackData(IIS_ROLL_XNODE, varData);
}
}
else
{
hr = E_SCO_IIS_INVALID_INDEX;
}
if ( FAILED(hr) )
IIsScoLogFailure();
TRACE_EXIT(L"CIISSCO50::DeleteWebSite");
return hr;
}
///////////////////////////////////////////////////////////////////////////////
// CIISSCO50::DeleteWebSite_Rollback
// Author: Russ Gibfried
// Params: [in] none
// [out] none
// Purpose: Called by MAPS framework when is encounters a failure during
// 'DeleteWebSite'. The Rollback recreates the WebSite if it can.
// MAPS returns data in the format: <executeData><Website number=''>...
//-------------------------------------------------------------
HRESULT CIISSCO50::DeleteWebSite_Rollback( IXMLDOMNode *pXMLNode )
{
//hr = m_pProvHelper->GetRollbackData(L"key", &varData );
TRACE_ENTER(L"CIISSCO50::DeleteWebSiteRollback");
CComBSTR bWebADsPath; // adsPath: IIS://server/W3SVC
CComBSTR bstrRoot; // root directory path: c:/inetpub
CComBSTR bstrServer; // Server name; localhost if black
CComBSTR bstrSiteName; // site name; www.mysite.com
CComBSTR bstrHost; // Web Hostname
CComBSTR bstrPort; // Web port number
CComBSTR bstrIP; // Web IP address
CComBSTR bstrSBindings; // Server bindings: IP:Post:HostName
CComBSTR bServerNumber; // WebSite number: 3
//CComBSTR bFilePermissions; // File permissions: domain\user:F
CComBSTR bstrStart; // Start site when done? TRUE/FALSE
CComBSTR bConfigPath; // Initial <ConfigPath> value: /W3SVC/3
CComBSTR bstrConfigPath; // Created sites ADsPath: /W3SVC/3
CComVariant xmlString; // Variant string returned by MAPS
CComPtr<IXMLDOMDocument> pDoc; // xml document
CComPtr<IXMLDOMNodeList> pNodeList; // xml node list <website>
CComPtr<IXMLDOMNode> pNode; // xml node <website>
HRESULT hr = S_OK;
// Get RollBack data. Will bein form: <executeData><Website number=''>...
hr = m_pProvHelper->GetRollbackData(IIS_ROLL_XNODE, &xmlString);
// load xml string into XML Dom
if ( xmlString.bstrVal != NULL )
{
hr = CoCreateInstance(
__uuidof(DOMDocument),
NULL,
CLSCTX_ALL,
__uuidof(IXMLDOMDocument),
(LPVOID*)&pDoc);
VARIANT_BOOL bSuccess = VARIANT_FALSE;
hr = pDoc->loadXML(xmlString.bstrVal, &bSuccess);
if ( SUCCEEDED(hr) && bSuccess != VARIANT_FALSE)
{
// Check that there is a <Website> tag
hr = pDoc->getElementsByTagName(L"Website",&pNodeList);
long numChild = 0;
if (SUCCEEDED(hr)) hr = pNodeList->get_length(&numChild);
if ( numChild > 0 )
{
// Get the next node which is <Website number=''>
hr = pNodeList->nextNode(&pNode);
// Get Server number from attribute map <Website number=2">
if (SUCCEEDED(hr) )
{
hr = GetInputAttr(pNode, L"", L"number", bServerNumber);
if ( !IsPositiveInteger(bServerNumber) )
{
//hr = GetElement(pNode, L"ConfigPath", bConfigPath);
hr = ParseBSTR(bConfigPath,L'/', 2, 99, bServerNumber);
}
// Check Server number is valid
if ( !IsPositiveInteger(bServerNumber) )
{
hr = E_SCO_IIS_INVALID_INDEX;
IIsScoLogFailure();
}
}
// Get properties from XML
if (SUCCEEDED(hr) ) hr = GetInputParam(pNode, L"./Root", bstrRoot);
if (SUCCEEDED(hr) ) hr = GetInputParam(pNode, L"./Server", bstrServer);
if (SUCCEEDED(hr) ) hr = GetInputParam(pNode, L"./SiteName", bstrSiteName);
if (SUCCEEDED(hr) ) hr = GetInputParam(pNode, L"./HostName", bstrHost);
if (SUCCEEDED(hr) ) hr = GetInputParam(pNode, L"./PortNumber", bstrPort);
if (SUCCEEDED(hr) ) hr = GetInputParam(pNode, L"./IPAddress", bstrIP);
if (SUCCEEDED(hr) ) hr = GetInputParam(pNode, L"./StartOnCreate", bstrStart);
//if (SUCCEEDED(hr) ) hr = GetInputParam(pNode, L"./FilePermissions", bFilePermissions);
// Create a IIS metabase path. ex. IIS://localhost/W3SVC
bWebADsPath = IIS_PREFIX;
if ( bstrServer.Length() == 0 )
bstrServer = IIS_LOCALHOST;
bWebADsPath.AppendBSTR(bstrServer);
bWebADsPath.Append(IIS_W3SVC);
// Step .5: If port number missing, set to default (ie, 80)
if ( bstrPort.Length() == 0 )
bstrPort = IIS_DEFAULT_WEB_PORT;
if ( IsPositiveInteger(bstrPort) )
{
// Step 1: Create the ServerBinding string then check bindings to make sure
// there is not a duplicate server
CreateBindingString(bstrIP, bstrPort, bstrHost, bstrSBindings);
if (SUCCEEDED(hr) ) hr = CheckBindings(bWebADsPath, bstrSBindings);
IIsScoLogFailure();
// Step 2: Recreate Web Server
if (SUCCEEDED(hr) )
{
// Step 3: Create the Web Site on given path, ServerNumber.
if (SUCCEEDED(hr)) hr = CreateIIs50Site(IIS_IISWEBSERVER,bWebADsPath, bServerNumber, bstrConfigPath);
IIsScoLogFailure();
// Step 4: Create a Virtual directory on new IIsWebServer configPath
if (SUCCEEDED(hr))
{
CComBSTR bstrVDirAdsPath;
hr = CreateIIs50VDir(IIS_IISWEBVIRTUALDIR, bstrConfigPath,L"ROOT", L"Default Application", bstrRoot, bstrVDirAdsPath);
IIsScoLogFailure();
// Step 5: set each property; ie, server bindings
// Bind to ADs object
CComPtr<IADs> pADs;
if (SUCCEEDED(hr)) hr = ADsGetObject(bstrConfigPath, IID_IADs, (void**) &pADs );
if ( FAILED(hr) )
{
hr = E_SCO_IIS_ADS_CREATE_FAILED;
}
// Set "ServerComment" property
if (SUCCEEDED(hr) && bstrSiteName.Length() > 0 )
{
hr = SetMetaPropertyValue(pADs, L"ServerComment", bstrSiteName);
IIsScoLogFailure();
}
if (SUCCEEDED(hr)) hr = SetMetaPropertyValue(pADs, L"ServerBindings", bstrSBindings);
IIsScoLogFailure();
// Step 6: Start Server if required IIS_FALSE
bstrStart.ToUpper();
if ( SUCCEEDED(hr) )
{
if ( !StringCompare(bstrStart, IIS_FALSE) )
{
hr = SetMetaPropertyValue(pADs, L"ServerAutoStart", IIS_TRUE);
IIsScoLogFailure();
hr = IIsServerAction(bstrConfigPath,start);
IIsScoLogFailure();
}
else
{
hr = SetMetaPropertyValue(pADs, L"ServerAutoStart", IIS_FALSE);
IIsScoLogFailure();
}
}
// If there is a failure, 'IIsScoLogFailure' macro will log error
if ( FAILED(hr) )
{
// First delete any webseites that were created in the method. Do this here because a RollBack
// will only get called on a completed previous <step>, not a failed step.
DeleteIIs50Site(IIS_IISWEBSERVER,bWebADsPath,bServerNumber);
}
} // if Step 4
} // if Step 3
}
else
{
hr = E_SCO_IIS_PORTNUMBER_NOT_VALID;
IIsScoLogFailure();
} // portnumber positive
} // if hasChild
} // if isSuccessfull
}
// Log failure.
if ( FAILED(hr))
IIsScoLogFailure();
TRACE_EXIT(L"CIISSco50Obj::DeleteWebSiteRollback");
return hr;
}
///////////////////////////////////////////////////////////////////////////////
// CIISSCO50::CreateFTPSite_Execute
// Author: Russ Gibfried
// Params: [in] none
// [out] none
// Purpose: Called by MAPS framework when is encounters an action
// tag: CreateFTPSite. Code creates a IIS 5 ftp site
//
//-------------------------------------------------------------
HRESULT CIISSCO50::CreateFTPSite_Execute( IXMLDOMNode *pXMLNode )
{
TRACE_ENTER(L"CIISSCO50::CreateFTPSite");
HRESULT hr = S_OK;
CComBSTR bFTPADsPath; // adsPath: IIS://server/MSFTPSVC
CComBSTR bstrRoot; // root directory path: c:/inetpub
CComBSTR bstrServer; // Server name; localhost if black
CComBSTR bstrSiteName; // site name; www.mysite.com
CComBSTR bstrPort; // Web port number
CComBSTR bstrIP; // Web IP address
CComBSTR bstrSBindings; // Server bindings: IP:Post:HostName
CComBSTR bServerNumber; // WebSite number: 3
//CComBSTR bFilePermissions; // File permissions: domain\user:F
CComBSTR bstrStart; // Start site when done? TRUE/FALSE
CComBSTR bstrConfigPath; // Created sites ADsPath: /MSFTPSVC/3
CComPtr<IXMLDOMNode> pNode; // xml node <website>
// Get node in format: <executeData><FTPsite number=''><Root />...
hr = pXMLNode->selectSingleNode( L"//executeXml/executeData", &pNode );
// Get properties from XML
hr = GetInputAttr(pNode, L"./FTPsite", L"number", bServerNumber);
hr = GetInputParam(pNode,L"./FTPsite/Root", bstrRoot);
hr = GetInputParam(pNode,L"./FTPsite/Server", bstrServer);
hr = GetInputParam(pNode,L"./FTPsite/SiteName", bstrSiteName);
hr = GetInputParam(pNode,L"./FTPsite/PortNumber", bstrPort);
hr = GetInputParam(pNode,L"./FTPsite/IPAddress", bstrIP);
hr = GetInputParam(pNode,L"./FTPsite/StartOnCreate", bstrStart);
//hr = GetInputParam(pNode,L"./FTPsite/FilePermissions", bFilePermissions);
// Create a IIS metabase path. ex. IIS://localhost/MSFTPSVC
bFTPADsPath = IIS_PREFIX;
if ( bstrServer.Length() == 0 )
bstrServer = IIS_LOCALHOST;
bFTPADsPath.AppendBSTR(bstrServer);
bFTPADsPath.Append(IIS_MSFTPSVC);
// Step .5: If port number missing, set to default (ie, 21)
if ( bstrPort.Length() == 0 )
bstrPort = IIS_DEFAULT_FTP_PORT;
if ( IsPositiveInteger(bstrPort) )
{
// Step 1: Create the ServerBinding string to make sure not a duplicate server
hr = CreateBindingString(bstrIP, bstrPort, L"", bstrSBindings);
hr = CheckBindings(bFTPADsPath, bstrSBindings);
if (SUCCEEDED(hr) )
{
// Step 2: Get Next available Server Index
if ( bServerNumber.Length() == 0 )
hr = GetNextIndex(bFTPADsPath,bServerNumber);
// Step 3: Create the Web Site on given path, ServerNumber.
if (SUCCEEDED(hr)) hr = CreateIIs50Site(IIS_IISFTPSERVER,bFTPADsPath, bServerNumber, bstrConfigPath);
if (SUCCEEDED(hr))
{
// Step 4: Create a Virtual directory on new IIsWebServer configPath
CComBSTR bstrVDirAdsPath;
hr = CreateIIs50VDir(IIS_FTPVDIR,bstrConfigPath,L"ROOT", L"Default Application", bstrRoot, bstrVDirAdsPath);
IIsScoLogFailure();
// Step 5: set each property
CComPtr<IADs> pADs;
if (SUCCEEDED(hr)) hr = ADsGetObject(bstrConfigPath, IID_IADs, (void**) &pADs );
if (SUCCEEDED(hr))
{
// Set "ServerComment" property
if (bstrSiteName.Length() > 0 )
{
hr = SetMetaPropertyValue(pADs, L"ServerComment", bstrSiteName);
IIsScoLogFailure();
}
// Set "ServerBindings"
if (SUCCEEDED(hr)) hr = SetMetaPropertyValue(pADs, L"ServerBindings", bstrSBindings);
IIsScoLogFailure();
// Step 6: Start Server if required IIS_FALSE
bstrStart.ToUpper();
if ( SUCCEEDED(hr) && !StringCompare(bstrStart, IIS_FALSE) )
{
hr = SetMetaPropertyValue(pADs, L"ServerAutoStart", IIS_TRUE);
IIsScoLogFailure();
hr = IIsServerAction(bstrConfigPath,start);
IIsScoLogFailure();
}
else
{
hr = SetMetaPropertyValue(pADs, L"ServerAutoStart", IIS_FALSE);
IIsScoLogFailure();
}
// Step 7: write ConfigPath to output.
if (SUCCEEDED(hr) )
{
CComBSTR bstrXML1 = IIS_MSFTPSVC;
bstrXML1.Append(L"/");
bstrXML1.AppendBSTR(bServerNumber.m_str);
// Helper function to write to DOM
hr = PutElement(pNode, L"./FTPsite/ConfigPath", bstrXML1.m_str);
IIsScoLogFailure();
}
}
else
{
hr = E_SCO_IIS_ADS_CREATE_FAILED;
IIsScoLogFailure();
} // end step 4
// If something failed between steps 5-7, delete FTP site created in step 3
if ( FAILED(hr) )
{
// First delete any ftp sites that were created in the method. Do this here because a RollBack
// will only get called on a completed previous <step>, not a failed step.
DeleteIIs50Site(IIS_IISFTPSERVER,bFTPADsPath,bServerNumber);
}
} // end if L"CreateFTPSite: Could not create FTP site."
} // end if FTP ServerBindings already existed."
}
else
{
// L"CreateFTPSite: Port number must be positive value."
hr = E_SCO_IIS_PORTNUMBER_NOT_VALID;
}
// If there is a failure.
if ( FAILED(hr) )
{
// L"CreateFTPSite failed."
IIsScoLogFailure();
}
else
{
// FTP Site successfully created. Set Rollback data incase another step fails
CComVariant varData1(bFTPADsPath);
CComVariant varData2(bServerNumber);
hr = m_pProvHelper->SetRollbackData(IIS_ROLL_ADSPATH, varData1);
hr = m_pProvHelper->SetRollbackData(IIS_ROLL_SERVERNUMBER, varData2);
}
TRACE_EXIT(L"CIISSCO50::CreateFTPSite");
return hr;
}
///////////////////////////////////////////////////////////////////////////////
// CIISSCO50::CreateFTPSite_Rollback
// Author: Russ Gibfried
// Params: [in] none
// [out] none
// Purpose: Called by MAPS framework when is encounters a failure during
// 'CreateFTPSite'. The Rollback deletes the ftp if it can.
//-------------------------------------------------------------
HRESULT CIISSCO50::CreateFTPSite_Rollback( IXMLDOMNode *pXMLNode )
{
TRACE_ENTER(L"CIISSCO50::CreateFTPSiteRollback");
HRESULT hr = S_OK;
CComBSTR bFTPADsPath; // AdsPath: IIS://server/MSFTPSVC
CComBSTR bServerNumber; // Web server number
CComBSTR bstrConfigPath; // Complete ADsPath to check: IIS://localhost/MSFTPSVC/1
CComVariant varFTPADsPath;
CComVariant varServerNumber;
// Read ADsFTPPath and ServerNumber to form: IIS://localhost/MSFTPSVC/1
hr = m_pProvHelper->GetRollbackData(IIS_ROLL_ADSPATH, &varFTPADsPath);
if (SUCCEEDED(hr) ) hr = m_pProvHelper->GetRollbackData(IIS_ROLL_SERVERNUMBER, &varServerNumber);
if (SUCCEEDED(hr) )
{
bServerNumber = varServerNumber.bstrVal;
bFTPADsPath = varFTPADsPath.bstrVal;
bstrConfigPath = bFTPADsPath.Copy();
bstrConfigPath.Append(L"/");
bstrConfigPath.AppendBSTR(bServerNumber.m_str);
}
// Step 1: ShutDown Server
if (SUCCEEDED(hr)) hr = IIsServerAction(bstrConfigPath,stop);
// Only a warning if can't stop/start server given correct server path
// Step 2: Delete the server
hr = DeleteIIs50Site(IIS_IISFTPSERVER,bFTPADsPath,bServerNumber);
IIsScoLogFailure();
TRACE_EXIT(L"CIISSCO50::CreateFTPSiteRollback");
return hr;
}
///////////////////////////////////////////////////////////////////////////////
// CIISSCO50::DeleteFTPSite_Execute
// Author: Russ Gibfried
// Params: [in] none
// [out] none
// Purpose: Called by MAPS framework when is encounters an action
// tag: DeleteFTPSite. Code deletes a IIS 5 ftp site
//
//-------------------------------------------------------------
HRESULT CIISSCO50::DeleteFTPSite_Execute( IXMLDOMNode *pXMLNode )
{
TRACE_ENTER(L"CIISSCO50::DeleteFTPSite");
CComBSTR bFTPADsPath; // adsPath: IIS://server/MSFTPSVC
CComBSTR bstrServer; // Server name; localhost if blank
CComBSTR bServerNumber; // WebSite number: 3
CComBSTR bstrConfigPath; // Full configuartion path: IIS://localhost/MSFTPSVC/3
CComPtr<IXMLDOMNode> pNode; // xml node <website>
HRESULT hr = S_OK;
// Get node in format: <executeData><FTPsite number=''><Root />...
hr = pXMLNode->selectSingleNode( L"//executeXml/executeData", &pNode );
// Get properties from XML
hr = GetInputAttr(pNode, L"./FTPsite", L"number", bServerNumber);
hr = GetInputParam(pNode,L"./FTPsite/Server", bstrServer);
// Step .5: Make sure Server Number is a positive integer
if ( IsPositiveInteger(bServerNumber) )
{
// Create a IIS metabase path. ex. IIS://localhost/MSFTPSVC
bFTPADsPath = IIS_PREFIX;
if ( bstrServer.Length() == 0 )
bstrServer = IIS_LOCALHOST;
bFTPADsPath.AppendBSTR(bstrServer);
bFTPADsPath.Append(IIS_MSFTPSVC);
// Create metabase path to object: IIS://localhost/MSFTPSVC/1
bstrConfigPath = bFTPADsPath.Copy();
bstrConfigPath.Append(L"/");
bstrConfigPath.AppendBSTR(bServerNumber.m_str);
// Step 1: ShutDown Server
hr = IIsServerAction(bstrConfigPath,stop);
// Only a warning if can't stop/start server
// Step 2: Delete the server
hr = DeleteIIs50Site(IIS_IISFTPSERVER,bFTPADsPath,bServerNumber);
IIsScoLogFailure();
}
else
{
// L"DeleteFTPSite: Invalid Server number."
hr = E_SCO_IIS_INVALID_INDEX;
IIsScoLogFailure();
}
// If there is a failure
if ( FAILED(hr) )
{
// L"DeleteFTPSite failed."
IIsScoLogFailure();
}
else
{
// DeleteSite successfully. Set Rollback data to be whole xml node
// incase another step in SCO fails a RollBack is required.
CComBSTR webXML;
hr = pNode->get_xml(&webXML);
// convert BSTR to Variant and save in RollbackData
CComVariant varData(webXML);
hr = m_pProvHelper->SetRollbackData(IIS_ROLL_XNODE, varData);
}
TRACE_EXIT(L"CIISSCO50::DeleteFTPSite");
return hr;
}
///////////////////////////////////////////////////////////////////////////////
// CIISSCO50::DeleteFTPSite_Rollback
// Author: Russ Gibfried
// Params: [in] none
// [out] none
// Purpose: Called by MAPS framework when is encounters a failure during
// 'DeleteFTPSite'. The Rollback recreates the ftp Site if it can.
//-------------------------------------------------------------
HRESULT CIISSCO50::DeleteFTPSite_Rollback( IXMLDOMNode *pXMLNode )
{
TRACE_ENTER(L"CIISSCO50::DeleteFTPSiteRollback");
CComBSTR bFTPADsPath; // adsPath: IIS://server/MSFTPSVC
CComBSTR bstrRoot; // root directory path: c:/inetpub
CComBSTR bstrServer; // Server name; localhost if black
CComBSTR bstrSiteName; // site name; www.mysite.com
CComBSTR bstrPort; // Web port number
CComBSTR bstrIP; // Web IP address
CComBSTR bstrSBindings; // Server bindings: IP:Post:HostName
CComBSTR bServerNumber; // WebSite number: 3
//CComBSTR bFilePermissions; // File permissions: domain\user:F
CComBSTR bstrStart; // Start site when done? TRUE/FALSE
CComBSTR bConfigPath; // Initial <ConfigPath> value: /MSFTPSVC/3
CComBSTR bstrConfigPath; // Created sites ADsPath: /MSFTPSVC/3
CComVariant xmlString;
CComPtr<IXMLDOMDocument> pDoc; // xml document
CComPtr<IXMLDOMNodeList> pNodeList; // xml node list <website>
CComPtr<IXMLDOMNode> pNode; // xml node <website>
HRESULT hr = S_OK;
// Get RollBack data. Will bein form: <executeData><Website number=''>...
hr = m_pProvHelper->GetRollbackData(IIS_ROLL_XNODE, &xmlString);
// load xml string into XML Dom
if ( xmlString.bstrVal != NULL )
{
hr = CoCreateInstance(
__uuidof(DOMDocument),
NULL,
CLSCTX_ALL,
__uuidof(IXMLDOMDocument),
(LPVOID*)&pDoc);
VARIANT_BOOL bSuccess = VARIANT_FALSE;
if ( SUCCEEDED(hr) ) hr = pDoc->loadXML(xmlString.bstrVal, &bSuccess);
if ( SUCCEEDED(hr) && bSuccess != VARIANT_FALSE)
{
// Check that there is a <FTPSite number= > tag
hr = pDoc->getElementsByTagName(L"FTPsite",&pNodeList);
long numChild = 0;
if (SUCCEEDED(hr)) hr = pNodeList->get_length(&numChild);
if ( numChild > 0 )
{
hr = pNodeList->nextNode(&pNode);
// Get Server number from attribute map <FTPSite number=2">
if (SUCCEEDED(hr) ) hr = GetInputAttr(pNode, L"", L"number", bServerNumber);
// Check Server number is valid
if ( !IsPositiveInteger(bServerNumber) )
{
// L"DeleteFTPSiteRollback: FTP Server Number missing."
hr = E_SCO_IIS_INVALID_INDEX;
IIsScoLogFailure();
}
// Get properties from XML
if (SUCCEEDED(hr) ) hr = GetInputParam(pNode, L"./Root", bstrRoot);
if (SUCCEEDED(hr) ) hr = GetInputParam(pNode, L"./Server", bstrServer);
if (SUCCEEDED(hr) ) hr = GetInputParam(pNode, L"./SiteName", bstrSiteName);
if (SUCCEEDED(hr) ) hr = GetInputParam(pNode, L"./PortNumber", bstrPort);
if (SUCCEEDED(hr) ) hr = GetInputParam(pNode, L"./IPAddress", bstrIP);
if (SUCCEEDED(hr) ) hr = GetInputParam(pNode, L"./StartOnCreate", bstrStart);
//if (SUCCEEDED(hr) ) hr = GetInputParam(pNode, L"./FilePermissions", bFilePermissions);
if (SUCCEEDED(hr) ) hr = GetInputParam(pNode, L"./ConfigPath", bConfigPath);
// Create a IIS metabase path. ex. IIS://localhost/W3SVC
bFTPADsPath = IIS_PREFIX;
if ( bstrServer.Length() == 0 )
bstrServer = IIS_LOCALHOST;
bFTPADsPath.AppendBSTR(bstrServer);
bFTPADsPath.Append(IIS_MSFTPSVC);
// Step .5: If port number missing, set to default (ie, 21)
if ( bstrPort.Length() == 0 )
bstrPort = IIS_DEFAULT_FTP_PORT;
if ( IsPositiveInteger(bstrPort) )
{
// Step 1: Create the ServerBinding string to make sure not a duplicate server
hr = CreateBindingString(bstrIP, bstrPort, L"", bstrSBindings);
if (SUCCEEDED(hr)) hr = CheckBindings(bFTPADsPath, bstrSBindings);
IIsScoLogFailure();
// Step 2 Recreate FTP Server
if (SUCCEEDED(hr) )
{
// Step 3: Create the Web Site on given path, ServerNumber.
hr = CreateIIs50Site(IIS_IISFTPSERVER,bFTPADsPath, bServerNumber, bstrConfigPath);
IIsScoLogFailure();
// Step 4: Create a Virtual directory on new IIsFtpVirtualDir configPath
if (SUCCEEDED(hr) )
{
CComBSTR bstrVDirAdsPath;
hr = CreateIIs50VDir(IIS_FTPVDIR,bstrConfigPath,L"ROOT", L"Default Application", bstrRoot, bstrVDirAdsPath);
IIsScoLogFailure();
// Step 5 - set properties
if (SUCCEEDED(hr) )
{
CComPtr<IADs> pADs;
hr = ADsGetObject(bstrConfigPath, IID_IADs, (void**) &pADs );
if ( FAILED(hr) )
{
// L"DeleteFTPSiteRollback: Create FTP adsi object failed."
hr = E_SCO_IIS_ADS_CREATE_FAILED;
IIsScoLogFailure();
}
else
{
// Set "ServerComment" property
if (bstrSiteName.Length() > 0 )
{
hr = SetMetaPropertyValue(pADs, L"ServerComment", bstrSiteName);
IIsScoLogFailure();
}
// Set "ServerBindings"
if (SUCCEEDED(hr)) hr = SetMetaPropertyValue(pADs, L"ServerBindings", bstrSBindings);
IIsScoLogFailure();
// Step 6: Start Server if required IIS_FALSE
bstrStart.ToUpper();
if ( SUCCEEDED(hr) && !StringCompare(bstrStart, IIS_FALSE) )
{
hr = SetMetaPropertyValue(pADs, L"ServerAutoStart", IIS_TRUE);
IIsScoLogFailure();
hr = IIsServerAction(bstrConfigPath,start);
IIsScoLogFailure();
}
else
{
if (SUCCEEDED(hr)) hr = SetMetaPropertyValue(pADs, L"ServerAutoStart", IIS_FALSE);
IIsScoLogFailure();
}
} // end if Step 5
}
// If failure, delete the FTP site
if ( FAILED(hr))
{
DeleteIIs50Site(IIS_IISFTPSERVER,bFTPADsPath,bServerNumber);
}
} // end step 4
} // end if Step 2
}
else
{
// L"DeleteWebSiteRollback: Port number not a positive integer."
hr = E_SCO_IIS_PORTNUMBER_NOT_VALID;
} // step .5 portnumber positive
} // if numChild > 0
} // if isSuccessfull
}
if ( FAILED(hr) )
{
// DeleteFTPSiteRollback failed."
IIsScoLogFailure();
}
TRACE_EXIT(L"CIISSCO50::DeleteFTPSiteRollback");
return hr;
}
///////////////////////////////////////////////////////////////////////////////
// CIISSCO50::CreateVDir_Execute
// Author: Russ Gibfried
// Params: [in] none
// [out] none
// Purpose: Called by MAPS framework when is encounters an action
// tag: CreateVDir. Code creates a IIS 5 Virtual Directory
//
//-------------------------------------------------------------
HRESULT CIISSCO50::CreateVDir_Execute( IXMLDOMNode *pXMLNode )
{
TRACE_ENTER(L"CIISSCO50::CreateVDir");
CComBSTR bstrConfigPath; // adsPath: IIS://server/W3SVC/1/ROOT/MyDir
CComBSTR bServerNumber; // Server number
CComBSTR bstrServer; // Server name; localhost if blank
//CComBSTR bFilePermissions; // File permissions: domain\user:F
CComBSTR bstrDirPath; // root directory path: c:/inetpub
CComBSTR bstrVDirName; // Virtual Directory name; MyDir
CComBSTR bstrFriendlyName; // Display name or AppFriendlyName
CComBSTR bstrAppCreate; // AppCreate flag -- TRUE/FALSE
CComBSTR bstrIsoLevel; // AppIsolationLevel
CComBSTR bstrAccessRead; // AccessFalgs - AccessRead = TRUE/FALSE
CComBSTR bstrAccessScript; // AccessFalgs - AccessScript = TRUE/FALSE
CComBSTR bstrAccessWrite; // AccessFalgs - AccessWrite = TRUE/FALSE
CComBSTR bstrAccessExecute; // AccessFalgs - AccessExecute = TRUE/FALSE
CComPtr<IXMLDOMNode> pNode; // xml node. will be <executeData><VirtualDirectory>
HRESULT hr = S_OK;
// Get node in format: <executeData><VirtualDirectory number=''><Root />...
hr = pXMLNode->selectSingleNode( L"//executeXml/executeData", &pNode );
// Get properties from XML
hr = GetInputAttr(pNode,L"./VirtualDirectory", L"number", bServerNumber);
hr = GetInputParam(pNode,L"./VirtualDirectory/Server", bstrServer);
//hr = GetInputParam(pNode,L"./VirtualDirectory/FilePermissions", bFilePermissions);
hr = GetInputParam(pNode,L"./VirtualDirectory/Path", bstrDirPath);
hr = GetInputParam(pNode,L"./VirtualDirectory/VDirName", bstrVDirName);
hr = GetInputParam(pNode,L"./VirtualDirectory/DisplayName", bstrFriendlyName);
hr = GetInputParam(pNode,L"./VirtualDirectory/AppCreate", bstrAppCreate);
hr = GetInputParam(pNode,L"./VirtualDirectory/AppIsolationLevel", bstrIsoLevel);
hr = GetInputParam(pNode,L"./VirtualDirectory/AccessRead", bstrAccessRead);
hr = GetInputParam(pNode,L"./VirtualDirectory/AccessScript", bstrAccessScript);
hr = GetInputParam(pNode,L"./VirtualDirectory/AccessWrite", bstrAccessWrite);
hr = GetInputParam(pNode,L"./VirtualDirectory/AccessExecute", bstrAccessExecute);
// Step 1: Get Server number where VDir will be created
if ( !IsPositiveInteger(bServerNumber))
{
// "CreateVDir: Server number missing."
hr = E_SCO_IIS_INVALID_INDEX;
IIsScoLogFailure();
}
else
{
// Step 2: Construct the Metabase path that VDir will be created on.
// ex) IIS://localhost/W3SVC/1/ROOT
bstrConfigPath = IIS_PREFIX;
// append server name, W3SVC and server number
if ( bstrServer.Length() == 0 )
bstrServer = IIS_LOCALHOST;
bstrConfigPath.AppendBSTR(bstrServer);
bstrConfigPath.Append(IIS_W3SVC);
bstrConfigPath.Append(L"/");
bstrConfigPath.AppendBSTR(bServerNumber);
// if there is a VDir name, then it must be under 'ROOT'
if ( bstrVDirName.Length() == 0 )
{
bstrVDirName = IIS_VROOT;
}
else
{
bstrConfigPath.Append(L"/");
bstrConfigPath.Append(IIS_VROOT);
}
//Step 2: Get the AppFriendlyName
if ( bstrFriendlyName.Length() == 0 )
bstrFriendlyName = IIS_VDEFAULT_APP;
// Step 3: Create a Virtual directory on new IIsWebServer configPath
CComBSTR bstrVDirAdsPath;
hr = CreateIIs50VDir(IIS_IISWEBVIRTUALDIR,bstrConfigPath,bstrVDirName, bstrFriendlyName, bstrDirPath, bstrVDirAdsPath);
IIsScoLogFailure();
if ( SUCCEEDED(hr))
{
// Step 4: set each of the properties
// Set the server bindings
CComPtr<IADs> pADs;
if (SUCCEEDED(hr)) hr = ADsGetObject( bstrVDirAdsPath,IID_IADs, (void **)&pADs);
if ( FAILED(hr))
{
// "CreateVDir: Failed to create IADs object for VDir path."
hr = E_SCO_IIS_ADS_CREATE_FAILED;
IIsScoLogFailure();
}
// Bug# 453928 -- Default AppIsolationLevel is 2
if ( !IsPositiveInteger(bstrIsoLevel))
bstrIsoLevel = IIS_DEFAULT_APPISOLATED;
// Set AppIsolationLevel -- 'AppIsolated'
if (SUCCEEDED(hr)) hr = SetVDirProperty(pADs, L"AppIsolated",bstrIsoLevel);
IIsScoLogFailure();
// Set AccessFlags'
if ( bstrAccessRead.Length() > 0 && SUCCEEDED(hr))
{
hr = SetVDirProperty(pADs, L"AccessRead",bstrAccessRead);
IIsScoLogFailure();
}
if ( bstrAccessRead.Length() > 0 && SUCCEEDED(hr))
{
hr = SetVDirProperty(pADs, L"AccessScript",bstrAccessScript);
IIsScoLogFailure();
}
if ( bstrAccessRead.Length() > 0 && SUCCEEDED(hr))
{
hr = SetVDirProperty(pADs, L"AccessWrite",bstrAccessWrite);
IIsScoLogFailure();
}
if ( bstrAccessRead.Length() > 0 && SUCCEEDED(hr))
{
hr = SetVDirProperty(pADs, L"AccessExecute",bstrAccessExecute);
IIsScoLogFailure();
}
// Step 5: If AppCreate is FALSE, then remove the following properties.
// Bug# 453923
bstrAppCreate.ToUpper();
if ( SUCCEEDED(hr) && StringCompare(bstrAppCreate, IIS_FALSE) )
{
hr = DeleteMetaPropertyValue(pADs, L"AppIsolated");
if SUCCEEDED(hr) hr = DeleteMetaPropertyValue(pADs, L"AppRoot");
if SUCCEEDED(hr) hr = DeleteMetaPropertyValue(pADs, L"AppFriendlyName");
IIsScoLogFailure();
}
// If there is a failure.
if ( FAILED(hr) )
{
// First delete any virtual directories that were created in the method. Do this here because a RollBack
// will only get called on a completed previous <step>, not a failed step.
DeleteIIs50VDir(IIS_IISWEBVIRTUALDIR,bstrConfigPath, bstrVDirName);
}
else
{
CComBSTR bstrXML1;
// ParseBSTR
// Input: IIS://MyServer/W3SVC/1/ROOT/MyDir
// Output: /W3SVC/1/ROOT/MyDir
hr = ParseBSTR(bstrVDirAdsPath,bstrServer, 1, 99,bstrXML1);
// Matches line: <output type="WebSiteOutput" root="VirtualDirectory">
hr = PutElement(pNode, L"./VirtualDirectory/ConfigPath", bstrXML1.m_str);
}
}
}
// If there is a failure.
if ( FAILED(hr) )
{
// CreateVDir failed.
IIsScoLogFailure();
}
else
{
// WebSite successfully created. Set Rollback data incase another step fails
// a a ROllBack is initiated.
CComVariant varData1(bstrConfigPath);
CComVariant varData2(bstrVDirName);
hr = m_pProvHelper->SetRollbackData(IIS_ROLL_ADSPATH, varData1);
hr = m_pProvHelper->SetRollbackData(IIS_ROLL_VNAME, varData2);
}
TRACE_EXIT(L"CIISSCO50::CreateVDir");
return hr;
}
///////////////////////////////////////////////////////////////////////////////
// CIISSCO50::CreateVDir_Rollback
// Author: Russ Gibfried
// Params: [in] none
// [out] none
// Purpose: Called by MAPS framework when is encounters a failure during
// 'CreateVDir'. The Rollback deletes the virtual directory if it can.
//-------------------------------------------------------------
HRESULT CIISSCO50::CreateVDir_Rollback( IXMLDOMNode *pXMLNode )
{
TRACE_ENTER(L"CIISSCO50::CreateVDirRollback");
HRESULT hr = S_OK;
CComBSTR bstrVDirName; // Virtual Directory name, ie, MyDir
CComBSTR bstrConfigPath; // Complete ADsPath to VDir: IIS://localhost/W3SVC/1/ROOT
CComVariant varConfigPath;
CComVariant varVDirName;
// Read ADsWebPath and ServerNumber to form: IIS://localhost/W3SVC/1
hr = m_pProvHelper->GetRollbackData(IIS_ROLL_ADSPATH, &varConfigPath);
if (SUCCEEDED(hr) ) hr = m_pProvHelper->GetRollbackData(IIS_ROLL_VNAME, &varVDirName);
if ( SUCCEEDED(hr))
{
bstrVDirName = varVDirName.bstrVal;
bstrConfigPath = varConfigPath.bstrVal;
// Step 1: Delete the VDir
hr = DeleteIIs50VDir(IIS_IISWEBVIRTUALDIR,bstrConfigPath, bstrVDirName);
IIsScoLogFailure();
}
else
{
// "CreateVDirRollback: Failed to retrieve rollback properties."
hr = E_SCO_IIS_MISSING_FIELD;
IIsScoLogFailure();
}
TRACE_EXIT(L"CIISSCO50::CreateVDirRollback");
return hr;
}
///////////////////////////////////////////////////////////////////////////////
// CIISSCO50::DeleteVDir_Execute
// Author: Russ Gibfried
// Params: [in] none
// [out] none
// Purpose: Called by MAPS framework when is encounters an action
// tag: DeleteVDir. Code deletes a IIS 5 virtual directory
//
//-------------------------------------------------------------
HRESULT CIISSCO50::DeleteVDir_Execute( IXMLDOMNode *pXMLNode )
{
TRACE_ENTER(L"CIISSCO50::DeleteVDir");
CComBSTR bstrServer; // Server name; localhost if blank
CComBSTR bstrVDirName; // VDir name
CComBSTR bServerNumber; // WebSite number: 3
CComBSTR bstrConfigPath; // Full configuartion path: IIS://server/W3SVC/1/ROOT/MyDir
CComPtr<IXMLDOMNode> pNode; // xml node <website>
HRESULT hr = S_OK;
CComBSTR bstrDebug;
hr = pXMLNode->selectSingleNode( L"//executeXml/executeData", &pNode );
hr = pNode->get_xml(&bstrDebug);
ATLTRACE(_T("\t>>>DeleteVDir_Execute: xml = : %ls\n"), bstrDebug.m_str);
// Get properties from XML
hr = GetInputAttr(pNode, L"./VirtualDirectory", L"number", bServerNumber);
hr = GetInputParam(pNode,L"./VirtualDirectory/Server", bstrServer);
hr = GetInputParam(pNode,L"./VirtualDirectory/VDirName", bstrVDirName);
// Step 1: Get Server number where VDir will be created
if ( !IsPositiveInteger(bServerNumber) )
{
hr = E_SCO_IIS_INVALID_INDEX;
IIsScoLogFailure();
}
if (SUCCEEDED(hr))
{
// Step 2: Construct the Metabase path that VDir will be created on.
// ex) IIS://localhost/W3SVC/1/ROOT
bstrConfigPath = IIS_PREFIX;
// append server name, W3SVC and server number
if ( bstrServer.Length() == 0 )
bstrServer = IIS_LOCALHOST;
bstrConfigPath.AppendBSTR(bstrServer);
bstrConfigPath.Append(IIS_W3SVC);
bstrConfigPath.Append("/");
bstrConfigPath.AppendBSTR(bServerNumber);
// if there is a VDir name, then it must be under 'ROOT'
if ( bstrVDirName.Length() == 0 )
{
bstrVDirName = IIS_VROOT;
}
else
{
bstrConfigPath.Append(L"/");
bstrConfigPath.Append(IIS_VROOT);
}
// Step 2: Delete the server
if (SUCCEEDED(hr)) hr = DeleteIIs50VDir(IIS_IISWEBVIRTUALDIR,bstrConfigPath, bstrVDirName);
IIsScoLogFailure();
}
// If there is a failure
if ( FAILED(hr) )
{
// "DeleteVDir failed."
IIsScoLogFailure();
}
else
{
// DeleteSite successfully. Set Rollback data to be whole xml node
// incase another step in SCO fails a RollBack is required.
CComBSTR webXML;
hr = pNode->get_xml(&webXML);
// convert BSTR to Variant and save in RollbackData
CComVariant varData(webXML);
hr = m_pProvHelper->SetRollbackData(IIS_ROLL_XNODE, varData);
}
TRACE_EXIT(L"CIISSCO50::DeleteVDir");
return hr;
}
///////////////////////////////////////////////////////////////////////////////
// CIISSCO50::DeleteVDir_Rollback
// Author: Russ Gibfried
// Params: [in] none
// [out] none
// Purpose: Called by MAPS framework when is encounters a failure during
// 'DeleteVDir'. The Rollback recreates the virtual directory if it can.
//-------------------------------------------------------------
HRESULT CIISSCO50::DeleteVDir_Rollback( IXMLDOMNode *pXMLNode )
{
TRACE_ENTER(L"CIISSCO50::DeleteVDirRollback");
CComBSTR bstrConfigPath; // adsPath: IIS://server/W3SVC/1/ROOT/MyDir
CComBSTR bServerNumber; // Server number
CComBSTR bstrServer; // Server name; localhost if blank
//CComBSTR bFilePermissions; // File permissions: domain\user:F
CComBSTR bstrDirPath; // root directory path: c:/inetpub
CComBSTR bstrVDirName; // Virtual Directory name; MyDir
CComBSTR bstrFriendlyName; // Display name or AppFriendlyName
CComBSTR bstrAppCreate; // AppCreate flag -- TRUE/FALSE
CComBSTR bstrIsoLevel; // AppIsolationLevel
CComBSTR bstrAccessRead; // AccessFalgs - AccessRead = TRUE/FALSE
CComBSTR bstrAccessScript; // AccessFalgs - AccessScript = TRUE/FALSE
CComBSTR bstrAccessWrite; // AccessFalgs - AccessWrite = TRUE/FALSE
CComBSTR bstrAccessExecute; // AccessFalgs - AccessExecute = TRUE/FALSE
CComVariant xmlString;
CComPtr<IXMLDOMDocument> pDoc; // xml document
CComPtr<IXMLDOMNodeList> pNodeList; // xml node list <website>
CComPtr<IXMLDOMNode> pNode; // xml node <website>
HRESULT hr = S_OK;
// Get RollBack data. Will bein form: <executeData><Website number=''>...
hr = m_pProvHelper->GetRollbackData(IIS_ROLL_XNODE, &xmlString);
// load xml string into XML Dom
if ( xmlString.bstrVal != NULL )
{
hr = CoCreateInstance(
__uuidof(DOMDocument),
NULL,
CLSCTX_ALL,
__uuidof(IXMLDOMDocument),
(LPVOID*)&pDoc);
VARIANT_BOOL bSuccess = VARIANT_FALSE;
hr = pDoc->loadXML(xmlString.bstrVal, &bSuccess);
if ( SUCCEEDED(hr) && bSuccess != VARIANT_FALSE)
{
hr = pDoc->getElementsByTagName(XML_NODE_VDIR,&pNodeList);
long numChild = 0;
if (SUCCEEDED(hr)) hr = pNodeList->get_length(&numChild);
if ( numChild > 0 )
{
hr = pNodeList->nextNode(&pNode);
// Get Server number from attribute map <VirtualDirectory number=2">
if (SUCCEEDED(hr) ) hr = GetInputAttr(pNode, L"", L"number", bServerNumber);
IIsScoLogFailure();
// Check Server number is valid
if ( !IsPositiveInteger(bServerNumber) )
{
hr = E_SCO_IIS_INVALID_INDEX;
IIsScoLogFailure();
}
// Get properties from XML
if (SUCCEEDED(hr) ) hr = GetInputParam(pNode, L"./VirtualDirectory/Server", bstrServer);
//if (SUCCEEDED(hr) ) hr = GetInputParam(pNode, L"./VirtualDirectory/FilePermissions", bFilePermissions);
if (SUCCEEDED(hr) ) hr = GetInputParam(pNode, L"./VirtualDirectory/Path", bstrDirPath);
if (SUCCEEDED(hr) ) hr = GetInputParam(pNode, L"./VirtualDirectory/VDirName", bstrVDirName);
if (SUCCEEDED(hr) ) hr = GetInputParam(pNode, L"./VirtualDirectory/DisplayName", bstrFriendlyName);
if (SUCCEEDED(hr) ) hr = GetInputParam(pNode, L"./VirtualDirectory/AppCreate", bstrAppCreate);
if (SUCCEEDED(hr) ) hr = GetInputParam(pNode, L"./VirtualDirectory/AppIsolationLevel", bstrIsoLevel);
if (SUCCEEDED(hr) ) hr = GetInputParam(pNode, L"./VirtualDirectory/AccessRead", bstrAccessRead);
if (SUCCEEDED(hr) ) hr = GetInputParam(pNode, L"./VirtualDirectory/AccessScript", bstrAccessScript);
if (SUCCEEDED(hr) ) hr = GetInputParam(pNode, L"./VirtualDirectory/AccessWrite", bstrAccessWrite);
if (SUCCEEDED(hr) ) hr = GetInputParam(pNode, L"./VirtualDirectory/AccessExecute", bstrAccessExecute);
// Create a IIS metabase path. ex. IIS://localhost/W3SVC/1/ROOT
bstrConfigPath = IIS_PREFIX;
// append server name, W3SVC and server number
if ( bstrServer.Length() == 0 )
bstrServer = IIS_LOCALHOST;
bstrConfigPath.AppendBSTR(bstrServer);
bstrConfigPath.Append(IIS_W3SVC);
bstrConfigPath.Append(L"/");
bstrConfigPath.AppendBSTR(bServerNumber);
// if there is a VDir name, then it must be under 'ROOT'
if ( bstrVDirName.Length() == 0 )
{
bstrVDirName = IIS_VROOT;
}
else
{
bstrConfigPath.Append(L"/");
bstrConfigPath.Append(IIS_VROOT);
}
//Step 2: Get the AppFriendlyName
if ( bstrFriendlyName.Length() == 0 )
bstrFriendlyName = IIS_VDEFAULT_APP;
// Step 3: Create a Virtual directory on new IIsWebServer configPath
CComBSTR bstrVDirAdsPath;
hr = CreateIIs50VDir(IIS_IISWEBVIRTUALDIR,bstrConfigPath,bstrVDirName, bstrFriendlyName, bstrDirPath, bstrVDirAdsPath);
IIsScoLogFailure();
if ( SUCCEEDED(hr))
{
// Step 4: set each of the properties
// Set the server bindings
CComPtr<IADs> pADs;
hr = ADsGetObject( bstrVDirAdsPath,IID_IADs, (void **)&pADs);
if ( FAILED(hr) )
{
// "DeleteVDirRollback: Failed to create IADs object for VDir path."
hr = E_SCO_IIS_ADS_CREATE_FAILED;
IIsScoLogFailure();
}
// Bug# 453928 -- Default AppIsolationLevel is 2
if ( !IsPositiveInteger(bstrIsoLevel))
bstrIsoLevel = IIS_DEFAULT_APPISOLATED;
// Set AppIsolationLevel -- 'AppIsolated'
if (SUCCEEDED(hr)) hr = SetVDirProperty(pADs, L"AppIsolated",bstrIsoLevel);
IIsScoLogFailure();
// Set AccessFlags'
if ( bstrAccessRead.Length() > 0 && SUCCEEDED(hr))
{
hr = SetVDirProperty(pADs, L"AccessRead",bstrAccessRead);
IIsScoLogFailure();
}
if ( bstrAccessRead.Length() > 0 && SUCCEEDED(hr))
{
hr = SetVDirProperty(pADs, L"AccessScript",bstrAccessScript);
IIsScoLogFailure();
}
if ( bstrAccessRead.Length() > 0 && SUCCEEDED(hr))
{
hr = SetVDirProperty(pADs, L"AccessWrite",bstrAccessWrite);
IIsScoLogFailure();
}
if ( bstrAccessRead.Length() > 0 && SUCCEEDED(hr))
{
hr = SetVDirProperty(pADs, L"AccessExecute",bstrAccessExecute);
IIsScoLogFailure();
}
// Step 5: If AppCreate is FALSE, then remove the following properties.
bstrAppCreate.ToUpper();
if ( SUCCEEDED(hr) && StringCompare(bstrAppCreate, IIS_FALSE) )
{
hr = DeleteMetaPropertyValue(pADs, L"AppIsolated");
if SUCCEEDED(hr) hr = DeleteMetaPropertyValue(pADs, L"AppRoot");
if SUCCEEDED(hr) hr = DeleteMetaPropertyValue(pADs, L"AppFriendlyName");
IIsScoLogFailure();
}
} // end if step 3
}
else
{
// L"DeleteVDirRollback: VirtualDirectory child node missing from XML DOM Rollback data."
IIsScoLogFailure();
} // end if child node
}
else
{
// L"DeleteVDirRollback: Could not load XML DOM from Rollback data."
IIsScoLogFailure();
} // end if loadXML
}
else
{
// L"DeleteVDirRollback: xml string from Rollback data NULL."
IIsScoLogFailure();
} // end if xmlString != NULL
// "DeleteVDirRollback failed."
if ( FAILED(hr) )
IIsScoLogFailure();
TRACE_EXIT(L"CIISSCO50::DeleteVDirRollback");
return hr;
}
///////////////////////////////////////////////////////////////////////////////
// CIISSCO50::SetConfigProperty_Execute
// Author: Russ Gibfried
// Params: [in] none
// [out] none
// Purpose: Called by MAPS framework to set a IIS property value.
//-------------------------------------------------------------
HRESULT CIISSCO50::SetConfigProperty_Execute( IXMLDOMNode *pXMLNode )
{
TRACE_ENTER(L"CIISSCO50::SetConfigProperty");
HRESULT hr = S_OK;
CComBSTR bstrPathXML; // metabase path
CComBSTR bstrPropertyXML; // IIS property to set
CComBSTR bstrNewValueXML; // new property value
CComBSTR bstrOldValue; // current value for roll-back
CComBSTR bstrAdsiPath; // adsi path: IIS:// + bstrPathXML
CComPtr<IXMLDOMNode> pNode;
CComBSTR propertyXML;
// Get node in format: <executeData><Website number=''><Root />...
hr = pXMLNode->selectSingleNode( L"//executeXml/executeData", &pNode );
CComBSTR bstrDebug;
hr = pNode->get_xml(&bstrDebug);
ATLTRACE(_T("\t>>>SetConfigProperty_Execute: xml = : %ls\n"), bstrDebug.m_str);
// Step 1: Get the metabase path, property name and pointer to Property Node
hr = GetInputAttr(pNode, L"./ConfigPath", L"name", bstrPathXML);
if (SUCCEEDED(hr)) hr = GetInputAttr(pNode, L"./Property", L"name", bstrPropertyXML);
if (SUCCEEDED(hr)) hr = GetInputParam(pNode, L"./Property", bstrNewValueXML);
// Step 2: Get current value
if (SUCCEEDED(hr))
{
// Create a IIS metabase path. ex. IIS://W3SVC/MyServer/1
bstrAdsiPath = IIS_PREFIX;
bstrAdsiPath.AppendBSTR(bstrPathXML);
// Bind to ADs object
CComPtr<IADs> pADs;
hr = ADsGetObject(bstrAdsiPath, IID_IADs, (void**) &pADs );
if (SUCCEEDED(hr))
{
hr = GetMetaPropertyValue(pADs, bstrPropertyXML, bstrOldValue);
IIsScoLogFailure();
//Step 3: Set property data
if (SUCCEEDED(hr))
{
hr = SetMetaPropertyValue(pADs, bstrPropertyXML, bstrNewValueXML);
IIsScoLogFailure();
} // End if 'GetIIsPropertyValue'
}
else
{
// "SetConfigProperty: Failed to bind to ADs object."
hr = E_SCO_IIS_ADS_CREATE_FAILED;
IIsScoLogFailure();
}
}
else
{
hr = E_SCO_IIS_MISSING_FIELD;
} //End if 'Step 2'
// If there is a failure
if ( FAILED(hr) )
{
// SetConfigProperty Failed
IIsScoLogFailure();
}
else
{
// convert BSTR to Variant and save in RollbackData
CComVariant varData1(bstrAdsiPath);
hr = m_pProvHelper->SetRollbackData(L"ConfigPath", varData1);
// convert BSTR to Variant and save in RollbackData
CComVariant varData2(bstrPropertyXML);
hr = m_pProvHelper->SetRollbackData(L"Property", varData2);
// convert BSTR to Variant and save in RollbackData
CComVariant varData3(bstrOldValue);
hr = m_pProvHelper->SetRollbackData(L"Value", varData3);
}
TRACE_EXIT(L"CIISSCO50::SetConfigProperty");
return hr;
}
///////////////////////////////////////////////////////////////////////////////
// CIISSCO50::SetConfigProperty_Rollback
// Author: Russ Gibfried
// Params: [in] none
// [out] none
// Purpose: Called by MAPS framework to rollback a failed called
// tp 'SetMbProperty' above.
//-------------------------------------------------------------
HRESULT CIISSCO50::SetConfigProperty_Rollback( IXMLDOMNode *pXMLNode )
{
TRACE_EXIT(L"CIISSCO50::SetConfigPropertyRollback");
HRESULT hr = S_OK;
CComBSTR bstrAdsiPath;
CComBSTR bstrPropertyXML;
CComBSTR bstrOldValue;
// Get Rollback values, then convert from variants to BSTRs
CComVariant varAdsiPath;
hr = m_pProvHelper->GetRollbackData(L"ConfigPath", &varAdsiPath);
CComVariant varPropertyXML;
if (SUCCEEDED(hr)) hr = m_pProvHelper->GetRollbackData(L"Property", &varPropertyXML);
CComVariant varOldValue;
if (SUCCEEDED(hr)) hr = m_pProvHelper->GetRollbackData(L"Value", &varOldValue);
if (SUCCEEDED(hr))
{
// Convert to BSTRs
bstrAdsiPath = varAdsiPath.bstrVal;
bstrPropertyXML = varPropertyXML.bstrVal;
bstrOldValue = varOldValue.bstrVal;
// Bind to ADs object
CComPtr<IADs> pADs;
hr = ADsGetObject(bstrAdsiPath, IID_IADs, (void**) &pADs );
if (SUCCEEDED(hr))
{
hr = SetMetaPropertyValue(pADs, bstrPropertyXML, bstrOldValue);
IIsScoLogFailure();
}
else
{
hr = E_SCO_IIS_ADS_CREATE_FAILED;
IIsScoLogFailure();
}
}
else
{
// "SetConfigPropertyRollback: Failed to retrieve required rollback property ."
hr = E_SCO_IIS_MISSING_FIELD;
IIsScoLogFailure();
}
// Log failure -- SetConfigPropertyRollback Failed
if ( FAILED(hr) )
IIsScoLogFailure();
TRACE_EXIT(L"CIISSCO50::SetConfigPropertyRollback");
return hr;
}
///////////////////////////////////////////////////////////////////////////////
// CIISSCO50::GetConfigProperty_Execute
// Method: GetConfigProperty
// Author: Russ Gibfried
// Params: [in] none
// [out] none
// Purpose: Called by MAPS framework to get a IIS property value.
//-------------------------------------------------------------
HRESULT CIISSCO50::GetConfigProperty_Execute( IXMLDOMNode *pXMLNode )
{
TRACE_ENTER(L"CIISSco50Obj::GetConfigProperty");
HRESULT hr = S_OK;
CComBSTR bstrPathXML; // metabase path
CComBSTR bstrPropertyXML; // IIS property to set
CComBSTR bstrValue; // property value
CComBSTR bstrAdsiPath; // complete IIS metabase path
CComPtr<IXMLDOMNode> pNode; // xml node <property>
// Get node in format: <executeData><Website number=''><Root />...
hr = pXMLNode->selectSingleNode( L"//executeXml/executeData", &pNode );
CComBSTR bstrDebug;
hr = pNode->get_xml(&bstrDebug);
ATLTRACE(_T("\t>>>GetConfigProperty_Execute: xml = : %ls\n"), bstrDebug.m_str);
// Step 1: Get the metabase path, property name and pointer to Property Node
hr = GetInputAttr(pNode, L"./ConfigPath", L"name", bstrPathXML);
hr = GetInputAttr(pNode, L"./Property", L"name", bstrPropertyXML);
// Step 2: Get current value
if (SUCCEEDED(hr))
{
// Create a IIS metabase path. ex. IIS://W3SVC/MyServer/1
bstrAdsiPath.Append(IIS_PREFIX);
bstrAdsiPath.AppendBSTR(bstrPathXML);
// Bind to ADs object
CComPtr<IADs> pADs;
hr = ADsGetObject(bstrAdsiPath, IID_IADs, (void**) &pADs );
if (SUCCEEDED(hr))
{
hr = GetMetaPropertyValue(pADs, bstrPropertyXML, bstrValue);
if (SUCCEEDED(hr))
{
// Set the element value
hr = PutElement(pNode, L"./Property", bstrValue.m_str);
// Debug render the xml
CComBSTR bstring;
hr = pNode->get_xml(&bstring);
ATLTRACE(_T("\tGetConfigProperty: %ws\n"), bstring);
IIsScoLogFailure();
}
else
{
// "GetConfigProperty: Failed to get property."
hr = E_SCO_IIS_GET_PROPERTY_FAILED;
IIsScoLogFailure();
} // End if 'GetIIsPropertyValue'
}
else
{
// "GetConfigProperty: Failed to bind to ADs object."
hr = E_SCO_IIS_ADS_CREATE_FAILED;
IIsScoLogFailure();
}
}
else
{
// "GetConfigProperty: Input values missing."
hr = E_SCO_IIS_MISSING_FIELD;
IIsScoLogFailure();
}
// GetConfigProperty failed
if ( FAILED(hr) )
IIsScoLogFailure();
TRACE_EXIT(L"CIISSco50Obj::GetConfigProperty");
return hr;
}
///////////////////////////////////////////////////////////////////////////////
// CIISSCO50::EnumConfig_Execute
// Params: [in] none
// [out] none
// Purpose: Called by MAPS framework to list properties on a given adsi path.
// It will also list subnodes
// This is analogous to adsutil enum /w3svc/1
//-------------------------------------------------------------
HRESULT CIISSCO50::EnumConfig_Execute( IXMLDOMNode *pXMLNode )
{
TRACE_ENTER(L"CIISSCO50::EnumConfig");
HRESULT hr = S_OK;
CComBSTR bstrPathXML; // metabase path
CComBSTR bstrAdsiPath; // adsi path: IIS:// + bstrPathXML
CComBSTR bstrIsInherit; // True or false to check inheritable properties
CComPtr<IXMLDOMNode> pNode;
CComPtr<IXMLDOMNode> pConfigNode;
CComPtr<IXMLDOMNode> pTemp;
CComBSTR xmlString;
// Get node in format: <executeData><Website number=''><Root />...
hr = pXMLNode->selectSingleNode( L"//executeXml/executeData", &pNode );
CComBSTR bstrDebug;
hr = pNode->get_xml(&bstrDebug);
ATLTRACE(_T("\t>>>EnumConfig_Execute: xml = : %ls\n"), bstrDebug.m_str);
// Step .5: Get isInheritable flag. If blank, then default = TRUE
hr = GetInputAttr(pNode, L"./ConfigPath", XML_ATT_ISINHERITABLE, bstrIsInherit);
// Step 1: Get the metabase path
hr = GetInputAttr(pNode, L"./ConfigPath", L"name", bstrPathXML);
if (SUCCEEDED(hr))
{
// Step 2 Create a IIS metabase path to find properties on. ex. IIS://W3SVC/MyServer/1
bstrAdsiPath = IIS_PREFIX;
bstrAdsiPath.AppendBSTR(bstrPathXML);
// Step 3: Returns map of all properties set on this path (not inherited)
Map myProps;
hr = EnumPropertyValue(bstrAdsiPath, bstrIsInherit, myProps);
if (SUCCEEDED(hr) )
{
// Step 4: Create the <ConfigPath> element and append to pNode
xmlString = "<ConfigPath name='";
xmlString.AppendBSTR(bstrAdsiPath);
xmlString.Append(L"'></ConfigPath>");
hr = AppendElement(pNode,xmlString,pConfigNode);
if ( SUCCEEDED(hr))
{
// Iterate through property Map and append to pNode
Map::iterator it;
for (it=myProps.begin(); it != myProps.end(); it++)
{
// Create property element: <Property name='myProp'>ItsValue</Property>
xmlString = "<Property name='";
xmlString.AppendBSTR((*it).first);
xmlString.Append(L"'>");
xmlString.AppendBSTR((*it).second);
xmlString.Append(L"</Property>");
hr = AppendElement(pConfigNode,xmlString,pTemp);
pTemp = NULL;
}
}
else
{
// "EnumConfig: Call to AppendElement failed."
IIsScoLogFailure();
}
// Step 5: Get a List of subnodes and append to pNode
Map myNode;
int iCount = 0;
hr = EnumPaths(false,bstrAdsiPath,myNode);
if (SUCCEEDED(hr) )
{
// Iterate through subnodes and append to pNode
Map::iterator it;
for (it=myNode.begin(); it != myNode.end(); it++)
{
// In this case, skip the first element since it will
// be the <ConfigPath> already listed above.
if ( iCount != 0 )
{
xmlString = "<ConfigPath name='";
xmlString.AppendBSTR((*it).first);
xmlString.Append(L"' />");
hr = AppendElement(pNode,xmlString,pTemp);
pTemp = NULL;
}
iCount++;
}
}
else
{
// "EnumConfig: Failed to enumerate paths."
IIsScoLogFailure();
}
}
else
{
// "EnumConfig: Failed to enumerate properties."
IIsScoLogFailure();
}
}
else
{
// "EnumConfig: Input parameter missing."
hr = E_SCO_IIS_MISSING_FIELD;
IIsScoLogFailure();
} //End if 'Step 2'
TRACE_EXIT(L"CIISSco50Obj::EnumConfig");
return hr;
}
///////////////////////////////////////////////////////////////////////////////
// CIISSCO50::EnumConfigRecursive_Execute
// Author: Russ Gibfried
// Params: [in] none
// [out] none
// Purpose: Called by MAPS framework to list properties on a given adsi path plus
// recursively list all subnodes and their properties
// This is analogous to adsutil enum_all /w3svc/1
// Note: Only mandatory and optional properties specifically set
// on a given node are listed since listing all inherited properties
// would result in a huge output to MAPS
//-------------------------------------------------------------
HRESULT CIISSCO50::EnumConfigRecursive_Execute( IXMLDOMNode *pXMLNode )
{
TRACE_ENTER(L"CIISSCO50::EnumConfigRecursive");
HRESULT hr = S_OK;
CComBSTR bstrPathXML; // metabase path
CComBSTR bstrAdsiPath; // adsi path: IIS:// + bstrPathXML
CComBSTR bstrIsInherit; // isInheritable flag (default is true)
CComPtr<IXMLDOMNode> pNode;
CComPtr<IXMLDOMNode> pConfigNode;
CComPtr<IXMLDOMNode> pTemp;
CComBSTR xmlString;
Map myNode; // map of adsi paths
Map myProps; // map of property/values
Map::iterator it1;
Map::iterator it2;
// Get node in format: <executeData><Website number=''><Root />...
hr = pXMLNode->selectSingleNode( L"//executeXml/executeData", &pNode );
CComBSTR bstrDebug;
hr = pNode->get_xml(&bstrDebug);
ATLTRACE(_T("\t>>>EnumConfigRecursive_Execute: xml = : %ls\n"), bstrDebug.m_str);
// Step .5: Get isInheritable flag. If blank, then default = TRUE
hr = GetInputAttr(pNode, L"./ConfigPath", XML_ATT_ISINHERITABLE, bstrIsInherit);
// Step 1: Get the metabase path
hr = GetInputAttr(pNode, L"./ConfigPath", L"name", bstrPathXML);
if (SUCCEEDED(hr))
{
// Step 2 Create a IIS metabase path to find properties on. ex. IIS://W3SVC/MyServer/1
bstrAdsiPath = IIS_PREFIX;
bstrAdsiPath.AppendBSTR(bstrPathXML);
// Step 3: Get a list of all nodes; 'true' for recursive
hr = EnumPaths(true,bstrAdsiPath,myNode);
if (SUCCEEDED(hr) )
{
// Iterate through subnodes and append to pNode
for (it1=myNode.begin(); it1 != myNode.end(); it1++)
{
xmlString = "<ConfigPath name='";
xmlString.AppendBSTR((*it1).first);
xmlString.Append(L"'></ConfigPath>");
hr = AppendElement(pNode,xmlString,pConfigNode);
// Step 4: Returns map of all properties set on this path (not inherited)
if ( SUCCEEDED(hr))
{
myProps.clear();
// Pass in the path from map (ie, IIS:/w3svc/localhost/1/root )
hr = EnumPropertyValue((*it1).first,bstrIsInherit, myProps);
if (SUCCEEDED(hr) )
{
// Iterate through property Map and append to pNode
for (it2=myProps.begin(); it2 != myProps.end(); it2++)
{
// Create property element: <Property name='myProp'>ItsValue</Property>
xmlString = "<Property name='";
xmlString.AppendBSTR((*it2).first);
xmlString.Append(L"'>");
xmlString.AppendBSTR((*it2).second);
xmlString.Append(L"</Property>");
hr = AppendElement(pConfigNode,xmlString,pTemp);
pTemp = NULL;
}
// Done with pConfigNode so set it to NULL
pConfigNode = NULL;
}
else
{
// "EnumConfigRecursive: Call to EnumPropertyValue failed."
IIsScoLogFailure();
}
}
else
{
// "EnumConfigRecursive: Call to AppendElement failed."
IIsScoLogFailure();
}
} // end for myNode
}
else
{
// "EnumConfigRecursive: Failed to enumerate paths."
IIsScoLogFailure();
}
}
else
{
// "EnumConfigRecursive: Input parameter missing."
hr = E_SCO_IIS_MISSING_FIELD;
IIsScoLogFailure();
} //End if 'Step 2'
TRACE_EXIT(L"CIISSCO50::EnumConfigRecursive");
return hr;
}
//--------------------------- ADSI Helper Methods ------------------------------//
//-----------------------------------------------------------
// Method: GetMetaPropertyValue
// Author: Russ Gibfried
// Params: [in] pADs -- IADs pointer to metabase path for property value
// bstrName -- name or property
// [out] pVal -- value of property
// Purpose: Return value of particular property
//-------------------------------------------------------------
HRESULT CIISSCO50::GetMetaPropertyValue(CComPtr<IADs> pADs, CComBSTR bstrName, CComBSTR& pVal)
{
HRESULT hr;
CComVariant var;
CComBSTR bValue;
hr = pADs->Get(bstrName, &var);
if (SUCCEEDED(hr))
{
switch (var.vt)
{ case VT_EMPTY:
{
break;
}
case VT_NULL:
{
break;
}
case VT_I4:
{
hr = var.ChangeType(VT_BSTR);
if ( SUCCEEDED(hr) ) pVal = V_BSTR(&var);
break;
}
case VT_BSTR:
{
pVal = V_BSTR(&var);
break;
}
case VT_BOOL:
{
if (var.boolVal == 0)
{
pVal = L"False";
}
else
{
pVal = L"True";
}
break;
}
case VT_ARRAY|VT_VARIANT: // SafeArray of Variants
{
LONG lstart, lend;
SAFEARRAY *sa = V_ARRAY( &var );
VARIANT varItem;
// Get the lower and upper bound
hr = SafeArrayGetLBound( sa, 1, &lstart );
hr = SafeArrayGetUBound( sa, 1, &lend );
// Now iterate and print the content
VariantInit(&varItem);
CComBSTR bString;
for ( long idx=lstart; idx <= lend; idx++ )
{
hr = SafeArrayGetElement( sa, &idx, &varItem );
pVal = V_BSTR(&varItem);
VariantClear(&varItem);
}
break;
}
case VT_DISPATCH:
{
//if (!_wcsicmp(bstrName, L"ipsecurity"))
break;
}
default:
{ break;
}
}
}
if ( FAILED(hr))
hr = E_SCO_IIS_GET_PROPERTY_FAILED;
return hr;
}
//-----------------------------------------------------------
// Method: SetMetaPropertyValue
// Author: Russ Gibfried
// Params: [in] pADs -- pointer to metabase path object; ie 'IIS://MachineName/W3SVC/1'
// bstrName -- name or property
// bstrValue -- property value to set
// [out] none
// Purpose: Set the value of particular a particular property
//-------------------------------------------------------------
HRESULT CIISSCO50::SetMetaPropertyValue(CComPtr<IADs> pADs, CComBSTR bstrName, CComBSTR bstrValue)
{
HRESULT hr = E_SCO_IIS_SET_PROPERTY_FAILED;
hr = pADs->Put(bstrName, CComVariant(bstrValue));
if (SUCCEEDED(hr))
{
hr = pADs->SetInfo();
}
return hr;
}
//-----------------------------------------------------------
// Method: DeleteMetaPropertyValue
// Author: Russ Gibfried
// Params: [in] pADs -- pointer to metabase path object; ie 'IIS://MachineName/W3SVC/1'
// bstrName -- name or property
// bstrValue -- property value to set
// [out] none
// Purpose: Set the value of particular a particular property
//-------------------------------------------------------------
HRESULT CIISSCO50::DeleteMetaPropertyValue(CComPtr<IADs> pADs, CComBSTR bstrName)
{
HRESULT hr = E_SCO_IIS_SET_PROPERTY_FAILED;
VARIANT vProp;
VariantInit(&vProp);
hr = pADs->PutEx(1, bstrName, vProp); // 1 = Clear
if (SUCCEEDED(hr))
{
hr = pADs->SetInfo();
}
VariantClear(&vProp);
return hr;
}
//-----------------------------------------------------------
// Method: CreateIIs50Site
// Author: Russ Gibfried
// Params: [in] bstrType -- 'Type' of site, ie 'IIsWebServer' or 'IIsFtpServer
// bWebADsPath -- AdsPath, ex. IIS:/localhost/w3svc
// bSiteIndex -- Site number, ie, 1
// [out] bstrConfigPath -- craeted adsi path, ex. IIS://localhost/W3SVC/1
// Purpose: Set the value of particular a particular property
//-------------------------------------------------------------
HRESULT CIISSCO50::CreateIIs50Site(CComBSTR bstrType,CComBSTR bWebADsPath,
CComBSTR bServerNumber,CComBSTR &bstrConfigPath)
{
HRESULT hr = S_OK;
CComPtr<IADs> pADs;
CComPtr<IADsContainer> pCont;
IDispatch* pDisp;
CComVariant var;
// Bind to a domain object: 'IIS://MachineName/W3SVC'
hr = ADsGetObject( bWebADsPath,IID_IADsContainer, (void **)&pCont);
if (SUCCEEDED(hr))
{
//Create a virtual web server
hr = pCont->Create(bstrType,bServerNumber,&pDisp);
if ( SUCCEEDED(hr))
{
// Get the newly created ConfigPath value
hr = pDisp->QueryInterface(IID_IADs, (void**)&pADs);
if ( SUCCEEDED(hr))
{
// Release the IDispath pointer
pDisp->Release();
// Get the newly created ADsPath for this Server
if (SUCCEEDED(hr)) hr = pADs->get_ADsPath(&bstrConfigPath);
hr = pADs->SetInfo();
// Return the correct HRESULT depending is Web Site of FTP Site
if (FAILED(hr))
{
if (StringCompare(bstrType,IIS_IISWEBSERVER))
{
hr = E_SCO_IIS_CREATE_WEB_FAILED;
}
else
{
hr = E_SCO_IIS_CREATE_FTP_FAILED;
}
}
}
} // end if Create
else
{
// Return the correct HRESULT depending is Web Site of FTP Site
if (StringCompare(bstrType,IIS_IISWEBSERVER))
{
hr = E_SCO_IIS_CREATE_WEB_FAILED;
}
else
{
hr = E_SCO_IIS_CREATE_FTP_FAILED;
}
}
} // end if ADsGetObject
else
{
hr = E_SCO_IIS_ADS_CREATE_FAILED;
}
return hr;
}
//-----------------------------------------------------------
// Method: DeleteIIs50Site
// Author: Russ Gibfried
// Params: [in] bstrType -- 'Type' of site, ie 'IIsWebServer' or 'IIsFtpServer
// bWebADsPath -- server adsi path ex. IIS://localhost/W3SVC
// bServerNumber -- Server index number to delete
// Purpose: Delete a Web or FTP server
//-------------------------------------------------------------
HRESULT CIISSCO50::DeleteIIs50Site(CComBSTR bstrType,CComBSTR bWebADsPath,CComBSTR bServerNumber)
{
HRESULT hr = S_OK;
CComPtr<IADsContainer> pCont;
// Bind to a domain object: 'IIS://MachineName/W3SVC'
hr = ADsGetObject( bWebADsPath,IID_IADsContainer, (void **)&pCont);
//Delete a virtual web server
if (SUCCEEDED(hr))
{
hr = pCont->Delete(bstrType,bServerNumber);
if (FAILED(hr))
{
// Return the correct HRESULT depending is Web Site of FTP Site
if (StringCompare(bstrType,IIS_IISWEBSERVER))
{
hr = E_SCO_IIS_DELETE_WEB_FAILED;
}
else
{
hr = E_SCO_IIS_DELETE_FTP_FAILED;
}
}
}
else
{
hr = E_SCO_IIS_ADSCONTAINER_CREATE_FAILED;
}
return hr;
}
//-----------------------------------------------------------
// Method: CreateIIs50VDir
// Author: Russ Gibfried
// Params: [in] bstrType -- 'Type' of site, ie 'IIsWebVirtualDir"
// bWebADsPath -- IIS://localhost/W3SVC/1
// bVDirName -- url, ex. 'ROOT'
// bAppFriendName -- 'Default Application'
// bVDirPath -- url, ex. c:/inetpub/myDir
//
// [out] bstrConfigPath -- created adsi path, ex. IIS://localhost/W3SVC/1/ROOT
// Purpose: Set the value of particular a particular property
//-------------------------------------------------------------
HRESULT CIISSCO50::CreateIIs50VDir(CComBSTR bstrType,CComBSTR bWebADsPath, CComBSTR bVDirName,
CComBSTR bAppFriendName, CComBSTR bVDirPath,CComBSTR &bstrConfigPath)
{
HRESULT hr = S_OK;
CComPtr<IADs> pADs;
CComPtr<IADsContainer> pCont;
IDispatch* pDisp;
CComVariant var;
// Bind to a domain object: 'IIS://MachineName/W3SVC/1'
hr = ADsGetObject( bWebADsPath,IID_IADsContainer, (void **)&pCont);
if (SUCCEEDED(hr))
{
//Create a virtual directory for web server
hr = pCont->Create(bstrType,bVDirName,&pDisp);
if ( SUCCEEDED(hr))
{
// Get the newly created ConfigPath value
hr = pDisp->QueryInterface(IID_IADs, (void**)&pADs);
if ( SUCCEEDED(hr))
{
// Release the IDispath pointer
pDisp->Release();
// Set Root path and AccessRead
if (SUCCEEDED(hr)) hr = pADs->Put(L"Path",CComVariant(bVDirPath));
if (SUCCEEDED(hr)) hr = pADs->Put(L"AccessRead",CComVariant(L"TRUE"));
// Get the newly created ADsPath for this Server
if (SUCCEEDED(hr)) hr = pADs->get_ADsPath(&bstrConfigPath);
// Set the info
if (SUCCEEDED(hr)) hr = pADs->SetInfo();
//-----------------------------------------------------
// RG: Now call AppCreate through IDispatch to set the application
// Note: This only seems to work for 'IIsWebVirtualDir'??
//-----------------------------------------------------
if ( bstrType == "IIsWebVirtualDir" && SUCCEEDED(hr) )
{
DISPID dispid;
LPOLESTR str = OLESTR("AppCreate");
// Get a pointer to IDispatch from object
hr = pCont->GetObject(bstrType,bVDirName,&pDisp);
// See if object supports 'AppCreate' and dispid
if (SUCCEEDED(hr)) hr = pDisp->GetIDsOfNames(IID_NULL, &str, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
// Set the parameters
VARIANT myVars[1];
VariantInit(&myVars[0]);
myVars[0].vt = VT_BOOL;
myVars[0].boolVal = true;
DISPPARAMS params = {myVars,0,1,0};
// Invoke 'AppCreate'
if (SUCCEEDED(hr)) hr = pDisp->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT,
DISPATCH_METHOD,&params, NULL, NULL, NULL);
// Cleanup
if (SUCCEEDED(hr)) hr = pDisp->Release();
//VariantClear(&myVars);
// Set AppFriendlyName
if (SUCCEEDED(hr)) hr = pADs->Put(L"AppFriendlyName",CComVariant(bAppFriendName));
// Set the info
if (SUCCEEDED(hr)) hr = pADs->SetInfo();
}
// Check for failure
if ( FAILED(hr)) hr = E_SCO_IIS_CREATE_VDIR_FAILED;
}
else
{
hr = E_SCO_IIS_ADS_CREATE_FAILED;
}
} // end if Create
else
{
hr = E_SCO_IIS_CREATE_VDIR_FAILED;
}
} // end if ADsGetObject
else
{
hr = E_SCO_IIS_ADSCONTAINER_CREATE_FAILED;
}
return hr;
}
//-----------------------------------------------------------
// Method: DeleteIIs50VDir
// Author: Russ Gibfried
// Params: [in] bstrType -- 'Type' of site, ie 'IIsWebVirtualDir"
// bWebADsPath -- IIS://localhost/W3SVC/1
// bVDirName -- url, ex. 'ROOT'
//
// [out] bstrConfigPath -- created adsi path, ex. IIS://localhost/W3SVC/1/ROOT
// Purpose: Set the value of particular a particular property
//-------------------------------------------------------------
HRESULT CIISSCO50::DeleteIIs50VDir(CComBSTR bstrType,CComBSTR bWebADsPath, CComBSTR bVDirName)
{
HRESULT hr = S_OK;
CComPtr<IADsContainer> pCont;
IDispatch* pDisp;
// Bind to a domain object: 'IIS://MachineName/W3SVC/1'
hr = ADsGetObject( bWebADsPath,IID_IADsContainer, (void **)&pCont);
if (SUCCEEDED(hr))
{
//-----------------------------------------------------
// RG: Now call AppDelete through IDispatch to set the application
//-----------------------------------------------------
DISPID dispid;
LPOLESTR str = OLESTR("AppDelete");
// Get a pointer to IDispatch from object
if (SUCCEEDED(hr)) hr = pCont->GetObject(bstrType,bVDirName,&pDisp);
// See if object supports 'AppCreate' and dispid
if (SUCCEEDED(hr)) hr = pDisp->GetIDsOfNames(IID_NULL, &str, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
// Set the parameters
//VARIANT myVars[1];
//VariantInit(&myVars[0]);
//myVars[0].vt = VT_BOOL;
///myVars[0].boolVal = true;
DISPPARAMS params = {NULL,NULL,0,0};
// Invoke 'AppCreate'
if (SUCCEEDED(hr)) hr = pDisp->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT,
DISPATCH_METHOD,&params, NULL, NULL, NULL);
// Cleanup
if (SUCCEEDED(hr)) hr = pDisp->Release();
//VariantClear(&myVars);
//Delete the virtual directory at VDirName
if (SUCCEEDED(hr)) hr = pCont->Delete(bstrType,bVDirName);
if ( FAILED(hr) )
hr = E_SCO_IIS_DELETE_VDIR_FAILED;
} // end if ADsGetObject
else
{
hr = E_SCO_IIS_ADSCONTAINER_CREATE_FAILED;
}
return hr;
}
//-----------------------------------------------------------
// Method: SetVDirProperty
// Author: Russ Gibfried
// Params: [in]
// pADs -- pointer to ADs object for something like IIS://localhost/W3SVC/1/ROOT
// bVDirProperty -- , ex. 'AuthFlags'
// bVDirValue -- property value
//
// [out] none
// Purpose: Set the value of particular a particular property for a Virtual Directory
//-------------------------------------------------------------
HRESULT CIISSCO50::SetVDirProperty(CComPtr<IADs> pADs, CComBSTR bVDirProperty,CComBSTR bVDirValue)
{
HRESULT hr = E_FAIL;
// Bind to a domain object: 'IIS://MachineName/W3SVC/1/ROOT'
if ( pADs != NULL )
{
// Set the property
hr = pADs->Put(bVDirProperty,CComVariant(bVDirValue));
// Set the info
if (SUCCEEDED(hr)) hr = pADs->SetInfo();
} // end if ADsGetObject
if ( FAILED(hr))
hr = E_SCO_IIS_SET_PROPERTY_FAILED;
return hr;
}
//-----------------------------------------------------------
// Method: EnumPaths
// Author: Russ Gibfried
// Params: [in] bRecursive -- Boolean; true to recursely iterate through subnodes
// bstrPath -- metabase path for key to Enumerate
// [out] variant SafeArray
// Purpose: Enumerate the keys/nodes for a given ADsPath
// Example: IIS://localhost/W3SVC/1 yields IISCertMapper and Root
//-------------------------------------------------------------
HRESULT CIISSCO50::EnumPaths(BOOL bRecursive,CComBSTR bstrPath, Map& mVar)
{
//initialize
HRESULT hr = E_FAIL;
IADs *pADs;
CComPtr<IADsContainer> pCont;
VARIANT var;
ULONG lFetch;
IDispatch *pDisp;
IEnumVARIANT *pEnum;
// Get the container object for given ADsPath
hr = ADsGetObject(bstrPath, IID_IADsContainer, (void**) &pCont );
if ( SUCCEEDED(hr))
{
//add to Map
mVar[bstrPath] = bstrPath;
// Create a Enum object in container
hr = ADsBuildEnumerator(pCont, &pEnum);
// Walk through all providers
while (hr == S_OK)
{
hr = ADsEnumerateNext(pEnum,1,&var,&lFetch);
if ( lFetch == 1)
{
pDisp = V_DISPATCH(&var);
pDisp->QueryInterface(IID_IADs, (void**)&pADs);
pDisp->Release();
BSTR bstr;
pADs->get_ADsPath(&bstr);
pADs->Release();
// true if we are to recursively navigate lower nodes
if ( bRecursive )
{
EnumPaths(bRecursive,bstr, mVar);
}
else
{
mVar[bstr] = bstr;
}
SysFreeString(bstr);
}
}
if ( pEnum )
ADsFreeEnumerator(pEnum);
}
else
{
hr = E_SCO_IIS_ADS_CREATE_FAILED;
}
return hr;
}
//-----------------------------------------------------------
// Method: EnumPropertyValue
// Author: Russ Gibfried
// Params: [in] bstrPath -- metabase path for key to Enumerate
// [in] bstrIsInHerit -- True/False if required to display inheritable properties
// [out] variant SafeArray
// Purpose: Make sure IIS://localhost/W3SVC/2
//-------------------------------------------------------------
HRESULT CIISSCO50::EnumPropertyValue(CComBSTR bstrPath, CComBSTR bstrIsInHerit, Map& mVar)
{
//initialize
HRESULT hr = S_OK;
CComPtr<IADs> pADs;
CComPtr<IADsClass> pCls;
CComBSTR bstrSchema;
CComPtr<IISBaseObject> pBase;
// variables for SafeArray or properties
LONG lstart, lend;
CComBSTR bstrProperty;
CComBSTR bstrValue;
// Set bstrIsInHerit to uppercase
bstrIsInHerit.ToUpper();
// Bind to a domain object -- this will give us schema, class and name
hr = ADsGetObject(bstrPath, IID_IADs, (void**) &pADs );
if ( SUCCEEDED(hr)) hr = pADs->get_Schema(&bstrSchema);
if ( SUCCEEDED(hr))
{
// Bind to IIS Admin Object so we can determine if properties are inherited or not
hr = ADsGetObject(bstrPath, IID_IISBaseObject, (void**) &pBase );
if ( SUCCEEDED(hr))
{
// Bind to schema object and get all optional properties
hr = ADsGetObject(bstrSchema,IID_IADsClass, (void**)&pCls);
if ( SUCCEEDED(hr))
{
//********** Get Mandatory Properties ************************
VARIANT varProperty;
VariantInit(&varProperty);
hr = pCls->get_MandatoryProperties(&varProperty);
// iterate through properties
if ( SUCCEEDED(hr))
{
VARIANT varItem;
SAFEARRAY *sa = V_ARRAY( &varProperty );
hr = SafeArrayGetLBound( sa, 1, &lstart );
hr = SafeArrayGetUBound( sa, 1, &lend );
VariantInit(&varItem);
// For loop through properties
for ( long idx=lstart; idx <= lend; idx++ )
{
// Get a property
hr = SafeArrayGetElement( sa, &idx, &varItem );
bstrProperty = V_BSTR(&varItem);
VariantClear(&varItem);
// if isInheriable = false, then properties must be set on path
if ( SUCCEEDED(hr) && !StringCompare(bstrIsInHerit, IIS_FALSE) )
{
// True -- just return property
hr = GetMetaPropertyValue(pADs, bstrProperty, bstrValue);
if ( SUCCEEDED(hr) ) mVar[bstrProperty] = bstrValue;
}
else
{
// False -- Check if property set on this path
if ( EnumIsSet(pBase,bstrPath,bstrProperty))
{
// This property was set on this path. Get the value and add to map
hr = GetMetaPropertyValue(pADs, bstrProperty, bstrValue);
if ( SUCCEEDED(hr) ) mVar[bstrProperty] = bstrValue;
}
}
} // end For
}
//********** Repeat for Optional Properties ************************
VariantClear(&varProperty);
VariantInit(&varProperty);
hr = pCls->get_OptionalProperties(&varProperty);
// iterate through properties
if ( SUCCEEDED(hr))
{
VARIANT varItem;
SAFEARRAY *sa = V_ARRAY( &varProperty );
hr = SafeArrayGetLBound( sa, 1, &lstart );
hr = SafeArrayGetUBound( sa, 1, &lend );
VariantInit(&varItem);
// For loop through properties
for ( long idx=lstart; idx <= lend; idx++ )
{
// Get a property
hr = SafeArrayGetElement( sa, &idx, &varItem );
bstrProperty = V_BSTR(&varItem);
VariantClear(&varItem);
// if isInheriable = false, then properties must be set on path
if ( SUCCEEDED(hr) && !StringCompare(bstrIsInHerit, IIS_FALSE) )
{
// True -- just return property
hr = GetMetaPropertyValue(pADs, bstrProperty, bstrValue);
if ( SUCCEEDED(hr) ) mVar[bstrProperty] = bstrValue;
}
else
{
// False -- Check if property set on this path
if ( EnumIsSet(pBase,bstrPath,bstrProperty))
{
// This property was set on this path. Get the value and add to map
hr = GetMetaPropertyValue(pADs, bstrProperty, bstrValue);
if ( SUCCEEDED(hr) ) mVar[bstrProperty] = bstrValue;
}
}
} // end For
} // end if
VariantClear(&varProperty);
}
else
{
// failed to bind to schema
hr = E_SCO_IIS_ADSCLASS_CREATE_FAILED;
}
}
else
{
// failed to bind to IIS BaseObject
hr = E_SCO_IIS_BASEADMIN_CREATE_FAILED;
}
}
else
{
// failed to bind to ADs Object
hr = E_SCO_IIS_ADS_CREATE_FAILED;
}
return hr;
}
//-----------------------------------------------------------
// Method: EnumIsSet
// Params: [in] pBase -- pointer to IISBaseObject for given 'bstrPath'
// bstrPath -- adsi Path; IIS://localhost/W3SVC/2
// bstrProperty -- property found in schema for this path
// [out] Boolean - True is the property was set for given path and not
// inherited from another key.
// Purpose: Function checks the paths returned by 'GetDataPaths' for a given property
// to current path to determine if property was actually set at this path.
//
// Note: You can easily extend this function by adding a flag to only check
// for inheritable properties, all properties or non-inheritable.
//-------------------------------------------------------------
BOOL CIISSCO50::EnumIsSet(CComPtr<IISBaseObject> pBase, CComBSTR bstrPath, CComBSTR bstrProperty)
{
VARIANT pvPaths; // list of paths returned by 'GetDataPaths'
VARIANT *varPath; // property path
SAFEARRAY *PathArray; // SafeArray to hold pvPaths
BOOL bFound = false;
HRESULT hr;
// Get Property paths
VariantInit(&pvPaths);
VariantClear(&pvPaths);
// Check if this is a inheritable property
hr = pBase->GetDataPaths(bstrProperty,1,&pvPaths);
if ( SUCCEEDED(hr) )
{
//Any property
PathArray = pvPaths.parray;
varPath = (VARIANT*)PathArray->pvData;
if ( varPath->vt == VT_BSTR)
{
if ( !_wcsicmp(varPath->bstrVal,bstrPath.m_str) )
{
// This property was set on this path.
bFound = true;
}
}
}
// Check if this is not an inheritable property
else
{
VariantClear(&pvPaths);
VariantInit(&pvPaths);
hr = pBase->GetDataPaths(bstrProperty,0,&pvPaths);
if ( SUCCEEDED(hr) )
{
//Inheritable property
PathArray = pvPaths.parray;
varPath = (VARIANT*)PathArray->pvData;
if ( varPath->vt == VT_BSTR)
{
if ( !_wcsicmp(varPath->bstrVal,bstrPath.m_str))
{
// This property was set on this path. Get the value and add to map
bFound = true;
}
}
} // end if GetDataPaths -- IIS_ANY_PROPERTY
} // end if GetDataPaths -- IIS_INHERITABLE_ONLY
VariantClear(&pvPaths);
return bFound;
}
//-----------------------------------------------------------
// Method: IIsServerAction
// Author: Russ Gibfried
// Params: [in] bWebADsPath -- IIS://localhost/W3SVC/1
// action -- Start, Stop or Pause
//
// [out] HRESULT
// Purpose: Start, stop or pause a web site
//-------------------------------------------------------------
HRESULT CIISSCO50::IIsServerAction(CComBSTR bWebADsPath,IIsAction action)
{
HRESULT hr = E_FAIL;
CComPtr<IADsServiceOperations> pService;
// Bind to a domain object: 'IIS://MachineName/W3SVC/1'
hr = ADsGetObject( bWebADsPath,IID_IADsServiceOperations, (void **)&pService);
if (SUCCEEDED(hr))
{
// Perform the action on the server
switch ( action )
{
// Start the server
case start:
hr = pService->Start();
break;
// Stop the server
case stop:
hr = pService->Stop();
break;
// Pause the Server
case pause:
hr = pService->Pause();
break;
default:
break;
} // end switch
} // end if
else
{
hr = E_SCO_IIS_ADSSERVICE_CREATE_FAILED;
}
return hr;
}
//-----------------------------------------------------------
// Method: GetNextIndex
// Author: Russ Gibfried
// Params: [in] bstrPath -- metabase path for IIsWebService
// bstrName -- name or property
// bstrValue -- property value to set
// [out] none
// Purpose: Set the value of particular a particular property
//-------------------------------------------------------------
HRESULT CIISSCO50::GetNextIndex(CComBSTR bstrPath, CComBSTR& pIndex)
{
// initialize
HRESULT hr = S_OK;
CComPtr<IADs> pObj;
long lCount = 1;
CComVariant var = lCount;
// initialize starting path: IIS://MyServer/W3SVC/
CComBSTR tempPath = bstrPath.Copy();
tempPath.Append(L"/");
// Append 1 to starting path: IIS://MyServer/W3SVC/1
var.ChangeType(VT_BSTR);
tempPath.Append(var.bstrVal);
// Loop through each server until fails, then we have the next server number
try
{
while ( SUCCEEDED( ADsGetObject( tempPath,IID_IADs, (void **)&pObj) ))
{
lCount++;
tempPath = bstrPath.Copy();
tempPath.Append(L"/");
var = lCount;
var.ChangeType(VT_BSTR);
tempPath.Append(var.bstrVal);
pObj = NULL;
}
}
catch(...)
{
// unhandled exception
hr=E_FAIL;
}
var.ChangeType(VT_BSTR);
ChkAllocBstr(pIndex,var.bstrVal);
return hr;
}
//------------------------------------------------------------------------------
// Method: CreateBindingString
// Author: Russ Gibfried
// Params: [in] bstrIP -- site IP
// bstrPort -- site port
// bstrHostName -- site HostName
// [out] bstrString -- server binding string
// Purpose: Creates a binding string in the format IP:Port:Hostname.
// Used in other methods to check existing server bindings and
// set new bindings. Both the IP and Hostname parameter of the string are optional.
//-------------------------------------------------------------------------------
HRESULT CIISSCO50::CreateBindingString(CComBSTR bstrIP,CComBSTR bstrPort,
CComBSTR bstrHostName,CComBSTR& bstrString)
{
bstrString.AppendBSTR(bstrIP);
bstrString.Append(L":");
bstrString.AppendBSTR(bstrPort);
bstrString.Append(L":");
bstrString.AppendBSTR(bstrHostName);
return 0;
}
//------------------------------------------------------------------------------
// Method: CheckBindings
// Author: Russ Gibfried
// Params: [in] bWebADsPath -- ADs path to bind to search
// bstrNewBindings -- site IP
// [out] none
// Purpose: This compares current server bindings to the requested new bindings
// to make sure there is not a duplicate server already running. Binding
// string format is IP:Port:Hostname.
//
// Note Both the IP and Hostname parameter of the string are optional.
// Any unspecified parameters default to an all-inclusive wildcard.
//
// Metabase Path Key Type
// /LM/MSFTPSVC/N IIsFtpServer
// /LM/W3SVC/N IIsWebServer
//-------------------------------------------------------------------------------
HRESULT CIISSCO50::CheckBindings(CComBSTR bWebADsPath, CComBSTR bstrNewBindings)
{
// initialize
HRESULT hr = E_FAIL;
CComPtr<IADsContainer> pCont;
IADs* pADs;
CComVariant vBindings;
BSTR bstr;
IEnumVARIANT* pEnum;
LPUNKNOWN pUnk;
VARIANT var;
IDispatch *pDisp;
ULONG lFetch;
VariantInit(&var);
// Get a container to IIsWebService object
hr = ADsGetObject(bWebADsPath, IID_IADsContainer, (void**) &pCont );
if ( !SUCCEEDED(hr) )
{
return E_SCO_IIS_ADSCONTAINER_CREATE_FAILED;
}
// Get an enumeration of all objects below it
pCont->get__NewEnum(&pUnk);
pUnk->QueryInterface(IID_IEnumVARIANT, (void**) &pEnum);
pUnk->Release();
// Now Enumerate through objects
hr = pEnum->Next(1, &var, &lFetch);
while(hr == S_OK)
{
if (lFetch == 1)
{
pDisp = V_DISPATCH(&var);
pDisp->QueryInterface(IID_IADs, (void**)&pADs);
pDisp->Release();
pADs->get_Class(&bstr); // Debug to see Class
SysFreeString(bstr);
hr = pADs->Get(L"ServerBindings",&vBindings);
// Check server bindings for this class
if ( SUCCEEDED(hr) )
{
LONG lstart, lend;
SAFEARRAY *sa = V_ARRAY( &vBindings );
VARIANT varItem;
// Get the lower and upper bound
hr = SafeArrayGetLBound( sa, 1, &lstart );
hr = SafeArrayGetUBound( sa, 1, &lend );
// Now iterate and print the content
VariantInit(&varItem);
CComBSTR bString;
for ( long idx=lstart; idx <= lend; idx++ )
{
hr = SafeArrayGetElement( sa, &idx, &varItem );
bString = V_BSTR(&varItem);
VariantClear(&varItem);
}
// Checkbindings. If match then fail;
if ( bstrNewBindings == bString)
{
hr = E_SCO_IIS_DUPLICATE_SITE;
pEnum->Release();
VariantClear(&var);
goto Leave;
}
} // end if 'bindings'
} // end if 'enum'
VariantClear(&var);
hr = pEnum->Next(1, &var, &lFetch);
}; // end while
pEnum->Release();
Leave:
return hr;
}
//-----------------------------------------------------------
// Method: AddBackSlashesToString
// Author: Russ Gibfried
// Params: [in] bString -- BSTR to parse; ie 'redmond\bob:F'
//
// [out] bString -- 'redmond\\bob:F'
// Purpose: If string has only one backslash, add two since backslash is an
// escape character.
//-------------------------------------------------------------
void CIISSCO50::AddBackSlashesToString(CComBSTR& bString)
{
// initialize variables
size_t start, length, db; // string counters
start = 0; // start of string
db = 0; // index if '\\' found ( db = double backslash)
// Convert the BSTR to a std:string
USES_CONVERSION;
std::string s = OLE2A(bString.m_str);
std::string temp1,temp2,temp3 = "";
length = s.length();
// Loop through string looking for single slashes
for (size_t pos = s.find("\\")+1; pos < length; pos = s.find("\\", pos+2)+1)
{
// pos = 0 when it goes off end of string
if ( pos == 0 ) break;
// find location of double slash
db = s.find("\\\\",pos-2)+1;
// pos is the location of a single slash, if it matches db then we really have
// the first part of a double slash; so skip
if ( pos != db )
{
// replace the single slash with a double '\\'
temp1 = s.substr(start,pos-1);
temp2 = s.substr(pos,length);
s = temp1 + "\\\\" + temp2;
}
}
// return
bString = A2BSTR(s.c_str());
}
//-----------------------------------------------------------
// Method: ParseBSTR
// Author: Russ Gibfried
// Params: [in] bString -- BSTR to parse; ie 'redmond\bob:F'
// delim -- deliminator; ie ':' or 'IIS://'
// iFirstPiece -- starting piece of BSTR to return; ie 1
// iLastPiece -- ending piece of BSTR to return; ie 99
//
// [out] pVal -- piece of BSTR; ie, 'redmond\bob'
// Purpose: uses std:string functionality to parse an BSTR given a deliminator
// and which part of BSTR should be returned.
// ex) bString = "IIS://localhost/W3SVC/1/ROOT/1
// (bString,1,99,'host') --> /W3SVC/1/ROOT/1
// (bString,2,3,'/') --> localhost
// (bString,4,99,'/') --> 1
// (bString,2,4,'/') --> localhost/W3SVC
//-------------------------------------------------------------
HRESULT CIISSCO50::ParseBSTR(CComBSTR bString,CComBSTR sDelim, int iFirstPiece, int iLastPiece,CComBSTR &pVal)
{
// ------ initialize variables ------------------
// start = begining of substring
// end = end of substring
// count = counter of number of deliminators found
// done = variable to end while loop for each piece
// length = length of original string
//--------------------------------------
HRESULT hr = S_OK;
size_t start,end;
int iCount, done, iLength;
done = start = end = 0;
iCount = 0; // first piece to look for.
// If last piece is not greater that fist then end
if ( iLastPiece < iFirstPiece)
done=1;
USES_CONVERSION;
// deliminator
std::string myDelim = OLE2A(sDelim.m_str);
long iDelimLen = myDelim.length();
// my string
std::string myString = OLE2A(bString.m_str);
iLength = myString.length();
// temp and new string
std::string newString = "";
std::string tmpString = "";
while (!done)
{
// find the start of the piece
end = myString.find(myDelim,start);
if ( iCount >= iFirstPiece && iCount <= (iLastPiece-1))
{
//we want this piece
tmpString = myString.substr(start,end-start);
newString.append(tmpString);
// if iCount < iLastPiece and we're not at the end, then append deliminator too
if ( iCount < (iLastPiece-1) && end < iLength)
newString.append(myDelim);
}
// if we have gone passed end of string quit, else increment
// deliminator and string counters.
if ( end >= iLength || iCount >= (iLastPiece-1))
{
done = 1;
}
else
{
start = end + iDelimLen; // increment start
iCount++;
}
}
//convert string back to BSTR -- A2BSTR
pVal = A2BSTR(newString.c_str());
return hr;
}
//-----------------------------------------------------------
// Method: NumberOfDelims
// Author: Russ Gibfried
// Params: [in] bString -- BSTR to parse; ie 'redmond\bob:F'
// sDelim -- deliminator to find
//
// [out] int -- number of deliminators found in string
// Purpose: Return the number of deliminators found in a string. This is used
// by 'PutElement'
//-------------------------------------------------------------
int CIISSCO50::NumberOfDelims(CComBSTR& bString, CComBSTR bDelim)
{
// initialize variables
int iCount = 0;
int length;
// Convert the BSTR to a std:string
USES_CONVERSION;
std::string s = OLE2A(bString.m_str);
std::string sDelim = OLE2A(bDelim.m_str);
length = s.length();
// Loop through string looking for deliminator
for (size_t pos = s.find(sDelim)+1; pos < length; pos = s.find(sDelim, pos+2)+1)
{
// pos = 0 when it goes off end of string
if ( pos == 0 ) break;
iCount++;
}
// return
return iCount;
}
/* --------------------- XML Helper Methods ------------------------------- */
//-----------------------------------------------------------
// Method: GetElementValueByAttribute
// Author: Russ Gibfried
// Params: [in] elementName -- element name to look for
// [out] pVal -- value of element
// Purpose: Return value of particular element in XML document
// <Property name="someName">someValue</Property>
//-------------------------------------------------------------
HRESULT CIISSCO50::GetElementValueByAttribute(CComPtr<IXMLDOMNode> pTopNode,CComBSTR elementName, CComBSTR attributeName, CComBSTR& pVal)
{
HRESULT hr = S_OK;
CComPtr<IXMLDOMNodeList> pNodeList; // List of nodes matching elementName
CComPtr<IXMLDOMNode> pNode; // individual node
CComPtr<IXMLDOMNamedNodeMap> pAttributeMap;
CComPtr<IXMLDOMNode> pXMLElement;
// Get a node list, ie, all <Property> tags
if (S_OK == (hr = pTopNode->selectNodes(elementName,&pNodeList)))
{
// Get the number of nodes and loop through them looking for
// specific Property found in attribute 'name='
long lLength;
pNodeList->get_length(&lLength);
for ( int i=0; i < lLength; i++)
{
// Get a node
hr = pNodeList->get_item(i,&pNode);
if ( SUCCEEDED(hr))
{
//Get 'name' attribute of this nodes <Property> tag
hr = pNode->get_attributes(&pAttributeMap);
if ( SUCCEEDED(hr))
{
BSTR bstrProperty = SysAllocString(L"");
hr = pAttributeMap->getNamedItem(L"name",&pXMLElement);
if (SUCCEEDED(hr)) hr = pXMLElement->get_text(&bstrProperty);
if (SUCCEEDED(hr))
{
// If the property in attribute name is the same as passed in, then get value
if ( bstrProperty == attributeName.m_str)
{
// Setup a BSTR to get element value
BSTR bstrTemp = SysAllocString(L"");
hr = pXMLElement->get_text(&bstrTemp);
// Copy BSTR to CComBSTR and free it
if (SUCCEEDED(hr)) hr = pVal.CopyTo(&bstrTemp);
SysFreeString(bstrTemp);
i = lLength;
}
} // end if attribute
} // end if node
} //end if pNode
} // end for
}
else
{
// element name doesn't exists
hr = E_FAIL;
}
return hr;
}
//-----------------------------------------------------------
// Method: GetInputAttr
// Author: Russ Gibfried
// Params: [in] pTopNode -- xml Node pointer
// AttributeName -- attribute name to look for
// elementName -- element name
// [out] pVal -- value of attribute
// Purpose: Select a tag based on its name (elementName) and
// Return the value of particular attribute in XML document
//-------------------------------------------------------------
HRESULT CIISSCO50::GetInputAttr(CComPtr<IXMLDOMNode> pTopNode, CComBSTR elementName, CComBSTR AttributeName, CComBSTR& pVal)
{
HRESULT hr = E_FAIL;
CComPtr<IXMLDOMNamedNodeMap> pAttributeMap;
CComPtr<IXMLDOMNode> pNode;
CComPtr<IXMLDOMNode> pXMLElement;
if ( pTopNode != NULL )
{
// if elementName = "", then at current node
if ( elementName.Length() == 0 )
{
pNode = pTopNode;
hr = S_OK;
}
else
{
// Get the node of the element we are looking for ie, "./Website"
hr = pTopNode->selectSingleNode(elementName,&pNode);
}
// Get the attribute value
if (SUCCEEDED(hr) && pNode != NULL)
{
//Get 'name' attribute of this nodes <Property name=''> tag
hr = pNode->get_attributes(&pAttributeMap);
if ( SUCCEEDED(hr))
{
// Return the attributes value
hr = pAttributeMap->getNamedItem(AttributeName,&pXMLElement);
if (SUCCEEDED(hr)) hr = pXMLElement->get_text(&pVal);
}
}
}
if ( FAILED(hr) ) hr = E_SCO_IIS_XML_ATTRIBUTE_MISSING;
return hr;
}
//-----------------------------------------------------------
// Method: GetInputParam
// Author: Russ Gibfried
// Params: [in] elementName -- element name to look for. ie IpAddress
// [out] pVal -- value of element ie. 10.2.1.10
// Purpose: Return value of particular element in XML document
// ex) <IpAddress>10.2.1.10</IpAddress>
//-------------------------------------------------------------
HRESULT CIISSCO50::GetInputParam(CComPtr<IXMLDOMNode> pNode,CComBSTR elementName,CComBSTR& pVal)
{
HRESULT hr = E_FAIL;
CComPtr<IXMLDOMNode> pXMLElement;
if ( pNode != NULL )
{
if (S_OK == (hr = pNode->selectSingleNode(elementName,&pXMLElement)))
{
pXMLElement->get_text(&pVal);
}
}
return hr;
}
//-----------------------------------------------------------
// Method: PutElement
// Author: Russ Gibfried
// Params: [in] pNode -- xml node pointer
// elementName -- element name to look for
// [in] newVal -- new value of element
// Purpose: Return HRESULT
//-------------------------------------------------------------
HRESULT CIISSCO50::PutElement(CComPtr<IXMLDOMNode> pNode, CComBSTR elementName, CComBSTR newVal)
{
HRESULT hr = S_OK;
CComPtr<IXMLDOMDocument> pDoc;
CComPtr<IXMLDOMNode> pNewNode;
CComPtr<IXMLDOMNode> pLastChild;
CComPtr<IXMLDOMNode> pTempNode;
if ( pNode != NULL )
{
// Find the Element 'elementName'
if (S_OK != (hr = pNode->selectSingleNode(elementName,&pNewNode)))
{
// Could not find element so create new node and add to DOM
hr = CoCreateInstance(
__uuidof(DOMDocument),
NULL,
CLSCTX_ALL,
__uuidof(IXMLDOMDocument),
(LPVOID*)&pDoc);
// Get the node name from the element path. ie, './WebSite/ConfigPath' yields 'ConfigPath'
int iCount = NumberOfDelims(elementName, L"/");
CComBSTR bstrElement;
if ( SUCCEEDED(hr)) hr = ParseBSTR(elementName, L"/", iCount, 99, bstrElement);
// Create the new node
VARIANT vtTemp;
vtTemp.vt = VT_I2;
vtTemp.iVal = NODE_ELEMENT;
if ( SUCCEEDED(hr)) hr = pDoc->createNode(vtTemp,bstrElement,NULL, &pNewNode);
// Insert text in new node
if ( SUCCEEDED(hr)) hr= pNewNode->put_text(newVal.m_str);
// Get the last child node
if ( SUCCEEDED(hr)) hr = pNode->get_lastChild(&pLastChild);
// Append our new node to the end of the last child node
if ( SUCCEEDED(hr)) hr = pLastChild->appendChild(pNewNode,&pTempNode);
// Debug code to verify node built correctly.
if ( SUCCEEDED(hr))
{
CComBSTR bstrDebug;
hr = pNode->get_xml(&bstrDebug);
ATLTRACE(_T("\t>>>PutElement: xml = : %ls\n"), bstrDebug.m_str);
}
}
else
{
hr = pNewNode->put_text(newVal.m_str);
}
}
return hr;
}
//-----------------------------------------------------------
// Method: AppendElement
// Author: Russ Gibfried
// Params: [in] pNode -- xml node pointer
// xmlString -- well formed XML fragment; ie <Property></Property>
// [out] pNewNode -- xml pointer to new node
// Purpose: Return HRESULT
// Appends a XML tag to the end of a given node.
//-------------------------------------------------------------
HRESULT CIISSCO50::AppendElement(CComPtr<IXMLDOMNode> pNode, CComBSTR xmlString,CComPtr<IXMLDOMNode>& pNewNode)
{
HRESULT hr = E_FAIL;
CComPtr<IXMLDOMDocument> pDoc;
CComPtr<IXMLDOMElement> pNewElement;
VARIANT_BOOL bSuccess = VARIANT_FALSE;
if ( pNode != NULL )
{
// Load string into XML Document
hr = CoCreateInstance(
__uuidof(DOMDocument),
NULL,
CLSCTX_ALL,
__uuidof(IXMLDOMDocument),
(LPVOID*)&pDoc);
if (SUCCEEDED(hr)) hr = pDoc->loadXML(xmlString, &bSuccess);
if ( SUCCEEDED(hr) && bSuccess != VARIANT_FALSE)
{
// Get the document element
hr = pDoc->get_documentElement(&pNewElement);
if ( SUCCEEDED(hr))
{
// append new element to XML node passed in
hr = pNode->appendChild(pNewElement,&pNewNode);
}
}
}
return hr;
}
//-----------------------------------------------------------
// Method: GetNodeLength
// Author: Russ Gibfried
// Params: [in] pNode -- pointer to xml node
// elementName -- element name to look for
// [out] iLength -- number of elements matching that name
// Purpose: Return HRESULT
//-------------------------------------------------------------
HRESULT CIISSCO50::GetNodeLength(CComPtr<IXMLDOMNode> pTopNode, CComBSTR elementName, long *lLength)
{
// initialize variables
HRESULT hr = S_OK;
CComPtr<IXMLDOMNodeList> pXMLNode;
long lTemp = 0;
lLength = &lTemp;
// Get a node list, ie, all <Property> tags
if (S_OK == (hr = pTopNode->selectNodes(elementName,&pXMLNode)))
{
pXMLNode->get_length(lLength);
}
return hr;
}
//-----------------------------------------------------------
// Method: IsPositiveInteger
// Author: Russ Gibfried
// Params: [in]
// bstrPort -- port number as a string
// [out] Boolean - True if the port is a positive integer
// Purpose: Function checks if the port or server number is a posivive integer
// and less than 20,000
//
//-------------------------------------------------------------
BOOL CIISSCO50::IsPositiveInteger(CComBSTR bstrPort)
{
BOOL bInteger = false;
long iPort = 0;
CComVariant var(bstrPort.m_str);
// We're
var.ChangeType(VT_I4);
iPort = var.lVal;
if ( iPort > 0 && iPort <= IIS_SERVER_MAX)
bInteger = true;
return bInteger;
}
//-----------------------------------------------------------
// Method: StringCompare
// Author: Russ Gibfried
// Params: [in] bString1 -- BSTR string1
// bString2 -- BSTR string2
//
// [out] Boolean - True/False if string1 and string2 equal
// Purpose: Compares to strings and returns 'true' if they are equal.
//-------------------------------------------------------------
BOOL CIISSCO50::StringCompare(CComBSTR bstrString1, CComBSTR bstrString2)
{
// initialize variables
bool bEqual = false;
bEqual = (wcscmp(bstrString1.m_str, bstrString2.m_str) == 0) ? true : false;
return bEqual;
}