//*************************************************************** // 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 pNode; // xml node HRESULT hr = S_OK; // Get node in format: ... 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 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 /W3SVC/n 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 , 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 pNode; // xml node HRESULT hr = S_OK; // Get node in format: ... 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: ... //------------------------------------------------------------- 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 value: /W3SVC/3 CComBSTR bstrConfigPath; // Created sites ADsPath: /W3SVC/3 CComVariant xmlString; // Variant string returned by MAPS CComPtr pDoc; // xml document CComPtr pNodeList; // xml node list CComPtr pNode; // xml node HRESULT hr = S_OK; // Get RollBack data. Will bein form: ... 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 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 hr = pNodeList->nextNode(&pNode); // Get Server number from attribute map 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 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 , 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 pNode; // xml node // Get node in format: ... 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 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 , 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 pNode; // xml node HRESULT hr = S_OK; // Get node in format: ... 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 value: /MSFTPSVC/3 CComBSTR bstrConfigPath; // Created sites ADsPath: /MSFTPSVC/3 CComVariant xmlString; CComPtr pDoc; // xml document CComPtr pNodeList; // xml node list CComPtr pNode; // xml node HRESULT hr = S_OK; // Get RollBack data. Will bein form: ... 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 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 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 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 pNode; // xml node. will be HRESULT hr = S_OK; // Get node in format: ... 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 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 , 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: 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 pNode; // xml node 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 pDoc; // xml document CComPtr pNodeList; // xml node list CComPtr pNode; // xml node HRESULT hr = S_OK; // Get RollBack data. Will bein form: ... 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 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 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 pNode; CComBSTR propertyXML; // Get node in format: ... 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 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 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 pNode; // xml node // Get node in format: ... 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 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 pNode; CComPtr pConfigNode; CComPtr pTemp; CComBSTR xmlString; // Get node in format: ... 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 element and append to pNode xmlString = ""); 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: ItsValue xmlString = ""); xmlString.AppendBSTR((*it).second); xmlString.Append(L""); 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 already listed above. if ( iCount != 0 ) { xmlString = ""); 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 pNode; CComPtr pConfigNode; CComPtr 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: ... 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 = ""); 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: ItsValue xmlString = ""); xmlString.AppendBSTR((*it2).second); xmlString.Append(L""); 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 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 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 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 pADs; CComPtr 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 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 pADs; CComPtr 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,¶ms, 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 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,¶ms, 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 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 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 pADs; CComPtr pCls; CComBSTR bstrSchema; CComPtr 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 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 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 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 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 // someValue //------------------------------------------------------------- HRESULT CIISSCO50::GetElementValueByAttribute(CComPtr pTopNode,CComBSTR elementName, CComBSTR attributeName, CComBSTR& pVal) { HRESULT hr = S_OK; CComPtr pNodeList; // List of nodes matching elementName CComPtr pNode; // individual node CComPtr pAttributeMap; CComPtr pXMLElement; // Get a node list, ie, all 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 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 pTopNode, CComBSTR elementName, CComBSTR AttributeName, CComBSTR& pVal) { HRESULT hr = E_FAIL; CComPtr pAttributeMap; CComPtr pNode; CComPtr 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 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) 10.2.1.10 //------------------------------------------------------------- HRESULT CIISSCO50::GetInputParam(CComPtr pNode,CComBSTR elementName,CComBSTR& pVal) { HRESULT hr = E_FAIL; CComPtr 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 pNode, CComBSTR elementName, CComBSTR newVal) { HRESULT hr = S_OK; CComPtr pDoc; CComPtr pNewNode; CComPtr pLastChild; CComPtr 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 // [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 pNode, CComBSTR xmlString,CComPtr& pNewNode) { HRESULT hr = E_FAIL; CComPtr pDoc; CComPtr 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 pTopNode, CComBSTR elementName, long *lLength) { // initialize variables HRESULT hr = S_OK; CComPtr pXMLNode; long lTemp = 0; lLength = &lTemp; // Get a node list, ie, all 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; }