Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2039 lines
59 KiB

/*++
Copyright (c) 2001 Microsoft Corporation
Module Name :
webcomp.cxx
Abstract:
Class used to install the World Wide Web component
Author:
Christopher Achille (cachille)
Project:
Internet Services Setup
Revision History:
April 2002: Created
--*/
#include "stdafx.h"
#include "webcomp.hxx"
#include "acl.hxx"
#include "iadm.h"
#include "iiscnfgp.h"
#include "mdkey.h"
#include "mdentry.h"
#include "restrlst.hxx"
#include "svc.h"
#include "reg.hxx"
#include "ACShim.h"
#include "Setuser.h"
#include "lockdown.hxx"
#include "helper.h"
#include "Wtsapi32.h" // TS settings
#include "Mprapi.h" // RAS/VPN Settings
#include "lockdown.hxx"
#include <secconlib.h>
#include <shlwapi.h>
#include "inetinfo.h"
#include "resource.h"
// Undef this becase of collision with TSTR::PathAppend
#ifdef PathAppend
#undef PathAppend
#endif
// Local const definitions
//
LPCWSTR IIS_WPG_GROUPNAME = L"IIS_WPG";
LPCWSTR OLD_WAM_GROUPNAME = L"Web Applications";
const LPTSTR MofCompFiles[] =
{ { _T("asp.mof") },
{ _T("w3core.mof") },
{ _T("w3isapi.mof") },
{ NULL } };
sOurDefaultExtensions CWebServiceInstallComponent::m_aExternalExt[ CWebServiceInstallComponent::EXTENSIONS_EXTERNAL ] =
{
{ _T("idq.dll"),
_T("IndexingService"),
IDS_PRODUCT_INDEXSERVICE,
NULL, // No component name - we don't install this
FALSE, // UI deletable
FALSE, // Disabled
{ _T(".idq"),
_T(".ida"),
NULL
}
},
{ _T("webhits.dll"),
_T("IndexingService"),
IDS_PRODUCT_INDEXSERVICE,
NULL, // No component name - we don't install this
FALSE, // UI deletable
FALSE, // Disabled
{ _T(".htw"),
NULL
}
},
{ _T("msw3prt.dll"),
_T("W3PRT"),
IDS_PRODUCT_INETPRINT,
NULL, // No component name - we don't install this
FALSE, // UI deletable
FALSE, // Disabled
{ _T(".printer"),
NULL
}
}
};
// Constructor
//
CWebServiceInstallComponent::CWebServiceInstallComponent()
{
m_bMofCompRun = FALSE;
m_bWebDavIsDisabled = FALSE;
}
// GetName
//
// Return the name for the Web Service Component
//
LPTSTR
CWebServiceInstallComponent::GetName()
{
return _T("iis_www");
}
// GetFriendlyName
//
// Get the Friendly name for the UI
//
BOOL
CWebServiceInstallComponent::GetFriendlyName( TSTR *pstrFriendlyName )
{
return pstrFriendlyName->LoadString( IDS_DTC_WORLDWIDEWEB );
}
// SetWWWRootAclonDir
//
// Set the WWW Root Acl that we need. This will be used for WWWRoot
// and the customer error pages root
//
// The acl is the following:
// Upgrades - Add IIS_WPG:R
// Fresh Install - <Deny> IUSR_MACHINENAME:Write+Delete
// <Allow> Users:Read+Execute
// <Allow> IIS_WPG:Read+Execute
// <Allow> Administrators:Full
// <Allow> LocalSystem:Full
//
// Parameters:
// szPhysicalPath - The Physical Path to add the ACL
// bAddIusrDeny - Should we add the IUSR_ deny acl?
//
// Return:
// TRUE - Success
// FALSE - Failure
BOOL
CWebServiceInstallComponent::SetWWWRootAclonDir(LPTSTR szPhysicalPath,
BOOL bAddIusrDeny)
{
CSecurityDescriptor PathSD;
iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Calling SetWWWRootAclonDir\n")));
if ( IsUpgrade() )
{
// Upgrade
if ( !PathSD.GetSecurityInfoOnFile( szPhysicalPath ) )
{
// Failed to retrieve old SD
return FALSE;
}
}
else
{
// Fresh Install
if ( !PathSD.AddAccessAcebyWellKnownID( CSecurityDescriptor::GROUP_USERS,
CSecurityDescriptor::ACCESS_READ_EXECUTE,
TRUE,
TRUE ) ||
!PathSD.AddAccessAcebyWellKnownID( CSecurityDescriptor::GROUP_ADMINISTRATORS,
CSecurityDescriptor::ACCESS_FULL,
TRUE,
TRUE ) ||
!PathSD.AddAccessAcebyWellKnownID( CSecurityDescriptor::USER_LOCALSYSTEM,
CSecurityDescriptor::ACCESS_FULL,
TRUE,
TRUE )
)
{
// Failed ot create SD
return FALSE;
}
if ( bAddIusrDeny &&
!PathSD.AddAccessAcebyName( g_pTheApp->m_csGuestName.GetBuffer(0),
CSecurityDescriptor::ACCESS_WRITEONLY |
CSecurityDescriptor::ACCESS_DIR_DELETE,
FALSE,
TRUE ) )
{
// Failed to add IUSR_
return FALSE;
}
}
if ( !PathSD.AddAccessAcebyName( _T("IIS_WPG"),
CSecurityDescriptor::ACCESS_READ_EXECUTE,
TRUE,
TRUE ) )
{
// Failed to add IIS_WPG
return FALSE;
}
if ( !CreateDirectoryWithSA( szPhysicalPath, PathSD, FALSE ) )
{
// Failed to set ACL on file/dir
return FALSE;
}
return TRUE;
}
// SetPassportAcls
//
// Set the appropriate Passport Acl's
//
// Parameters
// bAdd - TRUE == Add Acl
// FALSE == Remove Acl
//
BOOL
CWebServiceInstallComponent::SetPassportAcls( BOOL bAdd )
{
BOOL bIsAclable;
TSTR_PATH strPassportDir;
CSecurityDescriptor sdPassport;
iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Calling SetPassportAcls\n")));
if ( !strPassportDir.RetrieveSystemDir() ||
!strPassportDir.PathAppend( PATH_PASSPORT )
)
{
// Could not create CustomError Path
return FALSE;
}
if ( !CSecurityDescriptor::DoesFileSystemSupportACLs(
strPassportDir.QueryStr(),
&bIsAclable ) )
{
return FALSE;
}
if ( !bIsAclable )
{
// Passport dir is not aclable, so lets exit
return TRUE;
}
// If directory does not exist, then create it
if ( !IsFileExist( strPassportDir.QueryStr() ) )
{
if ( !bAdd )
{
// Nothing to remove ACl From
return TRUE;
}
if ( !CreateDirectory( strPassportDir.QueryStr(), NULL ) )
{
// Failed to create passport dir
return FALSE;
}
}
if ( !sdPassport.GetSecurityInfoOnFile( strPassportDir.QueryStr() ) )
{
return FALSE;
}
if ( bAdd )
{
if ( !sdPassport.AddAccessAcebyName( _T("IIS_WPG"),
CSecurityDescriptor::ACCESS_READ_EXECUTE |
CSecurityDescriptor::ACCESS_WRITEONLY |
CSecurityDescriptor::ACCESS_DIR_DELETE,
TRUE,
TRUE )
)
{
return FALSE;
}
}
else
{
if ( !sdPassport.RemoveAccessAcebyName( _T("IIS_WPG") ) )
{
return FALSE;
}
}
if ( !sdPassport.SetSecurityInfoOnFile( strPassportDir.QueryStr(), FALSE ) )
{
// Failed to set ACL
return FALSE;
}
return TRUE;
}
// SetAdminScriptsAcl
//
// Set the ACL on the AdminScripts Directory
//
BOOL
CWebServiceInstallComponent::SetAdminScriptsAcl()
{
TSTR_PATH strAdminScripts;
CSecurityDescriptor AdminSD;
BOOL bDriveIsAclable;
iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Calling SetAdminScriptsAcl\n")));
if ( !strAdminScripts.Copy( g_pTheApp->m_csPathInetpub.GetBuffer(0) ) ||
!strAdminScripts.PathAppend( _T("AdminScripts") ) )
{
// Failed to construct Path
return FALSE;
}
if ( !CSecurityDescriptor::DoesFileSystemSupportACLs(
strAdminScripts.QueryStr(),
&bDriveIsAclable ) )
{
// Failed to check if ACL is valid for this filesystem
return FALSE;
}
if ( !bDriveIsAclable )
{
// This drive is not aclable, so skip it
return TRUE;
}
if ( !AdminSD.AddAccessAcebyWellKnownID( CSecurityDescriptor::GROUP_ADMINISTRATORS,
CSecurityDescriptor::ACCESS_FULL,
TRUE,
TRUE ) ||
!AdminSD.AddAccessAcebyWellKnownID( CSecurityDescriptor::USER_LOCALSYSTEM,
CSecurityDescriptor::ACCESS_FULL,
TRUE,
TRUE ) )
{
// Failed to create Admin SD
return FALSE;
}
if ( !AdminSD.SetSecurityInfoOnFiles( strAdminScripts.QueryStr(), FALSE ) )
{
// Failed to set ACL on this resource
return FALSE;
}
return TRUE;
}
// SetAppropriateFileAcls
//
// To tighten security, set some ACL's in strategic places
// where we install files.
//
// We set the following ACL's on the web root, and
// custom error root
// IUSR_MACHINE: Deny Write and Delete
// IIS_WPG: Allow Read
// Administrators: Allow Full
// Local System: Allow Full
// Users: Allow Read
//
BOOL
CWebServiceInstallComponent::SetAppropriateFileAcls()
{
iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Calling SetAppropriateFileAcls\n")));
return SetAppropriateFileAclsforDrive( _T('*') );
}
// SetAppropriateFileAclsforDrive
//
// Set the appropriate File Acl's, but only for the drive
// specified
//
// Parameters:
// cDriveLetter - The drive letter to be acl'd, send in '*'
// for all drives
//
BOOL
CWebServiceInstallComponent::SetAppropriateFileAclsforDrive( WCHAR cDriveLetter)
{
BOOL bWWWRootIsAclable;
BOOL bCustomErrorsAreAclable;
TSTR_PATH strCustomErrorPath;
iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Calling SetAppropriateFileAclsforDrive\n")));
if ( !strCustomErrorPath.RetrieveWindowsDir() ||
!strCustomErrorPath.PathAppend( PATH_WWW_CUSTOMERRORS )
)
{
// Could not create CustomError Path
return FALSE;
}
if ( !CSecurityDescriptor::DoesFileSystemSupportACLs(
g_pTheApp->m_csPathWWWRoot.GetBuffer(0),
&bWWWRootIsAclable ) ||
!CSecurityDescriptor::DoesFileSystemSupportACLs(
strCustomErrorPath.QueryStr(),
&bCustomErrorsAreAclable ) )
{
// Could not check FS if they were aclable
return FALSE;
}
// Acl everything needed for systemdrive
if ( ( cDriveLetter == _T('*') ) ||
( tolower( cDriveLetter ) == tolower( *( strCustomErrorPath.QueryStr() ) ) ) )
{
if ( bCustomErrorsAreAclable &&
!SetWWWRootAclonDir( strCustomErrorPath.QueryStr(), FALSE ) )
{
// Failed to set ACL
return FALSE;
}
if ( !SetPassportAcls( TRUE ) )
{
// Failed to set ACL
return FALSE;
}
if ( !SetIISTemporaryDirAcls( TRUE ) )
{
// Failed to set Acl on IIS Temporary Dirs
return FALSE;
}
if ( !SetAdminScriptsAcl() )
{
// Failed to set ACL for AdminScripts directory
return FALSE;
}
}
// Acl everything in inetpub
if ( ( cDriveLetter == _T('*') ) ||
( tolower( cDriveLetter ) == tolower( *( g_pTheApp->m_csPathWWWRoot.GetBuffer(0) ) ) ) )
{
if ( bWWWRootIsAclable &&
!SetWWWRootAclonDir( g_pTheApp->m_csPathWWWRoot.GetBuffer(0), TRUE ) )
{
// Failed to set ACL
return FALSE;
}
}
return TRUE;
}
// SetIISTemporaryDirAcls
//
// Set the ACL's on the IIS Temporary dirs
//
BOOL
CWebServiceInstallComponent::SetIISTemporaryDirAcls( BOOL bAdd )
{
BOOL bIsAclable;
TSTR_PATH strCompressionDir;
CSecurityDescriptor sdCompression;
iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Calling SetIISTemporaryDirAcls\n")));
if ( !strCompressionDir.RetrieveWindowsDir() ||
!strCompressionDir.PathAppend( PATH_TEMPORARY_COMPRESSION_FILES )
)
{
// Could not create CustomError Path
return FALSE;
}
if ( !CSecurityDescriptor::DoesFileSystemSupportACLs(
strCompressionDir.QueryStr(),
&bIsAclable ) )
{
return FALSE;
}
if ( !bIsAclable )
{
// Passport dir is not aclable, so lets exit
return TRUE;
}
// If directory does not exist, then create it
if ( !IsFileExist( strCompressionDir.QueryStr() ) )
{
if ( !bAdd )
{
// Nothing to remove ACl From
return TRUE;
}
if ( !CreateDirectory( strCompressionDir.QueryStr(), NULL ) )
{
// Failed to create passport dir
return FALSE;
}
}
if ( !sdCompression.GetSecurityInfoOnFile( strCompressionDir.QueryStr() ) )
{
return FALSE;
}
if ( bAdd )
{
if ( !sdCompression.AddAccessAcebyName( _T("IIS_WPG"),
CSecurityDescriptor::ACCESS_FULL,
TRUE,
TRUE )
)
{
return FALSE;
}
}
else
{
if ( !sdCompression.RemoveAccessAcebyName( _T("IIS_WPG") ) )
{
return FALSE;
}
}
if ( !sdCompression.SetSecurityInfoOnFile( strCompressionDir.QueryStr(), FALSE ) )
{
// Failed to set ACL
return FALSE;
}
return TRUE;
}
// SetAspTemporaryDirAcl
//
// Set the ACL's on the ASP Temporary dirs
//
BOOL
CWebServiceInstallComponent::SetAspTemporaryDirAcl( BOOL bAdd )
{
BOOL bIsAclable;
TSTR_PATH strASPDir;
CSecurityDescriptor sdASP;
iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Calling SetAspTemporaryDirAcl\n")));
if ( !strASPDir.RetrieveSystemDir() ||
!strASPDir.PathAppend( PATH_TEMPORARY_ASP_FILES )
)
{
// Could not create CustomError Path
return FALSE;
}
if ( !CSecurityDescriptor::DoesFileSystemSupportACLs(
strASPDir.QueryStr(),
&bIsAclable ) )
{
return FALSE;
}
if ( !bIsAclable )
{
// Passport dir is not aclable, so lets exit
return TRUE;
}
// If directory does not exist, then create it
if ( !IsFileExist( strASPDir.QueryStr() ) )
{
if ( !bAdd )
{
// Nothing to remove ACL From
return TRUE;
}
if ( !CreateDirectory( strASPDir.QueryStr(), NULL ) )
{
// Failed to create ASP Temporary Dir
return FALSE;
}
}
if ( bAdd )
{
if ( !sdASP.AddAccessAcebyName( _T("IIS_WPG"),
CSecurityDescriptor::ACCESS_FULL,
TRUE,
TRUE ) ||
!sdASP.AddAccessAcebyWellKnownID( CSecurityDescriptor::GROUP_ADMINISTRATORS,
CSecurityDescriptor::ACCESS_FULL,
TRUE,
TRUE ) ||
!sdASP.AddAccessAcebyWellKnownID( CSecurityDescriptor::USER_LOCALSYSTEM,
CSecurityDescriptor::ACCESS_FULL,
TRUE,
TRUE )
)
{
// Could not create appropriate ACL
return FALSE;
}
}
else
{
if ( !sdASP.GetSecurityInfoOnFile( strASPDir.QueryStr() ) ||
!sdASP.RemoveAccessAcebyName( _T("IIS_WPG") ) )
{
return FALSE;
}
}
if ( !sdASP.SetSecurityInfoOnFile( strASPDir.QueryStr(), FALSE ) )
{
// Failed to set ACL
return FALSE;
}
return TRUE;
}
// RemoveOurAcls
//
// Remove IIS's Acls from a resource. This is so that when
// we delete the accounts, the bad sid's are not left around
//
BOOL
CWebServiceInstallComponent::RemoveOurAcls( LPTSTR szPhysicalPath)
{
BOOL bIsAclable;
CSecurityDescriptor sd;
iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Calling RemoveOurAcls\n")));
if ( !CSecurityDescriptor::DoesFileSystemSupportACLs(
szPhysicalPath,
&bIsAclable ) )
{
// Failed to check if it was aclable
return FALSE;
}
if ( !bIsAclable )
{
// No acling was needed
return TRUE;
}
if ( !sd.GetSecurityInfoOnFile( szPhysicalPath ) ||
!sd.RemoveAccessAcebyName( g_pTheApp->m_csGuestName.GetBuffer(0), TRUE ) ||
!sd.RemoveAccessAcebyName( _T("IIS_WPG"), TRUE ) ||
!sd.SetSecurityInfoOnFile( szPhysicalPath, FALSE ) )
{
// Failed to remove our acl's
return FALSE;
}
return TRUE;
}
// RemoveAppropriateFileAcls
//
// During install, we explicity set the ACLs for a couple of locations,
// including the \inetpub\wwwroot and the custom errors pages. For uninstall
// we will not remove all the ACL's, since someone might still have
// valuable information in those directories. What we will do, is we will
// remove the ACL's that will not mean anything after we are uninstalled. Like
// the IUSR_ and IIS_WPG since. Since those users are being removed later in setup,
// we must delete the ACL's now.
//
BOOL
CWebServiceInstallComponent::RemoveAppropriateFileAcls()
{
TSTR strCustomErrorPath;
BOOL bRet = TRUE;
iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Calling RemoveAppropriateFileAcls\n")));
if ( !strCustomErrorPath.Copy( g_pTheApp->m_csWinDir ) ||
!strCustomErrorPath.Append( PATH_WWW_CUSTOMERRORS )
)
{
// Could not create CustomError Path
return FALSE;
}
if ( !RemoveOurAcls( g_pTheApp->m_csPathWWWRoot.GetBuffer(0) ) )
{
bRet = FALSE;
}
if ( !RemoveOurAcls( strCustomErrorPath.QueryStr() ) )
{
bRet = FALSE;
}
if ( !SetPassportAcls( FALSE ) )
{
// Failed to set ACL
bRet = FALSE;
}
if ( !SetIISTemporaryDirAcls( FALSE ) )
{
// Failed to set Acl on IIS Temporary Dirs
bRet = FALSE;
}
if ( !SetAspTemporaryDirAcl( FALSE ) )
{
// Failed to remove acl for ASP Temp Dir
bRet = FALSE;
}
return bRet;
}
// SetApplicationDependencies
//
// Set the Application Dependencies as they are defined in the
// unattend file. We take the dependencies from the inf, and
// put them in the metabase
//
BOOL
CWebServiceInstallComponent::SetApplicationDependencies()
{
CApplicationDependencies AppDep;
iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Calling SetApplicationDependencies\n")));
// Load current settings
if ( !AppDep.InitMetabase() ||
!AppDep.LoadCurrentSettings() )
{
return FALSE;
}
// Load Unattend Values
if ( AppDep.DoUnattendSettingsExist() )
{
if ( !AppDep.AddUnattendSettings() )
{
// Failed to add unattend settings
return FALSE;
}
}
if ( !AppDep.AddDefaults() )
{
// Failed to add defaults
return FALSE;
}
return AppDep.SaveSettings();
}
// SetRestrictionList
//
// Set the restriction list for the extensions and CGIs.
//
// This will:
// - Load current RestrictionList
// - Incorporate old values (IsapiRestrictionList and CgiRestrictionList)
// - Load unattend values
// - Add defaults
// - Save them to metabase
//
// Return Values:
// TRUE - Successfully loaded and written
// FALSE - Failure
//
BOOL
CWebServiceInstallComponent::SetRestrictionList()
{
CRestrictionList RestList;
iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Calling SetRestrictionList\n")));
// Load current Value
if ( !RestList.InitMetabase() ||
!RestList.LoadCurrentSettings() )
{
// Failed to load current value
return FALSE;
}
if ( RestList.IsEmpty() &&
IsUpgrade() &&
( GetUpgradeVersion() == 6 )
)
{
// This is an IIS6 upgrade, so lets try to load the old format
// Isapi and Cgi Restriction Lists
if ( !RestList.ImportOldLists( m_mstrOldCgiRestList,
m_mstrOldIsapiRestList ) )
{
return FALSE;
}
}
// Now lets load values in unattend, if they exist
if ( !RestList.AddUnattendSettings() )
{
return FALSE;
}
// Last, lets put in the default values if they are not already
// present
if ( !RestList.AddDefaults( IsUpgrade() ? TRUE : FALSE ) )
{
return FALSE;
}
// Everything is done, so lets save our new values
return RestList.SaveSettings();
}
// LogWarningonFAT
//
// On Fat systems, just log a warning saying that we are installing on FAT,
// and that is not secure
//
BOOL
CWebServiceInstallComponent::LogWarningonFAT()
{
BOOL bSystemPreservesAcls;
iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Calling LogWarningonFAT\n")));
if ( !DoesTheInstallDrivePreserveAcls( &bSystemPreservesAcls ) )
{
return FALSE;
}
if ( !bSystemPreservesAcls )
{
iisDebugOut((LOG_TYPE_WARN,
_T("IIS is being installed on a fat volume. This will disable IIS security features. Please consider converting the partition from FAT to NTFS.\n") ) );
}
return TRUE;
}
// DisableW3SVCOnUpgrade
//
// Disable W3SVC on Upgrades
// This is determined by checking the registry entry that is set by
// the compatability wizard that runs on the Win2k side of the
// upgrade, and also affected by the unattend setting
//
// Return Values:
// TRUE - Success
// FALSE - Failure
//
BOOL
CWebServiceInstallComponent::DisableW3SVCOnUpgrade()
{
BOOL bDisable = TRUE;
BOOL bRet = TRUE;
CRegValue Value;
CRegistry Registry;
TSTR strUnattendValue( MAX_PATH );
iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Calling DisableW3SVCOnUpgrade\n")));
if ( !Registry.OpenRegistry( HKEY_LOCAL_MACHINE, REG_INETSTP, KEY_READ | KEY_WRITE ) )
{
// Failed to open our node in registry
return FALSE;
}
// Check registry entry
if ( Registry.ReadValue( REGISTR_IISSETUP_DISABLEW3SVC, Value ) )
{
if ( Value.m_dwType == REG_DWORD )
{
// Set Disable to on or off
bDisable = *( (LPDWORD) Value.m_buffData.QueryPtr() ) != 0;
}
// Delete the value, since it is no longer needed
Registry.DeleteValue( REGISTR_IISSETUP_DISABLEW3SVC );
}
if ( ( g_pTheApp->m_hUnattendFile != NULL ) &&
( g_pTheApp->m_hUnattendFile != INVALID_HANDLE_VALUE) &&
SetupGetLineText( NULL,
g_pTheApp->m_hUnattendFile,
UNATTEND_FILE_SECTION,
UNATTEND_INETSERVER_DISABLEW3SVC,
strUnattendValue.QueryStr(),
strUnattendValue.QuerySize(),
NULL ) )
{
// Retrieved line from unattend, so lets compare
if ( strUnattendValue.IsEqual( _T("true"), FALSE ) )
{
bDisable = TRUE;
}
else if ( strUnattendValue.IsEqual( _T("false"), FALSE ) )
{
bDisable = FALSE;
}
else
{
iisDebugOut((LOG_TYPE_ERROR,
_T("Unattend setting incorrect '%s=%s'\n"),
UNATTEND_INETSERVER_DISABLEW3SVC,
strUnattendValue.QueryStr() ) );
}
}
if ( bDisable )
{
// Disable the W3SVC Service
if ( InetDisableService( _T("W3SVC") ) != 0 )
{
iisDebugOut((LOG_TYPE_ERROR,
_T("Failed to disable W3SVC\n") ) );
bRet = FALSE;
}
g_pTheApp->dwUnattendConfig |= USER_SPECIFIED_INFO_MANUAL_START_WWW;
}
return bRet;
}
// DisableIUSRandIWAMLogons
//
// Disable Terminal Server Logons and RAS VPN Logons
// for both IUSR and IWAM accounts
//
// Return
// TRUE - Successfully changed
// FALSE - Not successfully changed
//
BOOL
CWebServiceInstallComponent::DisableIUSRandIWAMLogons()
{
DWORD dwAllowTSLogin = FALSE;
RAS_USER_1 RasInfo;
iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Calling DisableIUSRandIWAMLogons\n")));
RasInfo.bfPrivilege = RASPRIV_NoCallback | RASPRIV_CallbackType; // No callback
RasInfo.bfPrivilege = 0; // Do not allow dialin
_tcscpy( RasInfo.wszPhoneNumber, _T("") );
// Disable RAS/VPN access for our users
if ( MprAdminUserSetInfo( NULL, // Server
g_pTheApp->m_csWWWAnonyName.GetBuffer(0),
1, // RAS_USER_0
(LPBYTE) &RasInfo ) != NO_ERROR )
{
return FALSE;
}
if ( MprAdminUserSetInfo( NULL, // Server
g_pTheApp->m_csWAMAccountName.GetBuffer(0),
1, // RAS_USER_0
(LPBYTE) &RasInfo ) != NO_ERROR )
{
return FALSE;
}
// Disable TS access for our users
// IUSR_ account
if ( !WTSSetUserConfig( WTS_CURRENT_SERVER_NAME,
g_pTheApp->m_csWWWAnonyName.GetBuffer(0),
WTSUserConfigfAllowLogonTerminalServer,
(LPTSTR) &dwAllowTSLogin,
sizeof(DWORD) ) )
{
return FALSE;
}
// IWAM_ account
if ( !WTSSetUserConfig( WTS_CURRENT_SERVER_NAME,
g_pTheApp->m_csWAMAccountName.GetBuffer(0),
WTSUserConfigfAllowLogonTerminalServer,
(LPTSTR) &dwAllowTSLogin,
sizeof(DWORD) ) )
{
return FALSE;
}
return TRUE;
}
// RunMofCompOnIISFiles
//
// Run MofComp on the IIS mofcomp files
//
BOOL
CWebServiceInstallComponent::RunMofCompOnIISFiles()
{
HRESULT hRes;
TSTR_PATH strMofPath;
DWORD dwCurrent;
BOOL bRet = TRUE;
iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Calling RunMofCompOnIISFiles\n")));
if ( m_bMofCompRun )
{
// We have already done this
return TRUE;
}
for ( dwCurrent = 0;
MofCompFiles[ dwCurrent ] != NULL;
dwCurrent++ )
{
if ( !strMofPath.Copy( g_pTheApp->m_csPathInetsrv.GetBuffer(0) ) ||
!strMofPath.PathAppend( MofCompFiles[ dwCurrent ] ) )
{
// Fatal Error
iisDebugOut((LOG_TYPE_ERROR,
_T("RunMofCompOnIISFiles: Failed to construct path for '%s'\n"),
MofCompFiles[ dwCurrent ] ) );
return FALSE;
}
hRes = MofCompile( strMofPath.QueryStr() );
if ( FAILED( hRes ) )
{
iisDebugOut((LOG_TYPE_ERROR,
_T("RunMofCompOnIISFiles: Failed to mofcomp on file '%s', hRes=0x%8x\n"),
strMofPath.QueryStr(),
hRes ) );
bRet = FALSE;
}
}
if ( bRet )
{
m_bMofCompRun = TRUE;
}
return bRet;
}
// CheckIfWebDavIsDisabled
//
// Check if WebDav is disabled via the IIS Lockdown tool for
// IIS 4, 5, and 5.1
//
BOOL
CWebServiceInstallComponent::CheckIfWebDavIsDisabled()
{
BOOL bIsAclDisabled;
BOOL bIsRegistryDisabled = FALSE;
CRegValue Value;
CRegistry Registry;
iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Calling CheckIfWebDavIsDisabled\n")));
if ( !IsUpgrade() ||
( GetUpgradeVersion() <= 3 ) ||
( GetUpgradeVersion() >= 6 ) )
{
// Since we either not upgrading, or the version is not between
// 4 and 5.1, lets not do the test
return TRUE;
}
if ( !IsWebDavDisabled( &bIsAclDisabled ) ||
!IsWebDavDisabledViaRegistry( &bIsRegistryDisabled ) )
{
// Failed during check
return FALSE;
}
m_bWebDavIsDisabled = bIsAclDisabled || bIsRegistryDisabled;
return TRUE;
}
// DisabledWebDavOnUpgrade
//
// If Web DAV was disabled before the upgrade via acl's, then lets
// put that in the restriction list now
//
BOOL
CWebServiceInstallComponent::DisabledWebDavOnUpgrade()
{
iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Calling DisabledWebDavOnUpgrade\n")));
if ( !m_bWebDavIsDisabled )
{
// Nothing needed to be done
return TRUE;
}
return DisableWebDavInRestrictionList();
}
// SetServiceToManualIfNeeded
//
// Set the service to manual if specified in unattend file
//
BOOL
CWebServiceInstallComponent::SetServiceToManualIfNeeded()
{
iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Calling SetServiceToManualIfNeeded\n")));
if ( g_pTheApp->dwUnattendConfig & USER_SPECIFIED_INFO_MANUAL_START_WWW )
{
SetServiceStart( _T("W3SVC"), SERVICE_DEMAND_START );
}
return TRUE;
}
// PreInstall
//
// Do all of the work that needs to be done before we do
// all the heavy install work
//
BOOL
CWebServiceInstallComponent::PreInstall()
{
BOOL bRet = TRUE;
iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Calling PreInstall\n")));
// Rename the "Web Applications" group to IIS_WPG. This group is created by IIS Lockdown tool
if ( bRet && IsUpgrade() && ( GetUpgradeVersion() >= 4 ) )
{
if ( LocalGroupExists( OLD_WAM_GROUPNAME ) )
{
if ( !LocalGroupExists( IIS_WPG_GROUPNAME ) )
{
LOCALGROUP_INFO_0 Info = { const_cast<LPWSTR>( IIS_WPG_GROUPNAME ) };
if ( ::NetLocalGroupSetInfo( NULL, OLD_WAM_GROUPNAME, 0, (BYTE*)&Info, NULL ) != NERR_Success )
{
iisDebugOut((LOG_TYPE_ERROR, _T("Failed to rename '%s' group to '%s'!\n"), OLD_WAM_GROUPNAME, IIS_WPG_GROUPNAME ));
bRet = FALSE;
}
}
else
{
// IIS_WPG NT group should not exist at this point. If it does - move the code that creates it
// later or do no create it if the 'Web Applications' group exist
_ASSERT( false );
iisDebugOut((LOG_TYPE_ERROR, _T("IIS_WPG group exists. Cannot rename 'Web Applications'!\n"), OLD_WAM_GROUPNAME, IIS_WPG_GROUPNAME ));
}
}
}
bRet = bRet && CheckIfWebDavIsDisabled();
if ( bRet && IsUpgrade() )
{
if ( GetUpgradeVersion() == 6 )
{
// If it is an IIS6 upgrade, then we should load the old Cgi and Isapi Restriction
// Lists, because the metabase no longer know anything about them
bRet = bRet && CRestrictionList::LoadOldFormatSettings( &m_mstrOldCgiRestList,
&m_mstrOldIsapiRestList );
}
}
return bRet;
}
// Install
//
// Do all of the main work need for install
//
BOOL
CWebServiceInstallComponent::Install()
{
BOOL bRet = TRUE;
iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Executing Install of WWW Component...\n")));
bRet = bRet && SetVersionInMetabase();
bRet = bRet && SetAppropriateFileAcls();
/*bRet = bRet &&*/ DisableIUSRandIWAMLogons();
// Load the Restriction List and Application Dependencies
bRet = bRet && DisabledWebDavOnUpgrade();
bRet = bRet && SetRestrictionList();
bRet = bRet && SetApplicationDependencies();
bRet = bRet && SetServiceToManualIfNeeded();
bRet = bRet && AddInheritFlagToSSLUseDSMap();
bRet = bRet && SetRegEntries( TRUE );
bRet = bRet && UpdateSiteFiltersAcl(); // Set /w3svc/X/filters acl
if ( IsUpgrade() )
{
//Do work for upgrades
bRet = bRet && ProcessIISShims(); // Import IIS Shims from the AppCompat sys DB
bRet = bRet && UpgradeRestrictedExtensions(); // Upgrade restricted ( 404.dall mapped ) extension to WebSvcExtRestrictionList
if ( ( GetUpgradeVersion() >= 4 ) &&
( GetUpgradeVersion() < 6 ) )
{
bRet = bRet && UpgradeWAMUsers();
}
if ( GetUpgradeVersion() == 5 )
{
// Do work for Win2k Upgrades
bRet = bRet && DisableW3SVCOnUpgrade();
}
if ( ( GetUpgradeVersion() >= 4 ) &&
( GetUpgradeVersion() <= 5 ) )
{
// Remove IIS Help Vdir
bRet = bRet && RemoveHelpVdironUpgrade();
}
}
if ( !g_pTheApp->m_fNTGuiMode )
{
// Do non GUI stuff
bRet = bRet && RunMofCompOnIISFiles(); // If in GUI, must do at OC_CLEANUP
}
bRet = bRet && LogWarningonFAT();
return bRet;
}
// Post install
//
BOOL
CWebServiceInstallComponent::PostInstall()
{
BOOL bRet = TRUE;
iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Executing PostInstall for the WWW component...\n")));
// Run MofComp if not already run
bRet = bRet && RunMofCompOnIISFiles();
bRet = bRet && InitialMetabaseBackUp( TRUE ); // Backup Metabase
// Start the service
if ( !g_pTheApp->m_fNTGuiMode &&
( g_pTheApp->dwUnattendConfig & USER_SPECIFIED_INFO_MANUAL_START_WWW ) == 0 )
{
// If it is not GUI mode, then we will try an start the service.
// It's not fatal if we fail to start the service, but return result anyway
INT nRes = InetStartService( _T("W3SVC") );
bRet = ( (nRes == ERROR_SUCCESS) || (nRes == ERROR_SERVICE_ALREADY_RUNNING) );
}
return bRet;
}
// Uninstall
//
// Do all the main work to uninstall the component
//
BOOL
CWebServiceInstallComponent::UnInstall()
{
BOOL bRet = TRUE;
iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Executing UnInstall of WWW Component...\n")));
bRet = SetRegEntries( FALSE ) && bRet;
bRet = InitialMetabaseBackUp( FALSE ) && bRet;
return bRet;
}
// PreUninstall
//
// Do everything that needs to be done before uninstall
//
BOOL
CWebServiceInstallComponent::PreUnInstall()
{
BOOL bRet = TRUE;
iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Executing PreUnInstall of WWW Component...\n")));
bRet = bRet && RemoveAppropriateFileAcls();
return bRet;
}
/*
Locates all MD_WAM_USER_NAME values in the metabse and inserts each value ( the value is NT username )
in the IIS_WPG NT Group
*/
BOOL CWebServiceInstallComponent::UpgradeWAMUsers()
{
iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Upgrading WAM users...\n")));
// We support only UNICODE now. This functions is designed for UNICODE only!
#if !( defined(UNICODE) || defined(_UNICODE) )
#error UNICODE build required
#endif
// Find all nodes that have MD_WAM_USER_NAME explicitly set
CMDKey MBKey;
CStringList listPaths;
if ( FAILED( MBKey.OpenNode( METABASEPATH_WWW_ROOT ) ) )
{
iisDebugOut((LOG_TYPE_ERROR, _T("Failed open LM/W3SVC node\n") ));
return FALSE;
}
if ( FAILED( MBKey.GetDataPaths( MD_WAM_USER_NAME, STRING_METADATA, /*r*/listPaths ) ) )
{
iisDebugOut((LOG_TYPE_ERROR, _T("Failed to get data paths from LM/W3SVC node\n") ));
return FALSE;
}
// Get each value
POSITION pos = listPaths.GetHeadPosition();
BOOL bRet = TRUE;
while( pos != NULL )
{
CString strPath = listPaths.GetNext( pos );
CMDValue UserName;
BOOL bResult = MBKey.GetData( /*r*/UserName, MD_WAM_USER_NAME, strPath.GetBuffer( 0 ) );
if ( bResult )
{
NET_API_STATUS nRes = RegisterAccountToLocalGroup( reinterpret_cast<LPCWSTR>( UserName.GetData() ),
IIS_WPG_GROUPNAME,
TRUE );
bResult = ( ( nRes == NERR_Success ) || ( nRes == ERROR_MEMBER_IN_ALIAS ) );
}
if ( !bResult )
{
// Log error but try to import the other usernames
iisDebugOut((LOG_TYPE_ERROR, _T("Failed to transfer a WAM user from MB to IIS_WPG. Will try with next one...\n") ));
bRet = FALSE;
}
};
return bRet;
}
/*
Get all script maps ( on each level bellow LM/W3SVC )
For each script mapping - if there is a disabled extension - restore the mapping to the original one
and create a disabled entry for this extension in the WebSvcExtRestrictionList
*/
BOOL CWebServiceInstallComponent::UpgradeRestrictedExtensions()
{
typedef std::map<std::wstring, DWORD> TExtMap;
typedef std::list<std::pair<std::wstring, std::wstring> > TStrStrList;
// This shows whether a particular ext group ( an elem of TExtToCheck ) should be upgraded
enum GroupState
{
esUnknown, // Don't know if the element should be upgraded, so it woun't be
esUpgrade, // Upgrade it ( move it to WebSvcExtRestrictionList
esDontUpgrade // No thanks
};
// This is the array that flags which extensions should be moved to WebSvcExtRe...
GroupState anUpgradeExt[ TExtToCheck::ARRAY_SIZE ];
// Create a map for the file extension that we need to check
// The map is Extension->ExtnesionIndex
// Where Extension is the filename extension ( ".asp" )
// And ExtensionIndex is the array index in TExtToCheck and abUpgradeExt
TExtMap mapExt;
// This list holds a pair of strings. The first one is the full MB key where a script map is located
// The second script is extension name ( ".asp" )
// At one point of time we will change the mapping of this extension to be the default filename
TStrStrList listKeysToUpdate;
// Create the map with the extensions
// By default no extensions will be upgraded ( which means - added as disabled in WebSvcExtRestrictionList )
for ( DWORD iExtInfo = 0; iExtInfo < TExtToCheck::ARRAY_SIZE; ++iExtInfo )
{
anUpgradeExt[ iExtInfo ] = esUnknown;
// Enter the extensions in the map
for ( DWORD iExt = 0; iExt < sOurDefaultExtensions::MaxFileExtCount; ++iExt )
{
if ( TExtToCheck::Element( iExtInfo ).szExtensions[ iExt ] != NULL )
{
// Put this extension in the map
TExtMap::value_type New( std::wstring( TExtToCheck::Element( iExtInfo ).szExtensions[ iExt ] ), iExtInfo );
mapExt.insert( New );
}
}
}
// Get all paths at which the script mappings are set
CStringList listPaths;
CMDKey mdKey;
if ( FAILED( mdKey.OpenNode( METABASEPATH_WWW_ROOT ) ) ) return FALSE;
if ( FAILED( mdKey.GetDataPaths( MD_SCRIPT_MAPS, MULTISZ_METADATA, /*r*/listPaths ) ) ) return FALSE;
POSITION pos = listPaths.GetHeadPosition();
// For each script map - check if every mapping in the map is mapped to 404.dll
// and if so - whether this is an IIS extension
while( pos != NULL )
{
const CString strSubPath = listPaths.GetNext( /*r*/pos );
DWORD dwType = 0;
DWORD dwAttribs = 0;
LPCWSTR wszSubKey = strSubPath;
CStringList listMappings;
// If we fail - exit. No need to continue with other paths because we
// need to be sure that no mapping exist to anything different then 404.dll
if ( FAILED( mdKey.GetMultiSzAsStringList( MD_SCRIPT_MAPS,
&dwType,
&dwAttribs,
/*r*/listMappings,
wszSubKey ) ) )
{
iisDebugOut((LOG_TYPE_ERROR, _T("Failed to get and parse ScriptMap value\n") ));
return FALSE;
}
// For each mapping in the script map - get what ext is mapped to what filename
// If it is one of our extensions ( the ones in the map ) - check the filename
// If the filename is not 404.dll - this extension will not be modified
POSITION posMapping = listMappings.GetHeadPosition();
while( posMapping != NULL )
{
WCHAR wszFilename[ MAX_PATH ];
CString strMapping = listMappings.GetNext( /*r*/posMapping );
LPCWSTR wszMapping = strMapping;
LPCWSTR wszFirstComma = ::wcschr( wszMapping, L',' ) + 1; // Will point at the first symb after the comma
if ( NULL == wszFirstComma )
{
iisDebugOut((LOG_TYPE_ERROR, _T("Invalid mapping: %s\n"),wszMapping ));
return FALSE;
}
LPCWSTR wszSecondComma = ::wcschr( wszFirstComma, L',' ); // Will point at the second comma
if ( NULL == wszSecondComma )
{
// Set to point at the end of the string
wszSecondComma = wszMapping + ::wcslen( wszMapping );
}
// Get the extension and the filename
::wcsncpy( wszFilename, wszFirstComma, min( wszSecondComma - wszFirstComma, MAX_PATH ) );
wszFilename[ min( wszSecondComma - wszFirstComma, MAX_PATH ) ] = L'\0';
std::wstring strExt( wszMapping, wszFirstComma - wszMapping - 1 ); // -1 to remove the comma as well
TExtMap::iterator it = mapExt.find( strExt );
// If this is not an IIS extension - skip it
if ( mapExt.end() == it ) continue;
// Strip the path to be the filename only
::PathStripPath( wszFilename );
if ( ::_wcsicmp( wszFilename, L"404.dll" ) != 0 )
{
// If this is not an 404.dll filename - this extension will not be upgraded
anUpgradeExt[ it->second ] = esDontUpgrade;
}
else
{
// This is an IIS ext mapped to 404.dll.
// If this group upgrade flag is not esDontUpgrade - then we will upgrade the group
if ( anUpgradeExt[ it->second ] != esDontUpgrade )
{
anUpgradeExt[ it->second ] = esUpgrade;
// We may need to upgrade this entry, so store it
std::wstring strKeyName( L"LM/W3SVC/" );
strKeyName += ( L'/' == wszSubKey[ 0 ] ) ? wszSubKey + 1 : wszSubKey;
listKeysToUpdate.push_back( TStrStrList::value_type( strKeyName, strExt ) );
}
}
};
};
// Close the MB key. It is important to close it here because we will write to LM/W3SVC node
// so we should not have open handles
mdKey.Close();
// Right here, in anUpgradeExt we have esUpgrade values for all WebSvcExtensions we need to upgrade
// In listKeysToUpdate we have all the keys that contains script maps that contain
// mappings that MAY need to be modified. So perform the upgrade now
// Modify the script mappings for file extensions that will be upgraded
for ( TStrStrList::iterator itMapping = listKeysToUpdate.begin();
itMapping != listKeysToUpdate.end();
++itMapping )
{
// Find which element in TExtToCheck array represents this extension
TExtMap::iterator itInfo = mapExt.find( itMapping->second.c_str() );
// For an extension to be in listKeysToUpdate, it should've existed in mapExt.
// So we will always find it
_ASSERT( itInfo != mapExt.end() );
// If we will upgrade this extension info - then we need to modify this value
if ( esUpgrade == anUpgradeExt[ itInfo->second ] )
{
// Don't fail on error - try to update as many mappings as possible
if ( !UpdateScriptMapping( itMapping->first.c_str(), itMapping->second.c_str(), itInfo->second ) )
{
iisDebugOut(( LOG_TYPE_ERROR,
_T("Failed to update script mapping. Ext='%s' at '%s'\n"),
itMapping->second.c_str(),
itMapping->first.c_str() ));
}
}
}
CSecConLib Helper;
TSTR_PATH strFullPath( MAX_PATH );
BOOL bRet = TRUE;
// Now we need to put an entry in WebSvcExtRestrictionList for all disabled ISAPI dlls
// The ones we need to process are the ones on abUpgradeExt for which the element is TRUE
for ( DWORD iExtInfo = 0; iExtInfo < TExtToCheck::ARRAY_SIZE; ++iExtInfo )
{
if ( esUpgrade == anUpgradeExt[ iExtInfo ] )
{
TSTR strDesc;
// Extensions from the first array go to InetSrv dir
// Extensions from the second array - System32
LPCWSTR wszDir = TExtToCheck::IsIndexInFirst( iExtInfo ) ?
g_pTheApp->m_csPathInetsrv.GetBuffer(0) :
g_pTheApp->m_csSysDir.GetBuffer(0);
if ( !strFullPath.Copy( wszDir ) ||
!strFullPath.PathAppend( TExtToCheck::Element( iExtInfo ).szFileName ) ||
!strDesc.LoadString( TExtToCheck::Element( iExtInfo ).dwProductName ) )
{
// Failed to create full path, so skip to next one
bRet = FALSE;
iisDebugOut((LOG_TYPE_ERROR, _T("Unable to build full path for WebSvc extension. Possible OutOfMem\n") ));
continue;
}
// Delete the extension first ( the SeccLib will fail to add an extension if it's alreafy there )
HRESULT hrDel = Helper.DeleteExtensionFileRecord( strFullPath.QueryStr(), METABASEPATH_WWW_ROOT );
if ( FAILED( hrDel ) && ( hrDel != MD_ERROR_DATA_NOT_FOUND ) )
{
iisDebugOut(( LOG_TYPE_WARN,
_T("Failed to delete extension file '%s' in order to change it's settings\n"),
strFullPath.QueryStr() ) );
bRet = FALSE;
continue;
}
if ( FAILED( Helper.AddExtensionFile( strFullPath.QueryStr(), // Path
false, // Image should be disabled
TExtToCheck::Element( iExtInfo ).szNotLocalizedGroupName, // GroupID
TExtToCheck::Element( iExtInfo ).bUIDeletable != FALSE, // UI deletable
strDesc.QueryStr(), // Group description
METABASEPATH_WWW_ROOT ) ) ) // MB location
{
iisDebugOut(( LOG_TYPE_WARN,
_T("Failed to add extension '%s' to group '%s'\n"),
strFullPath.QueryStr(),
TExtToCheck::Element( iExtInfo ).szNotLocalizedGroupName ));
bRet = FALSE;
continue;
}
}
}
return bRet;
}
/*
This function updates the script mapping value ( MD_SCRIPT_MAP ) under the
metabase key wszMBKey.
The file extension wszExt will be associated with the filename specified in TExtToCheck[ iExtInfo ]
*/
BOOL CWebServiceInstallComponent::UpdateScriptMapping( LPCWSTR wszMBKey, LPCWSTR wszExt, DWORD iExtInfo )
{
_ASSERT( wszMBKey != NULL );
_ASSERT( ::wcsstr( wszMBKey, L"LM/W3SVC" ) != NULL );
_ASSERT( wszExt != NULL );
_ASSERT( iExtInfo < TExtToCheck::ARRAY_SIZE );
CMDKey Key;
CStringList listMappings;
DWORD dwType = 0;
DWORD dwAttribs = 0;
if ( FAILED( Key.OpenNode( wszMBKey ) ) ) return FALSE;
if ( FAILED( Key.GetMultiSzAsStringList( MD_SCRIPT_MAPS, &dwType, &dwAttribs, /*r*/listMappings ) ) ) return FALSE;
// Find the string that is the extension we are looking for
POSITION pos = listMappings.GetHeadPosition();
while( pos != NULL )
{
CString strMapping = listMappings.GetAt( pos );
// The mapping must be large enough to consist of our ext, +2 symbols for the first and second commas
// and +1 for at least one symbol for filename
if ( static_cast<size_t>( strMapping.GetLength() ) <= ( ::wcslen( wszExt ) + 2 + 1 ) )
{
continue;
}
// Check if this is the exteniosn we are looking for
if ( ::_wcsnicmp( wszExt, strMapping, ::wcslen( wszExt ) ) == 0 )
{
// Create the full path to the ISAPI that this ext should be mapped to
TSTR_PATH strFullPath( MAX_PATH );
// There is a little trick here - extensions from the first array go to InetSrv dir
// Extensions from the second array - System32
LPCWSTR wszDir = TExtToCheck::IsIndexInFirst( iExtInfo ) ?
g_pTheApp->m_csPathInetsrv.GetBuffer(0) :
g_pTheApp->m_csSysDir.GetBuffer(0);
if ( !strFullPath.Copy( wszDir ) ||
!strFullPath.PathAppend( TExtToCheck::Element( iExtInfo ).szFileName ) )
{
iisDebugOut((LOG_TYPE_ERROR, _T("Unable to build full path for WebSvc extension. Possible OutOfMem\n") ));
return FALSE;
}
LPCWSTR wszMapping = strMapping;
LPCWSTR wszTheRest = ::wcschr( wszMapping + wcslen( wszExt ) + 1, L',' );
_ASSERT( wszTheRest != NULL );
// Our buffer will be the ext size, +1 comma, +Path, + the rest of it +1 for the '\0'
std::auto_ptr<WCHAR> spMapping( new WCHAR[ ::wcslen( wszExt ) + 1 + strFullPath.QueryLen() + ::wcslen( wszTheRest ) + 1 ] );
if ( NULL == spMapping.get() ) return FALSE;
::wcscpy( spMapping.get(), wszExt );
::wcscat( spMapping.get(), L"," );
::wcscat( spMapping.get(), strFullPath.QueryStr() );
::wcscat( spMapping.get(), wszTheRest );
listMappings.SetAt( pos, CString( spMapping.get() ) );
if ( FAILED( Key.SetMultiSzAsStringList( MD_SCRIPT_MAPS, dwType, dwAttribs, listMappings ) ) )
{
iisDebugOut(( LOG_TYPE_ERROR,
_T("Failed to modify extension mapping ( ISAPI dll name ) for ext '%s' in '%s'\n"),
wszExt,
wszMBKey ));
}
// Thats it
break;
}
listMappings.GetNext( /*r*/pos );
}
return TRUE;
}
// SetVersionInMetabase
//
// Set the version information in the metabase
//
// Return Values
// TRUE - Successfully Set
// FALSE - Failed to Set
//
BOOL
CWebServiceInstallComponent::SetVersionInMetabase()
{
CMDValue MajorVersion;
CMDValue MinorVersion;
CMDKey Metabase;
iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Calling SetVersionInMetabase\n")));
if ( !MajorVersion.SetValue( MD_SERVER_VERSION_MAJOR,
0,
DWORD_METADATA,
IIS_SERVER_VERSION_MAJOR ) ||
!MinorVersion.SetValue( MD_SERVER_VERSION_MINOR,
0,
DWORD_METADATA,
IIS_SERVER_VERSION_MINOR ) )
{
// Could not create properties
return FALSE;
}
if ( FAILED( Metabase.OpenNode( METABASEPATH_WWW_INFO ) ) ||
!Metabase.SetData( MajorVersion, MD_SERVER_VERSION_MAJOR ) ||
!Metabase.SetData( MinorVersion, MD_SERVER_VERSION_MINOR ) )
{
// Failed to set
return FALSE;
}
return TRUE;
}
// RemoveIISHelpVdir
//
// Remove an IISHelp Vdir, if it exists
//
// Parameters
// szMetabasePath - Metabase path of website
// szPhysicalPath1 - One of the physical path's it could point to, to be considered valid
// szPhysicalPath1 - The second possible physical path it could point to, to be considered valid
//
BOOL
CWebServiceInstallComponent::RemoveIISHelpVdir( LPCTSTR szMetabasePath, LPCTSTR szPhysicalPath1, LPCTSTR szPhysicalPath2 )
{
CMDKey cmdKey;
CMDValue cmdValue;
TSTR strFullPath;
iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Calling RemoveIISHelpVdir\n")));
if ( !strFullPath.Copy( szMetabasePath ) ||
!strFullPath.Append( _T("/") ) ||
!strFullPath.Append( METABASEPATH_UPG_IISHELP_NAME ) )
{
// Failed to construct Full Path
return FALSE;
}
if ( SUCCEEDED( cmdKey.OpenNode( strFullPath.QueryStr() ) ) &&
cmdKey.GetData( cmdValue, MD_VR_PATH ) &&
( cmdValue.GetDataType() == STRING_METADATA ) &&
( ( _tcsicmp( (LPTSTR) cmdValue.GetData(), szPhysicalPath1 ) == 0 ) ||
( _tcsicmp( (LPTSTR) cmdValue.GetData(), szPhysicalPath2 ) == 0 )
)
)
{
cmdKey.Close();
// This is the correct vdir, so lets delete it
if ( FAILED( cmdKey.OpenNode( szMetabasePath ) ) )
{
// Failed to open node
return FALSE;
}
if ( FAILED( cmdKey.DeleteNode( METABASEPATH_UPG_IISHELP_NAME ) ) )
{
// Failed to remove vdir
return FALSE;
}
}
return TRUE;
}
// RemoveHelpVdironUpgrade
//
// Remove the IIS Help vdir on upgrades
//
BOOL
CWebServiceInstallComponent::RemoveHelpVdironUpgrade()
{
TSTR_PATH strHelpLoc1;
TSTR_PATH strHelpLoc2;
TSTR_PATH strHelpDeleteLoc;
iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Calling RemoveHelpVdironUpgrade\n")));
if ( !strHelpLoc1.RetrieveWindowsDir() ||
!strHelpLoc1.PathAppend( PATH_UPG_IISHELP_1 ) ||
!strHelpLoc2.RetrieveWindowsDir() ||
!strHelpLoc2.PathAppend( PATH_UPG_IISHELP_2 ) ||
!strHelpDeleteLoc.RetrieveWindowsDir() ||
!strHelpDeleteLoc.PathAppend( PATH_IISHELP_DEL ) )
{
// Failed to create Path
return FALSE;
}
if ( !RemoveIISHelpVdir( METABASEPATH_UPG_IISHELP_WEB1_ROOT,
strHelpLoc1.QueryStr(),
strHelpLoc2.QueryStr() ) ||
!RemoveIISHelpVdir( METABASEPATH_UPG_IISHELP_WEB2_ROOT,
strHelpLoc1.QueryStr(),
strHelpLoc2.QueryStr() ) )
{
// Failed to remove VDir
return FALSE;
}
// Now delete directory
RecRemoveDir( strHelpDeleteLoc.QueryStr(), TRUE );
return TRUE;
}
// CreateInitialMetabaseBackUp
//
// Create an initial backup of the metabase at the end of
// the W3SVC Instalation
//
// Parameters:
// bAdd - TRUE == Add,
// FALSE == remove
//
BOOL
CWebServiceInstallComponent::InitialMetabaseBackUp( BOOL bAdd )
{
TSTR strBackupName;
if ( !strBackupName.LoadString( IDS_INITIAL_METABASE_BK_NAME ) )
{
// Failed to get metabase name
return FALSE;
}
if ( bAdd )
{
return CMDKey::Backup( strBackupName.QueryStr(), // Backup Name
1, // Version #
MD_BACKUP_OVERWRITE |
MD_BACKUP_SAVE_FIRST |
MD_BACKUP_FORCE_BACKUP ); // Overwrite if one already exists
}
return CMDKey::DeleteBackup( strBackupName.QueryStr(),
1 );
}
// CWebServiceInstallComponent::
//
// If during upgrade, this metabase setting is set, add the inherit flag to it
// The reason for this was because it was not set in Win2k days, and now
// we need it set
//
BOOL
CWebServiceInstallComponent::AddInheritFlagToSSLUseDSMap()
{
CMDKey cmdKey;
CMDValue cmdValue;
if ( FAILED( cmdKey.OpenNode( METABASEPATH_WWW_ROOT ) ) )
{
// Failed to open metabase
return FALSE;
}
if ( cmdKey.GetData( cmdValue, MD_SSL_USE_DS_MAPPER ) &&
( cmdValue.GetDataType() == DWORD_METADATA ) )
{
// If this value is present, then set with inheritance
cmdValue.SetAttributes( METADATA_INHERIT );
if ( !cmdKey.SetData( cmdValue, MD_SSL_USE_DS_MAPPER ) )
{
return FALSE;
}
}
return TRUE;
}
// SetRegEntries
//
// Set the appropriate registry entries
//
// Parameters:
// bAdd - [in] TRUE == Add; FALSE == Remove
//
BOOL
CWebServiceInstallComponent::SetRegEntries( BOOL bAdd )
{
CRegistry Registry;
if ( !Registry.OpenRegistry( HKEY_LOCAL_MACHINE,
REG_HTTPSYS_PARAM,
KEY_WRITE ) )
{
// Failed to open registry Key
return FALSE;
}
if ( bAdd )
{
CRegValue Value;
if ( !Value.SetDword( 1 ) ||
!Registry.SetValue( REG_HTTPSYS_DISABLESERVERHEADER, Value ) )
{
// Failed to set
return FALSE;
}
}
else
{
Registry.DeleteValue( REG_HTTPSYS_DISABLESERVERHEADER );
}
return TRUE;
}
// function: UpdateSiteFiltersAcl
//
// Update all the SiteFilter's Acl's with the new ACL
//
// Return Value:
// TRUE - Success change
// FALSE - Failure changing
BOOL
CWebServiceInstallComponent::UpdateSiteFiltersAcl()
{
CMDKey cmdKey;
CMDValue cmdValue;
CMDValue cmdIISFiltersValue;
WCHAR szSubNode[METADATA_MAX_NAME_LEN];
TSTR strFilterKey;
DWORD i = 0;
iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Calling UpdateSiteFiltersAcl\n")));
if ( !RetrieveFiltersAcl( &cmdValue ) )
{
// There is no acl to set, so lets exit
return TRUE;
}
if ( FAILED( cmdKey.OpenNode( METABASEPATH_WWW_ROOT ) ) ||
!cmdIISFiltersValue.SetValue( MD_KEY_TYPE, // ID
0, // Attributes
IIS_MD_UT_SERVER, // UserType
STRING_METADATA, // DataType
( _tcslen( KEYTYPE_FILTERS ) + 1 ) * sizeof(TCHAR),
KEYTYPE_FILTERS ) ) // Value
{
// Failed to open filters node
return FALSE;
}
while ( cmdKey.EnumKeys( szSubNode, i++ ) )
{
if ( !IsNumber( szSubNode ) )
{
// Since it is not a number, it is not a website, so lets skip
continue;
}
if ( !strFilterKey.Copy( szSubNode ) ||
!strFilterKey.Append( METABASEPATH_FILTER_PATH ) )
{
return FALSE;
}
// Add the filters node if not already there
cmdKey.AddNode( strFilterKey.QueryStr() );
if ( !cmdKey.SetData( cmdIISFiltersValue, MD_KEY_TYPE, strFilterKey.QueryStr() ) ||
!cmdKey.SetData( cmdValue, MD_ADMIN_ACL, strFilterKey.QueryStr() ) )
{
// Failed to set ACL
return FALSE;
}
}
return TRUE;
}
// function: RetrieveFiltersAcl
//
// Retrieve the Filters ACL to use
//
BOOL
CWebServiceInstallComponent::RetrieveFiltersAcl(CMDValue *pcmdValue)
{
CMDKey cmdKey;
if ( FAILED( cmdKey.OpenNode( METABASEPATH_FILTER_GLOBAL_ROOT ) ) )
{
// Failed to open filters node
return FALSE;
}
// Don't inherit acl, but do retrieve if it should be inheritted
pcmdValue->SetAttributes( METADATA_ISINHERITED );
if ( !cmdKey.GetData( *pcmdValue, MD_ADMIN_ACL ) )
{
// Failed to retrieve value
return FALSE;
}
return TRUE;
}
// function: IsNumber
//
// Determine if the string is a number
//
BOOL
CWebServiceInstallComponent::IsNumber( LPWSTR szString )
{
while ( *szString )
{
if ( ( *szString < '0' ) ||
( *szString > '9' ) )
{
return FALSE;
}
szString++;
}
return TRUE;
}