|
|
/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
setup.cpp
Abstract:
Setup code called from regsvr32
--*/
#include "precomp.h"
BSTR g_PropertyBSTR = NULL; BSTR g_SyntaxBSTR = NULL; BSTR g_UserTypeBSTR = NULL; BSTR g_InheritBSTR = NULL; BSTR g_ClassBSTR = NULL; BSTR g_IsapiRestrictionListBSTR = NULL; BSTR g_RestrictionListCustomDescBSTR = NULL; BSTR g_FilterLoadOrderBSTR = NULL; BSTR g_IIsFilterBSTR = NULL; BSTR g_InProcessIsapiAppsBSTR = NULL; BSTR g_bitsserverBSTR = NULL; BSTR g_bitserverBSTR = NULL;
HRESULT InitializeSetup() {
g_PropertyBSTR = SysAllocString( L"Property" ); g_SyntaxBSTR = SysAllocString( L"Syntax" ); g_UserTypeBSTR = SysAllocString( L"UserType" ); g_InheritBSTR = SysAllocString( L"Inherit" ); g_ClassBSTR = SysAllocString( L"Class" ); g_IsapiRestrictionListBSTR = SysAllocString( L"IsapiRestrictionList" ); g_RestrictionListCustomDescBSTR = SysAllocString( L"RestrictionListCustomDesc" ); g_FilterLoadOrderBSTR = SysAllocString( L"FilterLoadOrder" ); g_IIsFilterBSTR = SysAllocString( L"IIsFilter" ); g_InProcessIsapiAppsBSTR = SysAllocString( L"InProcessIsapiApps" ); g_bitsserverBSTR = SysAllocString( L"bitsserver" ); g_bitserverBSTR = SysAllocString( L"bitserver" );
if ( !g_PropertyBSTR || !g_SyntaxBSTR || !g_UserTypeBSTR || !g_InheritBSTR | !g_ClassBSTR || !g_IsapiRestrictionListBSTR || !g_RestrictionListCustomDescBSTR || !g_FilterLoadOrderBSTR || !g_IIsFilterBSTR || !g_InProcessIsapiAppsBSTR || !g_bitsserverBSTR || !g_bitserverBSTR ) {
SysFreeString( g_PropertyBSTR ); SysFreeString( g_SyntaxBSTR ); SysFreeString( g_UserTypeBSTR ); SysFreeString( g_InheritBSTR ); SysFreeString( g_ClassBSTR ); SysFreeString( g_IsapiRestrictionListBSTR ); SysFreeString( g_RestrictionListCustomDescBSTR ); SysFreeString( g_FilterLoadOrderBSTR ); SysFreeString( g_IIsFilterBSTR ); SysFreeString( g_InProcessIsapiAppsBSTR ); SysFreeString( g_bitsserverBSTR ); SysFreeString( g_bitserverBSTR );
g_PropertyBSTR = g_SyntaxBSTR = g_UserTypeBSTR = g_InheritBSTR = g_ClassBSTR = g_IsapiRestrictionListBSTR = g_RestrictionListCustomDescBSTR = g_FilterLoadOrderBSTR = g_IIsFilterBSTR = g_InProcessIsapiAppsBSTR = g_bitsserverBSTR = g_bitserverBSTR = NULL;
return E_OUTOFMEMORY;
}
return S_OK;
}
void CleanupSetup() {
SysFreeString( g_PropertyBSTR ); SysFreeString( g_SyntaxBSTR ); SysFreeString( g_UserTypeBSTR ); SysFreeString( g_InheritBSTR ); SysFreeString( g_ClassBSTR ); SysFreeString( g_IsapiRestrictionListBSTR ); SysFreeString( g_RestrictionListCustomDescBSTR ); SysFreeString( g_FilterLoadOrderBSTR ); SysFreeString( g_IIsFilterBSTR ); SysFreeString( g_InProcessIsapiAppsBSTR ); SysFreeString( g_bitsserverBSTR ); SysFreeString( g_bitserverBSTR );
g_PropertyBSTR = g_SyntaxBSTR = g_UserTypeBSTR = g_InheritBSTR = g_ClassBSTR = g_IsapiRestrictionListBSTR = g_RestrictionListCustomDescBSTR = g_FilterLoadOrderBSTR = g_IIsFilterBSTR = g_InProcessIsapiAppsBSTR = g_bitsserverBSTR = NULL;
}
void RemoveFilterHelper( WCHAR * Buffer, const WCHAR * const ToRemove ) {
WCHAR *ToReplace; SIZE_T FragmentLength = wcslen( ToRemove );
while( ToReplace = wcsstr( Buffer, ToRemove ) ) { WCHAR *Next = ToReplace + FragmentLength; memmove( ToReplace, Next, sizeof(WCHAR) * ( wcslen( Next ) + 1 ) ); Buffer = ToReplace; }
}
DWORD BITSGetStartupInfoFilter( DWORD Status ) {
//
// The following exceptions are documented
// to be thrown by GetStartupInfoA
//
switch( Status ) {
case STATUS_NO_MEMORY: case STATUS_INVALID_PARAMETER_2: case STATUS_BUFFER_OVERFLOW: return EXCEPTION_EXECUTE_HANDLER;
default: return EXCEPTION_CONTINUE_SEARCH; }
}
HRESULT BITSGetStartupInfo( LPSTARTUPINFO lpStartupInfo ) {
__try { GetStartupInfoA( lpStartupInfo ); } __except( BITSGetStartupInfoFilter( GetExceptionCode() ) ) { return E_OUTOFMEMORY; } return S_OK;
}
HRESULT RestartIIS() {
//
// Restarts IIS by calling "iisreset /restart" at the commandline.
//
STARTUPINFO StartupInfo;
HRESULT Hr = BITSGetStartupInfo( &StartupInfo );
if ( FAILED( Hr ) ) return Hr;
#define IISRESET_EXE "iisreset.exe"
#define IISRESET_CMDLINE "iisreset /RESTART"
PROCESS_INFORMATION ProcessInfo; CHAR sApplicationPath[MAX_PATH]; CHAR *pApplicationName = NULL; CHAR sCmdLine[MAX_PATH]; DWORD dwLen = MAX_PATH; DWORD dwCount;
dwCount = SearchPath(NULL, // Search Path, NULL is PATH
IISRESET_EXE, // Application
NULL, // Extension (already specified)
dwLen, // Length (char's) of sApplicationPath
sApplicationPath, // Path + Name for application
&pApplicationName ); // File part of sApplicationPath
if (dwCount == 0) { return HRESULT_FROM_WIN32( GetLastError() ); }
if (dwCount > dwLen) { return HRESULT_FROM_WIN32( ERROR_BUFFER_OVERFLOW ); }
StringCbCopyA(sCmdLine, MAX_PATH, IISRESET_CMDLINE);
BOOL RetVal = CreateProcess( sApplicationPath, // name of executable module
sCmdLine, // command line string
NULL, // SD
NULL, // SD
FALSE, // handle inheritance option
CREATE_NO_WINDOW, // creation flags
NULL, // new environment block
NULL, // current directory name
&StartupInfo, // startup information
&ProcessInfo // process information
);
if ( !RetVal ) return HRESULT_FROM_WIN32( GetLastError() );
WaitForSingleObject( ProcessInfo.hProcess, INFINITE );
DWORD Status; GetExitCodeProcess( ProcessInfo.hProcess, &Status );
CloseHandle( ProcessInfo.hProcess ); CloseHandle( ProcessInfo.hThread );
return HRESULT_FROM_WIN32( Status ); }
HRESULT InstallPropertySchema( ) {
//
// Installs the ADSI schema with the new metabase properties.
//
HRESULT Hr; VARIANT var; VariantInit( &var ); IADsContainer *MbSchemaContainer = NULL;
Hr = ADsGetObject( L"IIS://LocalHost/Schema", __uuidof( *MbSchemaContainer), reinterpret_cast<void**>( &MbSchemaContainer ) );
if ( FAILED( Hr ) ) return Hr;
BSTR PropertyNameBSTR = NULL; BSTR PropertyClassBSTR = NULL;
IDispatch *Dispatch = NULL; IADs *MbProperty = NULL; IADsClass *MbClass = NULL;
for ( SIZE_T i = 0; i < g_NumberOfProperties; i++ ) { PropertyNameBSTR = SysAllocString( g_Properties[i].PropertyName ); PropertyClassBSTR = SysAllocString( g_Properties[i].ClassName );
Hr = MbSchemaContainer->Create( g_PropertyBSTR, PropertyNameBSTR, &Dispatch );
if ( Hr == E_ADS_OBJECT_EXISTS ) continue;
if ( FAILED( Hr ) ) goto failed;
Hr = Dispatch->QueryInterface( __uuidof( *MbProperty ), reinterpret_cast<void**>( &MbProperty ) );
if ( FAILED( Hr ) ) goto failed;
Dispatch->Release(); Dispatch = NULL;
var.bstrVal = SysAllocString( g_Properties[i].Syntax ); var.vt = VT_BSTR;
if ( !var.bstrVal ) { Hr = E_OUTOFMEMORY; goto failed; }
Hr = MbProperty->Put( g_SyntaxBSTR, var );
if ( FAILED(Hr) ) goto failed;
VariantClear( &var );
var.ulVal = g_Properties[i].UserType; var.vt = VT_UI4;
Hr = MbProperty->Put( g_UserTypeBSTR, var );
if ( FAILED( Hr ) ) goto failed;
var.boolVal = true; var.vt = VT_BOOL;
Hr = MbProperty->Put( g_InheritBSTR, var ); if ( FAILED(Hr) ) goto failed;
Hr = MbProperty->SetInfo();
if ( FAILED(Hr) ) goto failed;
VariantClear( &var ); MbProperty->Release(); MbProperty = NULL;
Hr = MbSchemaContainer->GetObject( g_ClassBSTR, PropertyClassBSTR, &Dispatch );
if ( FAILED(Hr) ) goto failed;
Hr = Dispatch->QueryInterface( __uuidof( *MbClass ), reinterpret_cast<void**>( &MbClass ) );
if ( FAILED( Hr ) ) goto failed;
Dispatch->Release(); Dispatch = NULL;
Hr = MbClass->get_OptionalProperties( &var );
if ( FAILED( Hr ) ) goto failed;
SAFEARRAY* Array = var.parray; long LBound; long UBound;
Hr = SafeArrayGetLBound( Array, 1, &LBound ); if ( FAILED( Hr ) ) goto failed;
Hr = SafeArrayGetUBound( Array, 1, &UBound ); if ( FAILED( Hr ) ) goto failed;
UBound++; // Add one to the upper bound
SAFEARRAYBOUND SafeBounds; SafeBounds.lLbound = LBound; SafeBounds.cElements = UBound - LBound + 1;
Hr = SafeArrayRedim( Array, &SafeBounds ); if ( FAILED( Hr ) ) goto failed;
VARIANT bstrvar; VariantInit( &bstrvar ); bstrvar.vt = VT_BSTR; bstrvar.bstrVal = SysAllocString( g_Properties[i].PropertyName ); if ( !bstrvar.bstrVal ) { Hr = E_OUTOFMEMORY; goto failed; }
long Dim = (long)UBound; Hr = SafeArrayPutElement( Array, &Dim, &bstrvar ); VariantClear( &bstrvar );
if ( FAILED(Hr) ) goto failed;
Hr = MbClass->put_OptionalProperties( var );
if ( FAILED(Hr) ) goto failed;
Hr = MbClass->SetInfo();
if ( FAILED(Hr) ) goto failed;
MbClass->Release(); MbClass = NULL;
SysFreeString( PropertyNameBSTR ); SysFreeString( PropertyClassBSTR ); PropertyNameBSTR = PropertyClassBSTR = NULL;
}
Hr = S_OK;
failed:
VariantClear( &var );
if ( Dispatch ) Dispatch->Release();
if ( MbProperty ) MbProperty->Release();
if ( MbClass ) MbClass->Release();
if ( MbSchemaContainer ) MbSchemaContainer->Release();
SysFreeString( PropertyNameBSTR ); SysFreeString( PropertyClassBSTR ); return Hr;
}
HRESULT RemovePropertySchema( ) {
// Removes our properties from the metabase schema
HRESULT Hr; VARIANT var; VariantInit( &var );
IADsContainer *MbSchemaContainer = NULL;
Hr = ADsGetObject( L"IIS://LocalHost/Schema", __uuidof( *MbSchemaContainer ), reinterpret_cast<void**>( &MbSchemaContainer ) );
if ( FAILED( Hr ) ) return Hr;
BSTR PropertyNameBSTR = NULL; BSTR PropertyClassBSTR = NULL; IDispatch *Dispatch = NULL; IADsClass *MbClass = NULL; IADs *Object = NULL;
for ( SIZE_T i = 0; i < g_NumberOfProperties; i++ ) {
PropertyNameBSTR = SysAllocString( g_Properties[i].PropertyName ); PropertyClassBSTR = SysAllocString( g_Properties[i].ClassName );
if ( !PropertyNameBSTR || !PropertyClassBSTR ) { Hr = E_OUTOFMEMORY; goto failed; }
MbSchemaContainer->Delete( g_PropertyBSTR, PropertyNameBSTR ); Hr = MbSchemaContainer->QueryInterface( __uuidof(*Object), reinterpret_cast<void**>( &Object ) );
if ( FAILED( Hr ) ) goto failed;
Object->SetInfo();
Object->Release(); Object = NULL;
Hr = MbSchemaContainer->GetObject( g_ClassBSTR, PropertyClassBSTR, &Dispatch );
if ( FAILED( Hr ) ) goto failed;
Hr = Dispatch->QueryInterface( __uuidof( *MbClass ), reinterpret_cast<void**>( &MbClass ) );
if ( FAILED( Hr ) ) goto failed;
Dispatch->Release(); Dispatch = NULL; if ( FAILED( Hr ) ) goto failed; Hr = MbClass->get_OptionalProperties( &var );
SAFEARRAY* Array = var.parray; Hr = SafeArrayLock( Array );
if ( FAILED( Hr ) ) goto failed;
ULONG NewSize = 0; SIZE_T j = Array->rgsabound[0].lLbound; SIZE_T k = Array->rgsabound[0].lLbound + Array->rgsabound[0].cElements; while( j < k ) {
VARIANT & JElem = ((VARIANT*)Array->pvData)[j];
// This element is fine, keep it
if ( 0 != _wcsicmp( (WCHAR*)JElem.bstrVal, BSTR( g_Properties[i].PropertyName ) ) ) { NewSize++; j++; }
else {
// find a suitable element to replace the bad element with
while( j < --k ) { VARIANT & KElem = ((VARIANT*)Array->pvData)[k]; if ( 0 != _wcsicmp( (WCHAR*)KElem.bstrVal, BSTR( g_Properties[i].PropertyName ) ) ) { // found element. move it
VARIANT temp = JElem; JElem = KElem; KElem = temp; break; } } } }
SAFEARRAYBOUND ArrayBounds; ArrayBounds = Array->rgsabound[0]; ArrayBounds.cElements = NewSize;
SafeArrayUnlock( Array );
Hr = SafeArrayRedim( Array, &ArrayBounds );
if ( FAILED( Hr ) ) goto failed;
Hr = MbClass->put_OptionalProperties( var );
if ( FAILED( Hr ) ) goto failed;
Hr = MbClass->SetInfo();
if ( FAILED( Hr ) ) goto failed;
MbClass->Release(); MbClass = NULL;
VariantClear( &var ); continue;
failed:
SysFreeString( PropertyNameBSTR ); SysFreeString( PropertyClassBSTR ); PropertyNameBSTR = PropertyClassBSTR = NULL;
if ( MbClass ) { MbClass->Release(); MbClass = NULL; }
if ( Dispatch ) { Dispatch->Release(); Dispatch = NULL; }
if ( Object ) { Object->Release(); Object = NULL; }
VariantClear( &var );
}
return S_OK;
}
HRESULT InstallDefaultValues( ) {
//
// Install default values for the configuration. Do this at the top and let inheritance deal with it.
//
HRESULT Hr = S_OK; METADATA_RECORD mdr; METADATA_HANDLE mdHandle = NULL; DWORD Value;
IMSAdminBase * IISAdminBase = NULL; class PropertyIDManager *PropertyMan = new PropertyIDManager();
if ( !PropertyMan ) return E_OUTOFMEMORY;
Hr = PropertyMan->LoadPropertyInfo(); if ( FAILED(Hr) ) goto error;
Hr = CoCreateInstance( GETAdminBaseCLSID(TRUE), NULL, CLSCTX_SERVER, __uuidof( *IISAdminBase ), (LPVOID*)&IISAdminBase );
if ( FAILED(Hr) ) goto error;
Hr = IISAdminBase->OpenKey( METADATA_MASTER_ROOT_HANDLE, L"/LM/W3SVC", METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE, 10000, // 10 seconds
&mdHandle );
if ( FAILED(Hr) ) goto error;
mdr.dwMDIdentifier = PropertyMan->GetPropertyMetabaseID( MD_BITS_CONNECTION_DIR ); mdr.dwMDAttributes = METADATA_INHERIT; mdr.dwMDUserType = PropertyMan->GetPropertyUserType( MD_BITS_CONNECTION_DIR ); mdr.dwMDDataType = STRING_METADATA; mdr.pbMDData = (PBYTE)MD_DEFAULT_BITS_CONNECTION_DIR; mdr.dwMDDataLen = sizeof(WCHAR) * ( wcslen( MD_DEFAULT_BITS_CONNECTION_DIR ) + 1 ); mdr.dwMDDataTag = 0;
Hr = IISAdminBase->SetData( mdHandle, NULL, &mdr );
if ( FAILED(Hr) ) goto error;
mdr.dwMDIdentifier = PropertyMan->GetPropertyMetabaseID( MD_BITS_MAX_FILESIZE ); mdr.dwMDAttributes = METADATA_INHERIT; mdr.dwMDUserType = PropertyMan->GetPropertyUserType( MD_BITS_MAX_FILESIZE ); mdr.dwMDDataType = STRING_METADATA; mdr.pbMDData = (PBYTE)MD_DEFAULT_BITS_MAX_FILESIZE; mdr.dwMDDataLen = sizeof(WCHAR) * ( wcslen( MD_DEFAULT_BITS_MAX_FILESIZE ) + 1 ); mdr.dwMDDataTag = 0;
Hr = IISAdminBase->SetData( mdHandle, NULL, &mdr );
if ( FAILED(Hr) ) goto error;
Value = MD_DEFAULT_NO_PROGESS_TIMEOUT; mdr.dwMDIdentifier = PropertyMan->GetPropertyMetabaseID( MD_BITS_NO_PROGRESS_TIMEOUT ); mdr.dwMDAttributes = METADATA_INHERIT; mdr.dwMDUserType = PropertyMan->GetPropertyUserType( MD_BITS_NO_PROGRESS_TIMEOUT ); mdr.dwMDDataType = DWORD_METADATA; mdr.pbMDData = (PBYTE)&Value; mdr.dwMDDataLen = sizeof(Value); mdr.dwMDDataTag = 0;
Hr = IISAdminBase->SetData( mdHandle, NULL, &mdr );
if ( FAILED(Hr) ) goto error;
Value = (DWORD)MD_DEFAULT_BITS_NOTIFICATION_URL_TYPE; mdr.dwMDIdentifier = PropertyMan->GetPropertyMetabaseID( MD_BITS_NOTIFICATION_URL_TYPE ); mdr.dwMDAttributes = METADATA_INHERIT; mdr.dwMDUserType = PropertyMan->GetPropertyUserType( MD_BITS_NOTIFICATION_URL_TYPE ); mdr.dwMDDataType = DWORD_METADATA; mdr.pbMDData = (PBYTE)&Value; mdr.dwMDDataLen = sizeof(Value); mdr.dwMDDataTag = 0;
Hr = IISAdminBase->SetData( mdHandle, NULL, &mdr );
if ( FAILED(Hr) ) goto error;
mdr.dwMDIdentifier = PropertyMan->GetPropertyMetabaseID( MD_BITS_NOTIFICATION_URL ); mdr.dwMDAttributes = METADATA_INHERIT; mdr.dwMDUserType = PropertyMan->GetPropertyUserType( MD_BITS_NOTIFICATION_URL ); mdr.dwMDDataType = STRING_METADATA; mdr.pbMDData = (PBYTE)MD_DEFAULT_BITS_NOTIFICATION_URL; mdr.dwMDDataLen = sizeof(WCHAR) * ( wcslen( MD_DEFAULT_BITS_NOTIFICATION_URL ) + 1 );; mdr.dwMDDataTag = 0;
Hr = IISAdminBase->SetData( mdHandle, NULL, &mdr );
if ( FAILED(Hr) ) goto error;
mdr.dwMDIdentifier = PropertyMan->GetPropertyMetabaseID( MD_BITS_HOSTID ); mdr.dwMDAttributes = METADATA_INHERIT; mdr.dwMDUserType = PropertyMan->GetPropertyUserType( MD_BITS_HOSTID ); mdr.dwMDDataType = STRING_METADATA; mdr.pbMDData = (PBYTE)MD_DEFAULT_BITS_HOSTID; mdr.dwMDDataLen = sizeof(WCHAR) * ( wcslen( MD_DEFAULT_BITS_HOSTID ) + 1 ); mdr.dwMDDataTag = 0;
Hr = IISAdminBase->SetData( mdHandle, NULL, &mdr );
if ( FAILED(Hr) ) goto error;
Value = MD_DEFAULT_HOSTID_FALLBACK_TIMEOUT; mdr.dwMDIdentifier = PropertyMan->GetPropertyMetabaseID( MD_BITS_HOSTID_FALLBACK_TIMEOUT ); mdr.dwMDAttributes = METADATA_INHERIT; mdr.dwMDUserType = PropertyMan->GetPropertyUserType( MD_BITS_HOSTID_FALLBACK_TIMEOUT ); mdr.dwMDDataType = DWORD_METADATA; mdr.pbMDData = (PBYTE)&Value; mdr.dwMDDataLen = sizeof(Value); mdr.dwMDDataTag = 0;
Hr = IISAdminBase->SetData( mdHandle, NULL, &mdr );
if ( FAILED(Hr) ) goto error;
error:
if ( PropertyMan ) delete PropertyMan;
if ( mdHandle ) IISAdminBase->CloseKey( mdHandle );
if ( IISAdminBase ) IISAdminBase->Release();
return Hr;
}
HRESULT AddDllToIISList( SAFEARRAY* Array ) {
//
// Add the ISAPI to the IIS list.
//
HRESULT Hr; WCHAR ExtensionPath[ MAX_PATH ];
DWORD dwRet = GetModuleFileNameW( g_hinst, ExtensionPath, MAX_PATH );
if ( !dwRet ) return HRESULT_FROM_WIN32( GetLastError() );
// Search for the DLL. If its already in the list, do nothing
Hr = SafeArrayLock( Array ); if ( FAILED( Hr ) ) return Hr;
for ( unsigned int i = Array->rgsabound[0].lLbound; i < Array->rgsabound[0].lLbound + Array->rgsabound[0].cElements; i++ ) {
VARIANT & IElem = ((VARIANT*)Array->pvData)[i];
if ( _wcsicmp( (WCHAR*)IElem.bstrVal, ExtensionPath ) == 0 ) { SafeArrayUnlock( Array ); return S_OK; }
}
// Need to add the DLL
SAFEARRAYBOUND SafeBounds; SafeBounds.lLbound = Array->rgsabound[0].lLbound; SafeBounds.cElements = Array->rgsabound[0].cElements+1;
SafeArrayUnlock( Array );
Hr = SafeArrayRedim( Array, &SafeBounds ); if ( FAILED( Hr ) ) return Hr;
VARIANT bstrvar; VariantInit( &bstrvar ); bstrvar.vt = VT_BSTR; bstrvar.bstrVal = SysAllocString( ExtensionPath ); long Index = SafeBounds.lLbound + SafeBounds.cElements - 1;
Hr = SafeArrayPutElement( Array, &Index, (void*)&bstrvar ); VariantClear( &bstrvar ); if ( FAILED( Hr ) ) return Hr;
return S_OK; }
HRESULT RemoveDllFromIISList( SAFEARRAY *Array ) {
// Remove the DLL from the IIS list
HRESULT Hr; WCHAR ExtensionPath[ MAX_PATH ];
DWORD dwRet = GetModuleFileNameW( g_hinst, ExtensionPath, MAX_PATH );
if ( !dwRet ) return HRESULT_FROM_WIN32( GetLastError() );
Hr = SafeArrayLock( Array ); if ( FAILED( Hr ) ) return Hr;
ULONG NewSize = 0; SIZE_T j = Array->rgsabound[0].lLbound; SIZE_T k = Array->rgsabound[0].lLbound + Array->rgsabound[0].cElements; while( j < k ) {
VARIANT & JElem = ((VARIANT*)Array->pvData)[j];
// This element is fine, keep it
if ( 0 != _wcsicmp( (WCHAR*)JElem.bstrVal, ExtensionPath ) ) { NewSize++; j++; }
else {
// find a suitable element to replace the bad element with
while( j < --k ) { VARIANT & KElem = ((VARIANT*)Array->pvData)[k]; if ( 0 != _wcsicmp( (WCHAR*)KElem.bstrVal, ExtensionPath ) ) { // found element. move it
VARIANT temp = JElem; JElem = KElem; KElem = temp; break; } } } }
SAFEARRAYBOUND ArrayBounds; ArrayBounds = Array->rgsabound[0]; ArrayBounds.cElements = NewSize;
SafeArrayUnlock( Array );
Hr = SafeArrayRedim( Array, &ArrayBounds );
if ( FAILED( Hr ) ) return Hr;
return S_OK; }
HRESULT ModifyLockdownList( bool Add ) {
// Toplevel function to modify the IIS lockdown list.
// If Add is 1, then the ISAPI is added. If Add is 0, then the ISAPI is removed.
HRESULT Hr; IADs *Service = NULL; SAFEARRAY* Array = NULL; bool ArrayLocked = false;
VARIANT var; VariantInit( &var );
Hr = ADsGetObject( BSTR( L"IIS://LocalHost/W3SVC" ), __uuidof( IADs ), (void**)&Service ); if ( FAILED( Hr ) ) return Hr;
Hr = Service->Get( g_IsapiRestrictionListBSTR, &var ); if ( FAILED(Hr) ) { // This property doesn't exist on IIS5 or IIS5.1 don't install it
Hr = S_OK; goto cleanup; }
Array = var.parray;
Hr = SafeArrayLock( Array ); if ( FAILED( Hr ) ) goto cleanup; ArrayLocked = true;
if ( !Array->rgsabound[0].cElements ) { // The array has no elements which means no restrictions.
Hr = S_OK; goto cleanup; }
VARIANT & FirstElem = ((VARIANT*)Array->pvData)[ Array->rgsabound[0].lLbound ]; if ( _wcsicmp(L"0", (WCHAR*)FirstElem.bstrVal ) == 0 ) {
//
// According to the IIS6 spec, a 0 means that all ISAPIs are denied except
// those that are explicitly listed.
//
// If installing: add to the list.
// If uninstalling: remove from the list
//
SafeArrayUnlock( Array ); ArrayLocked = false;
if ( Add ) Hr = AddDllToIISList( Array ); else Hr = RemoveDllFromIISList( Array );
if ( FAILED( Hr ) ) goto cleanup;
} else if ( _wcsicmp( L"1", (WCHAR*)FirstElem.bstrVal ) == 0 ) {
//
// According to the IIS6 spec, a 1 means that all ISAPIs are allowed except
// those that are explicitly denied.
//
// If installing: remove from the list
// If uninstalling: Do nothing
//
SafeArrayUnlock( Array ); ArrayLocked = false;
if ( Add ) { Hr = RemoveDllFromIISList( Array );
if ( FAILED( Hr ) ) goto cleanup; }
} else { Hr = E_FAIL; goto cleanup; }
Hr = Service->Put( g_IsapiRestrictionListBSTR, var ); if ( FAILED( Hr ) ) goto cleanup;
Hr = Service->SetInfo(); if ( FAILED( Hr ) ) goto cleanup;
Hr = S_OK; cleanup:
if ( Array && ArrayLocked ) SafeArrayUnlock( Array );
if ( Service ) Service->Release(); VariantClear( &var );
return Hr; }
HRESULT AddToLockdownListDisplayPutString( SAFEARRAY *Array, unsigned long Position, const WCHAR *String ) {
HRESULT Hr; VARIANT Var;
VariantInit( &Var ); Var.vt = VT_BSTR; Var.bstrVal = SysAllocString( String );
if ( !Var.bstrVal ) return E_OUTOFMEMORY;
long Index = (unsigned long)Position; Hr = SafeArrayPutElement( Array, &Index, (void*)&Var );
VariantClear( &Var ); return Hr;
}
HRESULT AddToLockdownListDisplay( SAFEARRAY *Array ) {
HRESULT Hr; WCHAR FilterPath[ MAX_PATH ];
DWORD dwRet = GetModuleFileNameW( g_hinst, FilterPath, MAX_PATH );
if ( !dwRet ) return HRESULT_FROM_WIN32( GetLastError() );
WCHAR ExtensionName[ MAX_PATH ]; if (! LoadStringW(g_hinst, // handle to resource module
IDS_EXTENSION_NAME, // resource identifier
ExtensionName, // resource buffer
MAX_PATH ) ) // size of buffer
return HRESULT_FROM_WIN32( GetLastError() );
//
// Check to see if the ISAPI is already in the list. If it is, don't modify
// list.
//
Hr = SafeArrayLock( Array );
if ( FAILED( Hr ) ) return Hr;
for( unsigned long i = Array->rgsabound[0].lLbound; i < Array->rgsabound[0].lLbound + Array->rgsabound[0].cElements; i++ ) {
VARIANT & CurrentElement = ((VARIANT*)Array->pvData)[ i ]; BSTR BSTRString = CurrentElement.bstrVal;
if ( _wcsicmp( (WCHAR*)BSTRString, FilterPath ) == 0 ) { // ISAPI is already in the list, don't do anything
SafeArrayUnlock( Array ); return S_OK; }
}
SAFEARRAYBOUND SafeArrayBound = Array->rgsabound[0]; unsigned long OldSize = SafeArrayBound.cElements; SafeArrayBound.cElements += 3; SafeArrayUnlock( Array );
Hr = SafeArrayRedim( Array, &SafeArrayBound ); if ( FAILED( Hr ) ) return Hr;
Hr = AddToLockdownListDisplayPutString( Array, OldSize, L"1" ); if ( FAILED( Hr ) ) return Hr;
Hr = AddToLockdownListDisplayPutString( Array, OldSize + 1, FilterPath ); if ( FAILED( Hr ) ) return Hr;
Hr = AddToLockdownListDisplayPutString( Array, OldSize + 2, ExtensionName ); if ( FAILED( Hr ) ) return Hr;
return S_OK; }
HRESULT SafeArrayRemoveSlice( SAFEARRAY *Array, unsigned long lBound, unsigned long uBound ) {
// Remove a slice of an array.
SIZE_T ElementsToRemove = uBound - lBound + 1; HRESULT Hr = SafeArrayLock( Array );
if ( FAILED( Hr ) ) return Hr;
if ( uBound + 1 < Array->rgsabound[0].cElements ) { // At least one element exists above this element
// Step 1, move slice to temp storage
VARIANT *Temp = (VARIANT*)new BYTE[ sizeof(VARIANT) * ElementsToRemove ];
if ( !Temp ) { SafeArrayUnlock( Array ); return E_OUTOFMEMORY; }
memcpy( Temp, &((VARIANT*)Array->pvData)[ lBound ], sizeof(VARIANT)*ElementsToRemove );
// Step 2, collapse hole left by slice
memmove( &((VARIANT*)Array->pvData)[ lBound ], &((VARIANT*)Array->pvData)[ uBound + 1 ], sizeof(VARIANT) * ( Array->rgsabound[0].cElements - ( uBound + 1 ) ) );
// Step 3, move slice to end of array
memcpy( &((VARIANT*)Array->pvData)[ Array->rgsabound[0].cElements - ElementsToRemove ], Temp, sizeof(VARIANT)*ElementsToRemove );
}
SAFEARRAYBOUND SafeArrayBound = Array->rgsabound[0]; SafeArrayBound.cElements -= (ULONG)ElementsToRemove;
SafeArrayUnlock( Array );
return SafeArrayRedim( Array, &SafeArrayBound );
}
HRESULT RemoveFromLockdownListDisplay( SAFEARRAY *Array ) {
HRESULT Hr; WCHAR FilterPath[ MAX_PATH ];
DWORD dwRet = GetModuleFileNameW( g_hinst, FilterPath, MAX_PATH );
if ( !dwRet ) return HRESULT_FROM_WIN32( GetLastError() );
Hr = SafeArrayLock( Array );
if ( FAILED( Hr ) ) return Hr;
for( unsigned int i = Array->rgsabound[0].lLbound; i < Array->rgsabound[0].lLbound + Array->rgsabound[0].cElements; i++ ) {
VARIANT & CurrentElement = ((VARIANT*)Array->pvData)[ i ]; BSTR BSTRString = CurrentElement.bstrVal;
if ( _wcsicmp( (WCHAR*)BSTRString, FilterPath ) == 0 ) { // ISAPI is in the list, remove it
Hr = SafeArrayUnlock( Array ); if ( FAILED( Hr ) ) return Hr;
Hr = SafeArrayRemoveSlice( Array, (i == 0) ? 0 : i - 1, min( i + 1, Array->rgsabound[0].cElements - 1 ) );
return Hr;
}
}
// ISAPI wasn't found. Nothing to do.
SafeArrayUnlock( Array ); return S_OK;
}
HRESULT ModifyLockdownListDisplay( bool Add ) { HRESULT Hr; SAFEARRAY* Array = NULL; IADs *Service = NULL;
VARIANT var; VariantInit( &var );
Hr = ADsGetObject( BSTR( L"IIS://LocalHost/W3SVC" ), __uuidof( IADs ), (void**)&Service ); if ( FAILED( Hr ) ) return Hr;
Hr = Service->Get( g_RestrictionListCustomDescBSTR, &var ); if ( FAILED(Hr) ) { // This property doesn't exist on IIS5 or IIS5.1 don't install or uninstall it
Hr = S_OK; goto cleanup; }
Array = var.parray;
if ( Add ) Hr = AddToLockdownListDisplay( Array ); else Hr = RemoveFromLockdownListDisplay( Array );
if ( FAILED( Hr ) ) goto cleanup;
Hr = Service->Put( g_RestrictionListCustomDescBSTR, var ); if ( FAILED( Hr ) ) goto cleanup;
Hr = Service->SetInfo(); if ( FAILED( Hr ) ) goto cleanup;
cleanup: VariantClear( &var ); if ( Service ) Service->Release();
return Hr; }
HRESULT RemoveFilterIfNeeded() { HRESULT Hr; VARIANT var; VariantInit( &var );
WCHAR *LoadOrder = NULL;
IADsContainer *MbFiltersContainer = NULL; IADs *Object = NULL;
Hr = ADsGetObject( BSTR( L"IIS://LocalHost/W3SVC/Filters" ), __uuidof( IADsContainer), (void**)&MbFiltersContainer ); if ( FAILED( Hr ) ) return Hr;
// Remove bits from the load path
Hr = MbFiltersContainer->QueryInterface( __uuidof(*Object), (void**)&Object );
if ( FAILED( Hr ) ) goto failed;
Hr = Object->Get( g_FilterLoadOrderBSTR, &var );
if ( FAILED( Hr ) ) goto failed;
Hr = VariantChangeType( &var, &var, 0, VT_BSTR );
if ( FAILED( Hr ) ) goto failed;
SIZE_T LoadOrderLength = wcslen( (WCHAR*)var.bstrVal ) + 1; LoadOrder = new WCHAR[ LoadOrderLength ];
if ( !LoadOrder ) { Hr = E_OUTOFMEMORY; goto failed; }
memcpy( LoadOrder, (WCHAR*)var.bstrVal, LoadOrderLength * sizeof( WCHAR ) ); // remove any old bitsserver entries
RemoveFilterHelper( LoadOrder, L",bitsserver" ); RemoveFilterHelper( LoadOrder, L"bitsserver," ); RemoveFilterHelper( LoadOrder, L"bitsserver" ); RemoveFilterHelper( LoadOrder, L",bitserver" ); RemoveFilterHelper( LoadOrder, L"bitserver," ); RemoveFilterHelper( LoadOrder, L"bitserver" );
VariantClear( &var ); var.vt = VT_BSTR; var.bstrVal = SysAllocString( LoadOrder );
if ( !var.bstrVal ) goto failed;
Hr = Object->Put( g_FilterLoadOrderBSTR, var );
if ( FAILED( Hr ) ) goto failed;
Hr = Object->SetInfo();
if ( FAILED( Hr ) ) goto failed;
MbFiltersContainer->Delete( g_IIsFilterBSTR, g_bitsserverBSTR ); MbFiltersContainer->Delete( g_IIsFilterBSTR, g_bitserverBSTR ); Object->SetInfo(); Hr = S_OK;
failed:
if ( MbFiltersContainer ) { MbFiltersContainer->Release(); MbFiltersContainer = NULL; }
if ( Object ) { Object->Release(); Object = NULL; }
return Hr; }
HRESULT ModifyInProcessList( bool Add ) {
// Toplevel function to modify the IIS inprocess list.
// If Add is 1, then the ISAPI is added. If Add is 0, then the ISAPI is removed.
HRESULT Hr; IADs *Service = NULL;
VARIANT var; VariantInit( &var );
Hr = ADsGetObject( BSTR( L"IIS://LocalHost/W3SVC" ), __uuidof( IADs ), (void**)&Service ); if ( FAILED( Hr ) ) return Hr;
Hr = Service->Get( g_InProcessIsapiAppsBSTR, &var ); if ( FAILED(Hr) ) { goto cleanup; }
if ( Add ) Hr = AddDllToIISList( var.parray ); else Hr = RemoveDllFromIISList( var.parray );
Hr = Service->Put( g_InProcessIsapiAppsBSTR, var ); if ( FAILED( Hr ) ) goto cleanup;
Hr = Service->SetInfo(); if ( FAILED( Hr ) ) goto cleanup;
Hr = S_OK; cleanup:
if ( Service ) Service->Release(); VariantClear( &var );
return Hr;
}
HRESULT StartupMSTask() { HRESULT Hr; SC_HANDLE hSC = NULL; SC_HANDLE hSchSvc = NULL; BYTE* ConfigBuffer = NULL; DWORD BytesNeeded = 0;
hSC = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); if (hSC == NULL) { Hr = HRESULT_FROM_WIN32( GetLastError() ); goto exit; } hSchSvc = OpenService(hSC, "Schedule", SERVICE_ALL_ACCESS ); if ( !hSchSvc ) { Hr = HRESULT_FROM_WIN32( GetLastError() ); goto exit; } SERVICE_STATUS SvcStatus; if (QueryServiceStatus(hSchSvc, &SvcStatus) == FALSE) { Hr = HRESULT_FROM_WIN32( GetLastError() ); goto exit; } if (SvcStatus.dwCurrentState == SERVICE_RUNNING) { // Service is already running
Hr = S_OK; goto exit; }
SetLastError( ERROR_SUCCESS );
QueryServiceConfig( hSchSvc, NULL, 0, &BytesNeeded );
if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ) { Hr = HRESULT_FROM_WIN32( GetLastError() ); goto exit; }
ConfigBuffer = new BYTE[ BytesNeeded ];
if ( !ConfigBuffer ) { Hr = E_OUTOFMEMORY; goto exit; }
if ( !QueryServiceConfig( hSchSvc, (LPQUERY_SERVICE_CONFIG)ConfigBuffer, BytesNeeded, &BytesNeeded ) ) { Hr = HRESULT_FROM_WIN32( GetLastError() ); goto exit; }
if ( ((LPQUERY_SERVICE_CONFIG)ConfigBuffer)->dwStartType != SERVICE_AUTO_START ) { if ( !ChangeServiceConfig( hSchSvc, SERVICE_NO_CHANGE, // type of service
SERVICE_AUTO_START, // when to start service
SERVICE_NO_CHANGE, // severity of start failure
NULL, // service binary file name
NULL, // load ordering group name
NULL, // tag identifier
NULL, // array of dependency names
NULL, // account name
NULL, // account password
NULL // display name
) ) { Hr = HRESULT_FROM_WIN32( GetLastError() ); goto exit; }
}
if ( StartService(hSchSvc, 0, NULL) == FALSE ) {
Hr = HRESULT_FROM_WIN32( GetLastError() ); goto exit; }
// Poll for the service to enter the running or error state
Hr = S_OK;
while( 1 ) {
if (QueryServiceStatus(hSchSvc, &SvcStatus) == FALSE) { Hr = HRESULT_FROM_WIN32( GetLastError() ); goto exit; }
if ( SvcStatus.dwCurrentState == SERVICE_STOPPED || SvcStatus.dwCurrentState == SERVICE_PAUSED ) { // Service is already running
Hr = HRESULT_FROM_WIN32( SvcStatus.dwCurrentState ); goto exit; }
if ( SvcStatus.dwCurrentState == SERVICE_RUNNING ) { Hr = S_OK; goto exit; }
}
exit:
if ( ConfigBuffer ) delete[] ConfigBuffer;
if ( hSchSvc ) CloseServiceHandle( hSC );
if ( hSC ) CloseServiceHandle( hSchSvc );
return Hr; }
#if 0
HRESULT ProcessVerbsInIniSection( WCHAR *Section, WCHAR *Verb, WCHAR *FileName, bool Add ) {
HRESULT Hr = S_OK; WCHAR *SectionData = (WCHAR*)new WCHAR[ 32768 ];
if ( !SectionData ) return E_OUTOFMEMORY;
WCHAR *NewSectionData = (WCHAR*)new WCHAR[ 32768 * 2 ]; if ( !NewSectionData ) { Hr = E_OUTOFMEMORY; goto exit; }
DWORD Result = GetPrivateProfileSectionW( Section, // section name
SectionData, // return buffer
32768, // size of return buffer
FileName // initialization file name
);
if ( Result == 32768 - 2 ) { // The buffer is not large enough. Interestingly,
// even urlscan is not capable of handing a section this
// large so just assume the file is corrupt and ignore it.
Hr = S_OK; goto exit; }
if ( Add ) {
// Loop through the list copying it to the new buffer.
// Stop if the verb has already been added.
WCHAR *OriginalVerb = SectionData; WCHAR *NewVerb = NewSectionData;
while( *OriginalVerb ) {
if ( wcscmp( OriginalVerb, Verb ) == 0 ) { // verb already found, no more processing needed
Hr = S_OK; goto exit; }
SIZE_T VerbSize = wcslen( OriginalVerb ) + 1; memcpy( NewVerb, OriginalVerb, sizeof( WCHAR ) * VerbSize ); OriginalVerb += VerbSize; NewVerb += VerbSize; }
// add the verb since it hasn't been added
SIZE_T VerbSize = wcslen( Verb ) + 1; memcpy( NewVerb, Verb, sizeof( WCHAR ) * VerbSize ); NewVerb[ VerbSize ] = '\0'; // end the list
} else {
// Loop though the list copying all nonmatching verbs to the new buffer
// Keep track if list changes
bool ListChanged = false; WCHAR *OriginalVerb = SectionData; WCHAR *NewVerb = NewSectionData;
while( *OriginalVerb ) {
if ( wcscmp( OriginalVerb, Verb ) == 0 ) { // verb to remove, skip it
OriginalVerb += wcslen( OriginalVerb ) + 1; ListChanged = true; } else { // copy the verb
SIZE_T VerbSize = wcslen( OriginalVerb ) + 1; memcpy( NewVerb, OriginalVerb, sizeof( WCHAR ) * VerbSize ); OriginalVerb += VerbSize; NewVerb += VerbSize; }
}
if ( !ListChanged ) { Hr = S_OK; goto exit; }
*NewVerb = '\0'; // end the list
}
if ( !WritePrivateProfileSectionW( Section, // section name
NewSectionData, // data
FileName // file name
) ) { Hr = HRESULT_FROM_WIN32( GetLastError() ); goto exit; }
Hr = S_OK;
exit:
delete[] SectionData; delete[] NewSectionData;
return Hr; }
HRESULT ModifyURLScanFiles( bool Add ) {
// Loop though the list of filters and find valid copies of urlscan.ini
HRESULT Hr = S_OK;
IADsContainer *MbFiltersContainer = NULL; IEnumVARIANT *EnumVariant = NULL; IADs *Filter = NULL; IUnknown *Unknown = NULL; VARIANT Var;
VariantInit( &Var );
Hr = ADsGetObject( BSTR( L"IIS://LocalHost/W3SVC/Filters" ), __uuidof( IADsContainer), (void**)&MbFiltersContainer ); if ( FAILED( Hr ) ) goto exit;
Hr = MbFiltersContainer->get__NewEnum( &Unknown ); if ( FAILED( Hr ) ) goto exit;
Hr = Unknown->QueryInterface( __uuidof( *EnumVariant ), (void**)&EnumVariant ); if ( FAILED( Hr ) ) goto exit;
Unknown->Release(); Unknown = NULL;
while( 1 ) {
ULONG NumberFetched;
Hr = EnumVariant->Next( 1, &Var, &NumberFetched );
if ( FAILED( Hr ) ) goto exit;
if ( S_FALSE == Hr ) { // All the filters were looped though.
Hr = S_OK; goto exit; }
Hr = VariantChangeType( &Var, &Var, 0, VT_UNKNOWN );
if ( FAILED( Hr ) ) goto exit;
Hr = Var.punkVal->QueryInterface( __uuidof( *Filter ), (void**)&Filter );
if ( FAILED( Hr ) ) goto exit;
VariantClear( &Var );
Hr = Filter->Get( (BSTR)L"FilterPath", &Var );
if ( FAILED( Hr ) ) goto exit;
Filter->Release(); Filter = NULL;
Hr = VariantChangeType( &Var, &Var, 0, VT_BSTR );
if ( FAILED( Hr ) ) goto exit;
// Test if this is UrlScan and bash the filepart
WCHAR * FilterPathString = (WCHAR*)Var.bstrVal; SIZE_T FilterPathStringSize = wcslen( FilterPathString ); const WCHAR UrlScanDllName[] = L"urlscan.dll"; const WCHAR UrlScanIniName[] = L"urlscan.ini"; const SIZE_T UrlScanNameSize = sizeof( UrlScanDllName ) / sizeof( *UrlScanDllName );
if ( FilterPathStringSize < UrlScanNameSize ) continue;
WCHAR * FilterPathStringFilePart = FilterPathString + FilterPathStringSize - UrlScanNameSize;
if ( _wcsicmp( FilterPathStringFilePart, UrlScanDllName ) != 0 ) continue;
// this is an urlscan.dll filter, bash the filename to get the ini file name
wcscpy( FilterPathStringFilePart, UrlScanIniName );
WCHAR *IniFileName = FilterPathString;
UINT AllowVerbs = GetPrivateProfileIntW( L"options", L"UseAllowVerbs", -1, IniFileName );
if ( AllowVerbs != 0 && AllowVerbs != 1 ) continue; // missing or broken ini file
if ( AllowVerbs ) Hr = ProcessVerbsInIniSection( L"AllowVerbs", L"BITS_POST", IniFileName, Add ); else Hr = ProcessVerbsInIniSection( L"DenyVerbs", L"BITS_POST", IniFileName, !Add );
}
Hr = S_OK;
exit:
if ( MbFiltersContainer ) MbFiltersContainer->Release();
if ( EnumVariant ) EnumVariant->Release();
if ( Filter ) Filter->Release();
if ( Unknown ) Unknown->Release();
VariantClear( &Var );
return Hr; }
#endif
STDAPI DllRegisterServer() {
//
// Main entry point for setup
//
HRESULT Hr = InitializeSetup(); if ( FAILED( Hr ) ) return Hr;
Hr = RemoveFilterIfNeeded();
if ( FAILED( Hr ) ) return Hr;
Hr = StartupMSTask();
if ( FAILED( Hr ) ) return Hr;
Hr = InstallPropertySchema();
if ( FAILED( Hr ) ) return Hr;
Hr = InstallDefaultValues();
if ( FAILED( Hr ) ) return Hr;
Hr = ModifyLockdownList( true );
if ( FAILED( Hr ) ) return Hr;
Hr = ModifyLockdownListDisplay( true );
if ( FAILED( Hr ) ) return Hr;
Hr = ModifyInProcessList( true );
if ( FAILED( Hr ) ) return Hr;
#if 0
Hr = ModifyURLScanFiles( true );
if ( FAILED( Hr ) ) return Hr;
#endif
Hr = RestartIIS(); CleanupSetup(); return Hr;
}
STDAPI DllUnregisterServer() { //
// Main entry point for setup unregistration
//
HRESULT Hr = RemovePropertySchema();
if ( FAILED(Hr) ) return Hr; Hr = ModifyLockdownList( false );
if ( FAILED( Hr ) ) goto failed;
Hr = ModifyLockdownListDisplay( false );
if ( FAILED( Hr ) ) goto failed;
Hr = ModifyInProcessList( false );
if ( FAILED( Hr ) ) return Hr;
Hr = RestartIIS(); return Hr;
failed: return Hr; }
|