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.
692 lines
18 KiB
692 lines
18 KiB
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
w3ssl_config.cxx
|
|
|
|
Abstract:
|
|
|
|
IIS Services IISADMIN Extension
|
|
adjust HTTPFilter service imagepath based on IIS mode (old vs new)
|
|
|
|
Author:
|
|
|
|
Jaroslav Dunajsky (11/05/2001)
|
|
|
|
--*/
|
|
|
|
#include <cominc.hxx>
|
|
#include <string.h>
|
|
#include "w3ssl_config.hxx"
|
|
|
|
|
|
|
|
//static
|
|
int W3SSL_CONFIG::s_fConfigTerminationRequested = FALSE;
|
|
//static
|
|
HANDLE W3SSL_CONFIG::s_hConfigChangeThread = NULL;
|
|
//static
|
|
LPWSTR W3SSL_CONFIG::s_pszImagePathInetinfo = NULL;
|
|
//static
|
|
LPWSTR W3SSL_CONFIG::s_pszImagePathLsass = NULL;
|
|
//static
|
|
LPWSTR W3SSL_CONFIG::s_pszImagePathSvchost = NULL;
|
|
|
|
|
|
|
|
//static
|
|
HRESULT
|
|
W3SSL_CONFIG::SetHTTPFilterImagePath(
|
|
BOOL fIIS5IsolationModeEnabled,
|
|
BOOL fStartInSvchost
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Configure image path of the service to point either
|
|
lsass.exe or inetinfo.exe based on the IIS Application
|
|
Mode
|
|
|
|
Arguments:
|
|
|
|
fIIS5IsolationModeEnabled - TRUE if IIS runs in old mode
|
|
FALSE if it runs in new mode
|
|
fStartInSvchost - preferred location for HTTPFilter is svchost.exe
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
|
|
{
|
|
SC_LOCK scLock = NULL;
|
|
SC_HANDLE schSCManager = NULL;
|
|
SC_HANDLE schHTTPFilterService = NULL;
|
|
LPQUERY_SERVICE_CONFIG pServiceConfig = NULL;
|
|
DWORD dwBytesNeeded = 0;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
// Open a handle to the SC Manager database.
|
|
|
|
schSCManager = OpenSCManagerW(
|
|
NULL, // local machine
|
|
NULL, // ServicesActive database
|
|
SC_MANAGER_ALL_ACCESS ); // full access rights
|
|
|
|
if ( schSCManager == NULL )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( GetLastError() );
|
|
goto Finished;
|
|
}
|
|
|
|
schHTTPFilterService = OpenServiceW(
|
|
schSCManager, // SCM database
|
|
HTTPFILTER_SERVICE_NAME, // service name
|
|
SERVICE_ALL_ACCESS);
|
|
|
|
if ( schHTTPFilterService == NULL )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( GetLastError() );
|
|
goto Finished;
|
|
}
|
|
|
|
//
|
|
// Get the configuration information.
|
|
// - to find out the current image path of the
|
|
// HTTPFilter service
|
|
//
|
|
|
|
if ( !QueryServiceConfigW(
|
|
schHTTPFilterService,
|
|
pServiceConfig,
|
|
0,
|
|
&dwBytesNeeded ) )
|
|
{
|
|
if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
|
|
{
|
|
pServiceConfig = reinterpret_cast<LPQUERY_SERVICE_CONFIG> (
|
|
new char[dwBytesNeeded] );
|
|
if ( pServiceConfig == NULL )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_OUTOFMEMORY );
|
|
goto Finished;
|
|
}
|
|
if ( !QueryServiceConfigW(
|
|
schHTTPFilterService,
|
|
pServiceConfig,
|
|
dwBytesNeeded,
|
|
&dwBytesNeeded ) )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( GetLastError() );
|
|
goto Finished;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32( GetLastError() );
|
|
goto Finished;
|
|
}
|
|
}
|
|
|
|
//
|
|
// reconfigure image path of HTTPFilter if necessary
|
|
//
|
|
if ( ( fIIS5IsolationModeEnabled &&
|
|
_wcsicmp( pServiceConfig->lpBinaryPathName,
|
|
s_pszImagePathInetinfo ) != 0 ) ||
|
|
( !fIIS5IsolationModeEnabled &&
|
|
_wcsicmp( pServiceConfig->lpBinaryPathName,
|
|
s_pszImagePathLsass ) != 0 &&
|
|
_wcsicmp( pServiceConfig->lpBinaryPathName,
|
|
s_pszImagePathSvchost ) != 0 )
|
|
|
|
)
|
|
{
|
|
|
|
//
|
|
// figure out what image path to configure
|
|
//
|
|
WCHAR * pszImagePath = ( fIIS5IsolationModeEnabled )?
|
|
s_pszImagePathInetinfo :
|
|
( ( fStartInSvchost )?
|
|
s_pszImagePathSvchost:
|
|
s_pszImagePathLsass );
|
|
|
|
if ( fIIS5IsolationModeEnabled )
|
|
{
|
|
BOOL fSave = FALSE;
|
|
//
|
|
// check if we need to store image path information
|
|
// before changing
|
|
//
|
|
if ( _wcsicmp( pServiceConfig->lpBinaryPathName,
|
|
s_pszImagePathLsass ) == 0 &&
|
|
fStartInSvchost )
|
|
{
|
|
fStartInSvchost = FALSE;
|
|
fSave = TRUE;
|
|
}
|
|
if ( _wcsicmp( pServiceConfig->lpBinaryPathName,
|
|
s_pszImagePathSvchost ) == 0 &&
|
|
!fStartInSvchost )
|
|
{
|
|
fStartInSvchost = TRUE;
|
|
fSave = TRUE;
|
|
}
|
|
if ( fSave )
|
|
{
|
|
//
|
|
// let's flag in the registry which one lsass and svchost
|
|
// was hosting the HTTPFilter service
|
|
//
|
|
DWORD dwValue = (DWORD) fStartInSvchost;
|
|
DWORD dwErr;
|
|
HKEY hKeyParam;
|
|
|
|
|
|
if ( ( dwErr = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
|
|
HTTPFILTER_PARAMETERS_KEY,
|
|
0,
|
|
KEY_WRITE,
|
|
&hKeyParam ) ) == NO_ERROR )
|
|
{
|
|
dwErr = RegSetValueExW( hKeyParam,
|
|
L"StartInSvchost",
|
|
NULL,
|
|
REG_DWORD,
|
|
( LPBYTE )&dwValue,
|
|
sizeof( dwValue )
|
|
);
|
|
//
|
|
// Ignore the error.
|
|
//
|
|
|
|
RegCloseKey( hKeyParam );
|
|
}
|
|
|
|
if ( dwErr != NO_ERROR )
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"Failed to write to registry to path %S (hr = %d)\n",
|
|
HTTPFILTER_PARAMETERS_KEY,
|
|
HRESULT_FROM_WIN32( dwErr )));
|
|
}
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// loop to acquire service database lock
|
|
//
|
|
for ( ; ; )
|
|
{
|
|
scLock = LockServiceDatabase( schSCManager );
|
|
if ( scLock == NULL )
|
|
{
|
|
if ( GetLastError() == ERROR_SERVICE_DATABASE_LOCKED )
|
|
{
|
|
if ( s_fConfigTerminationRequested == TRUE )
|
|
{
|
|
//
|
|
// if W3SSL_CONFIG::Terminate() is called
|
|
// while this function is still waiting for service
|
|
// to get locked, we simply bail out.
|
|
// ImagePath will not be changed
|
|
//
|
|
hr = HRESULT_FROM_WIN32( ERROR_OPERATION_ABORTED );
|
|
goto Finished;
|
|
}
|
|
|
|
Sleep( 1000 );
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32( GetLastError() );
|
|
goto Finished;
|
|
}
|
|
}
|
|
|
|
if ( s_fConfigTerminationRequested == TRUE )
|
|
{
|
|
//
|
|
// if W3SSL_CONFIG::Terminate() is called
|
|
// while this function is still waiting for service
|
|
// to get locked, we simply bail out.
|
|
// ImagePath will not be changed
|
|
//
|
|
hr = HRESULT_FROM_WIN32( ERROR_OPERATION_ABORTED );
|
|
goto Finished;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if ( !ChangeServiceConfigW(
|
|
schHTTPFilterService, // handle of service
|
|
SERVICE_NO_CHANGE, // service type
|
|
SERVICE_NO_CHANGE, // change service start type
|
|
SERVICE_NO_CHANGE, // error control
|
|
pszImagePath, // binary path
|
|
NULL, // load order group
|
|
NULL, // tag ID
|
|
NULL, // dependencies
|
|
NULL, // account name
|
|
NULL, // password
|
|
NULL) ) // display name
|
|
{
|
|
hr = HRESULT_FROM_WIN32( GetLastError() );
|
|
goto Finished;
|
|
}
|
|
|
|
UnlockServiceDatabase( scLock );
|
|
scLock = NULL;
|
|
|
|
}
|
|
|
|
|
|
hr = S_OK;
|
|
|
|
Finished:
|
|
|
|
if ( pServiceConfig != NULL )
|
|
{
|
|
delete [] pServiceConfig;
|
|
pServiceConfig = NULL;
|
|
}
|
|
|
|
if ( scLock != NULL )
|
|
{
|
|
UnlockServiceDatabase( scLock );
|
|
scLock = NULL;
|
|
}
|
|
|
|
if ( schHTTPFilterService != NULL )
|
|
{
|
|
DBG_REQUIRE( CloseServiceHandle( schHTTPFilterService ) );
|
|
schHTTPFilterService = NULL;
|
|
}
|
|
|
|
if ( schSCManager != NULL )
|
|
{
|
|
DBG_REQUIRE( CloseServiceHandle( schSCManager ) );
|
|
schSCManager = NULL;
|
|
}
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
//static
|
|
HRESULT
|
|
W3SSL_CONFIG::AdjustHTTPFilterImagePath(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Based on the metabase valuse
|
|
configure image path of the service to point either
|
|
lsass.exe or inetinfo.exe based on the IIS Application
|
|
Mode
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
|
|
HRESULT hr = E_FAIL;
|
|
METADATA_RECORD mdrData;
|
|
DWORD dwRequiredDataLen = 0;
|
|
METADATA_HANDLE mhOpenHandle = 0;
|
|
IMDCOM * pcCom = NULL;
|
|
DWORD dwStandardModeEnabled = 1;
|
|
|
|
DWORD dwType;
|
|
DWORD nBytes;
|
|
DWORD dwValue;
|
|
DWORD dwErr;
|
|
BOOL fStartInSvchost = FALSE;
|
|
HKEY hKeyParam;
|
|
|
|
|
|
//
|
|
// read registry to find out if preferred location for HTTPFilter is svchost
|
|
//
|
|
|
|
if ( RegOpenKeyExW( HKEY_LOCAL_MACHINE,
|
|
HTTPFILTER_PARAMETERS_KEY,
|
|
0,
|
|
KEY_READ,
|
|
&hKeyParam ) == NO_ERROR )
|
|
{
|
|
nBytes = sizeof( dwValue );
|
|
dwErr = RegQueryValueExW( hKeyParam,
|
|
L"StartInSvchost",
|
|
NULL,
|
|
&dwType,
|
|
( LPBYTE )&dwValue,
|
|
&nBytes
|
|
);
|
|
|
|
if ( ( dwErr == ERROR_SUCCESS ) && ( dwType == REG_DWORD ) )
|
|
{
|
|
fStartInSvchost = !!dwValue;
|
|
}
|
|
|
|
RegCloseKey( hKeyParam );
|
|
}
|
|
|
|
|
|
|
|
hr = CoCreateInstance( CLSID_MDCOM,
|
|
NULL,
|
|
CLSCTX_SERVER,
|
|
IID_IMDCOM,
|
|
(void**) &pcCom);
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Finished;
|
|
}
|
|
|
|
hr = pcCom->ComMDOpenMetaObject( METADATA_MASTER_ROOT_HANDLE,
|
|
L"/lm/w3svc",
|
|
METADATA_PERMISSION_READ,
|
|
OPEN_TIMEOUT_VALUE,
|
|
&mhOpenHandle );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Finished;
|
|
}
|
|
else
|
|
{
|
|
MD_SET_DATA_RECORD_EXT( &mdrData,
|
|
MD_GLOBAL_STANDARD_APP_MODE_ENABLED ,
|
|
METADATA_NO_ATTRIBUTES,
|
|
ALL_METADATA,
|
|
DWORD_METADATA,
|
|
sizeof( dwStandardModeEnabled ),
|
|
(PBYTE) &dwStandardModeEnabled );
|
|
|
|
hr = pcCom->ComMDGetMetaData( mhOpenHandle,
|
|
NULL,
|
|
&mdrData,
|
|
&dwRequiredDataLen );
|
|
|
|
if ( hr == MD_ERROR_DATA_NOT_FOUND )
|
|
{
|
|
//
|
|
// Standard mode is enabled by default
|
|
//
|
|
dwStandardModeEnabled = 1;
|
|
}
|
|
else if ( FAILED ( hr ) )
|
|
{
|
|
//
|
|
// Error different from not found
|
|
// In this case simply bail out
|
|
//
|
|
goto Finished;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Cleanup metabase object
|
|
//
|
|
pcCom->ComMDCloseMetaObject( mhOpenHandle );
|
|
mhOpenHandle = 0;
|
|
|
|
pcCom->Release();
|
|
pcCom = NULL;
|
|
|
|
hr = SetHTTPFilterImagePath( (BOOL) !!dwStandardModeEnabled, fStartInSvchost );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Finished;
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
Finished:
|
|
|
|
if ( mhOpenHandle != 0 )
|
|
{
|
|
pcCom->ComMDCloseMetaObject( mhOpenHandle );
|
|
mhOpenHandle = 0;
|
|
}
|
|
|
|
|
|
if ( pcCom != NULL )
|
|
{
|
|
pcCom->Release();
|
|
pcCom = NULL;
|
|
}
|
|
|
|
|
|
return hr;
|
|
}
|
|
|
|
//static
|
|
HRESULT
|
|
W3SSL_CONFIG::StartAsyncAdjustHTTPFilterImagePath(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Configure image path of the service to point either
|
|
lsass.exe or inetinfo.exe based on the IIS Application
|
|
Mode.
|
|
The action is executed on separate thread
|
|
|
|
Terminate() must be called to assure proper cleanup
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
|
|
s_hConfigChangeThread =
|
|
::CreateThread(
|
|
NULL, // default security descriptor
|
|
0, // default process stack size
|
|
W3SSL_CONFIG::ConfigChangeThread,
|
|
NULL, // thread argument - pointer to this class
|
|
0, // create running
|
|
NULL // don't care for thread identifier
|
|
);
|
|
|
|
if ( s_hConfigChangeThread == NULL )
|
|
{
|
|
return HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
ExpandImagePath(
|
|
const WCHAR * pszPath,
|
|
WCHAR ** ppszExpandedPath
|
|
)
|
|
{
|
|
DBG_ASSERT( *ppszExpandedPath == NULL );
|
|
DWORD dwLen = ExpandEnvironmentStringsW( pszPath, NULL, 0 );
|
|
* ppszExpandedPath = new WCHAR [dwLen];
|
|
if ( * ppszExpandedPath == NULL )
|
|
{
|
|
return HRESULT_FROM_WIN32( ERROR_OUTOFMEMORY );
|
|
}
|
|
|
|
(* ppszExpandedPath)[0] = '\0';
|
|
|
|
DWORD dwLen2 = ExpandEnvironmentStringsW( pszPath,
|
|
*ppszExpandedPath,
|
|
dwLen );
|
|
if ( dwLen2 != dwLen )
|
|
{
|
|
return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
//static
|
|
HRESULT
|
|
W3SSL_CONFIG::Initialize(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialization
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
//
|
|
// Expand image path because QueryServiceConfig
|
|
// already returns expanded ImagePath and
|
|
// Image Paths will be compared few times
|
|
//
|
|
|
|
hr = ExpandImagePath( HTTPFILTER_SERVICE_IMAGEPATH_INETINFO,
|
|
&s_pszImagePathInetinfo );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Failed;
|
|
}
|
|
hr = ExpandImagePath( HTTPFILTER_SERVICE_IMAGEPATH_LSASS,
|
|
&s_pszImagePathLsass );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Failed;
|
|
}
|
|
hr = ExpandImagePath( HTTPFILTER_SERVICE_IMAGEPATH_SVCHOST,
|
|
&s_pszImagePathSvchost );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Failed;
|
|
}
|
|
|
|
return S_OK;
|
|
|
|
Failed:
|
|
Terminate();
|
|
return hr;
|
|
}
|
|
|
|
|
|
//static
|
|
VOID
|
|
W3SSL_CONFIG::Terminate(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Quits the asynchronous change of HTTPFILTER image path (if any)
|
|
and/or does final cleanup
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
--*/
|
|
{
|
|
s_fConfigTerminationRequested = TRUE;
|
|
|
|
if ( s_hConfigChangeThread != NULL )
|
|
{
|
|
DWORD dwRet = WaitForSingleObject( s_hConfigChangeThread,
|
|
INFINITE );
|
|
DBG_ASSERT( dwRet == WAIT_OBJECT_0 );
|
|
|
|
// IVANPASH dwRet is used only in debug builds, so on /W4 there is
|
|
// a warning, which is cheated by the next otherwise useless line.
|
|
(VOID)dwRet;
|
|
|
|
CloseHandle( s_hConfigChangeThread );
|
|
s_hConfigChangeThread = NULL;
|
|
}
|
|
|
|
if ( s_pszImagePathInetinfo != NULL )
|
|
{
|
|
delete s_pszImagePathInetinfo;
|
|
s_pszImagePathInetinfo = NULL;
|
|
}
|
|
|
|
if ( s_pszImagePathSvchost != NULL )
|
|
{
|
|
delete s_pszImagePathSvchost;
|
|
s_pszImagePathSvchost = NULL;
|
|
}
|
|
if ( s_pszImagePathLsass != NULL )
|
|
{
|
|
delete s_pszImagePathLsass;
|
|
s_pszImagePathLsass = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//static
|
|
DWORD
|
|
W3SSL_CONFIG::ConfigChangeThread(
|
|
LPVOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Worker thread function used to perform image path change asynchronously
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
--*/
|
|
|
|
{
|
|
AdjustHTTPFilterImagePath();
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|