|
|
/************************************************************************
Copyright (c) 2002 Microsoft Corporation
Module Name :
config.cpp
Abstract :
Configuration APIs
Author :
Revision History :
***********************************************************************/
#include "precomp.h"
#include <sddl.h>
#pragma warning( disable : 4355 )
HRESULT GetTypeInfo( const GUID & guid, ITypeInfo **TypeInfo ) {
DWORD Result; HRESULT hr; WCHAR DllName[ MAX_PATH ];
Result = GetModuleFileName( g_hinst, DllName, MAX_PATH - 1 );
if ( !Result ) return HRESULT_FROM_WIN32( GetLastError() );
ITypeLib *TypeLib;
hr = LoadTypeLibEx( DllName, REGKIND_NONE, &TypeLib );
if ( FAILED( hr ) ) return hr;
hr = TypeLib->GetTypeInfoOfGuid( guid, TypeInfo );
TypeLib->Release();
return hr; }
void FreeReturnedWorkItems( ULONG NamesReturned, LPWSTR **ItemNamesPtr ) {
LPWSTR *ItemNames = *ItemNamesPtr;
if ( ItemNames ) {
for( ULONG i = 0; i < NamesReturned; i++ ) { CoTaskMemFree( ItemNames[i] ); }
CoTaskMemFree( ItemNames );
*ItemNamesPtr = NULL;
}
}
void FindWorkItemForVDIR( SmartITaskSchedulerPointer TaskScheduler, LPCWSTR Key, SmartITaskPointer* ReturnedTask, LPWSTR* ReturnedTaskName ) {
HRESULT Hr; SIZE_T KeyLength = sizeof(WCHAR) * ( wcslen( Key ) + 1 ); WORD DataLength; if ( ReturnedTask ) (*ReturnedTask).Clear();
if ( ReturnedTaskName ) *ReturnedTaskName = NULL;
SmartITaskPointer Task; SmartIEnumWorkItemsPointer EnumWorkItems; LPWSTR *ItemNames = NULL; BYTE *ItemData = NULL; ULONG NamesReturned = 0;
try { THROW_COMERROR( TaskScheduler->Enum( EnumWorkItems.GetRecvPointer() ) ); while( 1 ) {
THROW_COMERROR( EnumWorkItems->Next( 255, &ItemNames, &NamesReturned ) );
if ( !NamesReturned ) throw ComError( HRESULT_FROM_WIN32( ERROR_NOT_FOUND ) );
for ( ULONG i = 0; i < NamesReturned; i++ ) {
THROW_COMERROR( TaskScheduler->Activate( ItemNames[i], Task.GetUUID(), (IUnknown**)Task.GetRecvPointer() ) ); THROW_COMERROR( Task->GetWorkItemData( &DataLength, &ItemData ) );
if ( KeyLength == DataLength && ( wcscmp( Key, (WCHAR*)ItemData ) == 0 ) ) {
// Found the item, cleanup and return
if ( ReturnedTask ) *ReturnedTask = Task;
if ( ReturnedTaskName ) { *ReturnedTaskName = ItemNames[i]; ItemNames[i] = NULL; }
FreeReturnedWorkItems( NamesReturned, &ItemNames );
CoTaskMemFree( ItemData ); return; }
CoTaskMemFree( ItemData ); ItemData = NULL;
}
FreeReturnedWorkItems( NamesReturned, &ItemNames ); NamesReturned = 0;
}
} catch( ComError Error ) { FreeReturnedWorkItems( NamesReturned, &ItemNames ); CoTaskMemFree( ItemData );
throw; }
}
WCHAR *BasePathOf( IN WCHAR *pPath ) { WCHAR *pBasePath;
if (!pPath) { return NULL; }
if ( (pBasePath=wcsrchr(pPath,L'/')) || (pBasePath=wcsrchr(pPath,L'\\')) ) { pBasePath++; } else { pBasePath = pPath; }
return pBasePath; }
void CreateWorkItemForVDIR( IN SmartITaskSchedulerPointer TaskScheduler, IN LPWSTR Path, IN LPWSTR Key ) { WORD KeySize = sizeof(WCHAR) * ( wcslen( Key ) + 1 ); WCHAR ItemName[MAX_PATH]; WCHAR ItemCommentFormat[MAX_PATH]; WCHAR ItemComment[2*MAX_PATH]; WCHAR Parameters[4*MAX_PATH];
//
// Use the last part of the path for the item name and description comment.
//
const WCHAR *pBasePath = BasePathOf(Path);
if (!pBasePath || 0==wcslen(pBasePath)) { throw ComError( HRESULT_FROM_WIN32(ERROR_INVALID_NAME) ); }
//
// Construct the description/comment string.
//
DWORD Result; void* InsertArray[2] = { (void*)pBasePath, (void*)Key }; if ( !LoadString(g_hinst, IDS_WORK_ITEM_COMMENT, ItemCommentFormat, MAX_PATH) ) { throw ComError( HRESULT_FROM_WIN32(GetLastError()) ); }
Result = FormatMessage( FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, (LPCVOID)ItemCommentFormat, 0, 0, ItemComment, ARRAY_ELEMENTS(ItemComment), (va_list*)InsertArray );
ItemComment[ ARRAY_ELEMENTS(ItemComment) - 1 ] = L'\0';
if ( !Result ) { throw ComError( HRESULT_FROM_WIN32( GetLastError() ) ); }
//
// Construct the task scheduler item name. Since StringCchPrintfW() is always
// defined to return a (possibly trunctated) buffer, we can ignore the error
// return in this case.
//
StringCchPrintfW( ItemName, ARRAY_ELEMENTS(ItemName), L"BITS_%s_%s", pBasePath, Key );
//
// Construct the runstring for the task.
//
StringCchPrintfW( Parameters, ARRAY_ELEMENTS(Parameters), L"bitsmgr.dll,Cleanup_RunDLL %s \"%s\" %s", Path, ItemName, Key );
WORD TriggerNumber; SmartITaskPointer Task; SmartITaskTriggerPointer TaskTrigger; SmartIPersistFilePointer PersistFile;
try { try { FindWorkItemForVDIR( TaskScheduler, Key, &Task, NULL ); return; // work item already found
} catch( ComError Error ) { if ( HRESULT_FROM_WIN32( ERROR_NOT_FOUND ) != Error.m_Hr ) throw; }
// error not found
THROW_COMERROR( TaskScheduler->NewWorkItem( ItemName, CLSID_CTask, Task.GetUUID(), (IUnknown**)Task.GetRecvPointer() ) );
// Set basic task data
THROW_COMERROR( Task->SetApplicationName( L"%SystemRoot%\\system32\\rundll32.exe" ) ); THROW_COMERROR( Task->SetMaxRunTime( INFINITE ) ); THROW_COMERROR( Task->SetParameters( Parameters ) ); THROW_COMERROR( Task->SetPriority( IDLE_PRIORITY_CLASS ) ); THROW_COMERROR( Task->SetAccountInformation( L"", NULL ) ); //Run as localsystem
THROW_COMERROR( Task->SetFlags( TASK_FLAG_RUN_ONLY_IF_LOGGED_ON | TASK_FLAG_HIDDEN ) ); THROW_COMERROR( Task->SetWorkItemData( KeySize, (BYTE*)Key ) ); Task->SetComment( ItemComment ); // Don't fail if this one fails...
// Set the trigger information. Set start time to now, with a default
// interval of once a day.
THROW_COMERROR( Task->CreateTrigger( &TriggerNumber, TaskTrigger.GetRecvPointer() ) );
SYSTEMTIME LocalTime; GetLocalTime( &LocalTime ); TASK_TRIGGER Trigger; memset( &Trigger, 0, sizeof( Trigger ) ); Trigger.cbTriggerSize = sizeof(Trigger); Trigger.wBeginYear = LocalTime.wYear; Trigger.wBeginMonth = LocalTime.wMonth; Trigger.wBeginDay = LocalTime.wDay; Trigger.wStartHour = LocalTime.wHour; Trigger.wStartMinute = LocalTime.wMinute; Trigger.TriggerType = TASK_TIME_TRIGGER_DAILY; Trigger.MinutesDuration = 24 * 60; // 24 hours per day
Trigger.MinutesInterval = 12 * 60; // twice per day
Trigger.Type.Daily.DaysInterval = 1; THROW_COMERROR( TaskTrigger->SetTrigger( &Trigger ) );
// Commit the changes to disk.
THROW_COMERROR( Task->QueryInterface( PersistFile.GetUUID(), (void**)PersistFile.GetRecvPointer() ) ); THROW_COMERROR( PersistFile->Save( NULL, TRUE ) ); } catch( ComError Error ) { TaskScheduler->Delete( ItemName ); throw; } }
void DeleteWorkItemForVDIR( SmartITaskSchedulerPointer TaskScheduler, LPWSTR Key ) { LPWSTR TaskName = NULL;
try { FindWorkItemForVDIR( TaskScheduler, Key, NULL, &TaskName ); THROW_COMERROR( TaskScheduler->Delete( TaskName ) ); } catch( ComError Error ) { CoTaskMemFree( TaskName ); if ( HRESULT_FROM_WIN32( ERROR_NOT_FOUND ) == Error.m_Hr ) return;
throw; }
}
void ConnectToTaskScheduler( LPWSTR ComputerName, SmartITaskSchedulerPointer * TaskScheduler ) {
THROW_COMERROR( CoCreateInstance( CLSID_CTaskScheduler, NULL, CLSCTX_INPROC_SERVER, (*TaskScheduler).GetUUID(), (void**)(*TaskScheduler).GetRecvPointer() ) );
THROW_COMERROR( (*TaskScheduler)->SetTargetComputer( ComputerName ) );
}
void IsBITSEnabledOnVDir( PropertyIDManager *PropertyManager, IMSAdminBase *IISAdminBase, LPWSTR VirtualDirectory, BOOL *IsEnabled ) { DWORD BufferRequired;
*IsEnabled = false;
DWORD IsEnabledVal; METADATA_RECORD MdRecord; memset( &MdRecord, 0, sizeof( MdRecord ) ); MdRecord.dwMDDataType = DWORD_METADATA; MdRecord.dwMDIdentifier = PropertyManager->GetPropertyMetabaseID( MD_BITS_UPLOAD_ENABLED ); MdRecord.dwMDDataLen = sizeof(IsEnabled); MdRecord.pbMDData = (PBYTE)&IsEnabledVal;
try { THROW_COMERROR( IISAdminBase->GetData( METADATA_MASTER_ROOT_HANDLE, VirtualDirectory, &MdRecord, &BufferRequired ) ); } catch( ComError Error ) { if ( MD_ERROR_DATA_NOT_FOUND == Error.m_Hr || HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) == Error.m_Hr ) return;
throw; } *IsEnabled = IsEnabledVal ? true : false;
}
LPWSTR BITSGetFileOwnerSidString(LPCWSTR szFile) { DWORD cbSizeNeeded = 0; PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL; PSID pOwnerSid = NULL; BOOL fOwnerDefaulted = FALSE; LPWSTR pszSidString = NULL;
try { //
// Retrieve the file owner. Call GetFileSecurity twice - first to get
// the buffer size, then the actual information retrieval.
//
if (!GetFileSecurity(szFile, OWNER_SECURITY_INFORMATION, NULL, 0, &cbSizeNeeded)) { DWORD dwError = GetLastError();
if (dwError != ERROR_INSUFFICIENT_BUFFER) { throw ComError( HRESULT_FROM_WIN32( dwError ) ); } } else { // we don't expect this to ever succeed
throw ComError( E_UNEXPECTED ); }
//
// Allocate the buffer space necessary and retrieve the info.
//
pSecurityDescriptor = reinterpret_cast<SECURITY_DESCRIPTOR *>(new BYTE[cbSizeNeeded]); THROW_OUTOFMEMORY_IFNULL(pSecurityDescriptor);
if (!GetFileSecurity(szFile, OWNER_SECURITY_INFORMATION, pSecurityDescriptor, cbSizeNeeded, &cbSizeNeeded)) { throw ComError( HRESULT_FROM_WIN32( GetLastError() ) ); }
//
// Retrieve & validate the owner sid.
//
if (!GetSecurityDescriptorOwner(pSecurityDescriptor, &pOwnerSid, &fOwnerDefaulted)) { throw ComError( HRESULT_FROM_WIN32( GetLastError() ) ); }
if (!IsValidSid(pOwnerSid)) { throw ComError( HRESULT_FROM_WIN32( GetLastError() ) ); }
if(!ConvertSidToStringSidW(pOwnerSid, &pszSidString)) { throw ComError( HRESULT_FROM_WIN32( GetLastError() ) ); } } catch ( ComError Error ) { if (pSecurityDescriptor) { delete [] reinterpret_cast<BYTE *>(pSecurityDescriptor); pSecurityDescriptor = NULL; }
throw; }
//
// Everthing went fine
//
if (pSecurityDescriptor) { delete [] reinterpret_cast<BYTE *>(pSecurityDescriptor); pSecurityDescriptor = NULL; }
// caller should free this memory
return pszSidString; }
LPWSTR BITSAddAclForDirectoryOwner(LPCWSTR szBaseAcl, LPCWSTR szUserPartialAclPrefix, LPCWSTR szDirectory) { LPCWSTR szUserPartialAclSuffix = L")"; LPWSTR szFullAcl = NULL; DWORD cchFullAcl = 0; LPWSTR pszUserSID = NULL;
try { pszUserSID = BITSGetFileOwnerSidString(szDirectory); cchFullAcl = wcslen(szBaseAcl) + wcslen(szUserPartialAclPrefix) + wcslen(pszUserSID) + wcslen(szUserPartialAclSuffix) + 1;
// ATT: this buffer is being allocated and it should be freed by the caller
szFullAcl = new WCHAR[ cchFullAcl ]; THROW_OUTOFMEMORY_IFNULL(szFullAcl);
StringCchPrintfW(szFullAcl, cchFullAcl, L"%ws%ws%ws%ws", szBaseAcl, szUserPartialAclPrefix, pszUserSID, szUserPartialAclSuffix); } catch( ComError Error ) { //
// Free the String SID obtained by calling ConvertSidToStringSid()
//
if (pszUserSID) { LocalFree(reinterpret_cast<HLOCAL>(pszUserSID)); pszUserSID = NULL; } }
//
// Free the String SID obtained by calling ConvertSidToStringSid()
//
if (pszUserSID) { LocalFree(reinterpret_cast<HLOCAL>(pszUserSID)); pszUserSID = NULL; }
// this string should be freed by the caller
return szFullAcl; }
void BITSCreateDirectory( const WCHAR *Path, const WCHAR *SDString, BOOL fAllowInheritanceFromParent, BOOL fAddOwnerExplicitly ) { PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL; PACL pDacl = NULL; BOOL fDaclPresent = TRUE; BOOL fDaclDefaulted = TRUE; DWORD dwProtectedFlag = 0; DWORD dwError = ERROR_SUCCESS; LPWSTR szExpandedAcl = NULL;
try { //
// Note that we are setting the SecurityDescriptor as NULL initially.
// We will set the security separately via SetNamedSecurityInfo(), otherwise
// the inherited ACLs will not be computed.
//
if (!CreateDirectory(Path, NULL)) { dwError = GetLastError();
// ignore error if directory already exists
if ( ERROR_ALREADY_EXISTS != dwError ) { throw ComError( HRESULT_FROM_WIN32( dwError ) ); } }
//
// If we were given a security descriptor string, use it to set the security permissions
//
if ( SDString ) { if (fAddOwnerExplicitly) { //
// Grab the SID for the Owner of the directory we just created, transform it to string
// format and add it to the SDDL string that we were given.
// We do this in order to guarantee to the owner of the directory the right to
// create subdirectories and files. CO permissions will only last during creation time,
// so it doesn't help in our scenario. This behavior was confirmed by the Security team.
//
szExpandedAcl = BITSAddAclForDirectoryOwner(SDString, BITS_EXPLICITOWNER_PARTIAL_ACL, Path); }
if (!ConvertStringSecurityDescriptorToSecurityDescriptorW( (szExpandedAcl? szExpandedAcl : SDString), // security descriptor string
SDDL_REVISION_1, // revision level
&pSecurityDescriptor, // SD
NULL ) ) // SD size
{ throw ComError( HRESULT_FROM_WIN32( GetLastError() ) ); }
SECURITY_ATTRIBUTES SecurityAttributes = { sizeof( SECURITY_ATTRIBUTES ), pSecurityDescriptor, FALSE };
if (!GetSecurityDescriptorDacl(pSecurityDescriptor, &fDaclPresent, &pDacl, &fDaclDefaulted)) { throw ComError( HRESULT_FROM_WIN32( GetLastError() ) ); }
if (!fDaclPresent || !pDacl) { throw ComError( HRESULT_FROM_WIN32( ERROR_INVALID_DATA ) ); }
//
// Decide if we are going to interrupt the inheritance from the parent or not.
//
dwProtectedFlag = (fAllowInheritanceFromParent? UNPROTECTED_DACL_SECURITY_INFORMATION : PROTECTED_DACL_SECURITY_INFORMATION);
//
// Set the permissions in the directory
//
dwError = SetNamedSecurityInfoW( (WCHAR *)Path, // object name
SE_FILE_OBJECT, // object type
DACL_SECURITY_INFORMATION | dwProtectedFlag, // Security info flags
NULL, // psidOwner
NULL, // psidGroup
pDacl, // pDacl
NULL); // pSacl
if (dwError != ERROR_SUCCESS) { throw ComError( HRESULT_FROM_WIN32( dwError ) ); } } } catch ( ComError Error ) { if ( szExpandedAcl) { delete [] szExpandedAcl; szExpandedAcl = NULL; }
if ( pSecurityDescriptor ) { LocalFree( pSecurityDescriptor ); }
throw; }
//
// Success! Cleanup...
//
if ( szExpandedAcl) { delete [] szExpandedAcl; szExpandedAcl = NULL; }
if ( pSecurityDescriptor ) { LocalFree( pSecurityDescriptor ); } }
void LogDeleteError( DWORD Message, StringHandle Name, HRESULT Hr ) {
HANDLE EventHandle = RegisterEventSource( NULL, // server name
EVENT_LOG_SOURCE_NAME // source name
);
if ( EventHandle ) {
const WCHAR *Strings[] = { (const WCHAR*)Name };
ReportEvent( EventHandle, // handle to event log
EVENTLOG_ERROR_TYPE, // event type
BITSRV_EVENTLOG_CLEANUP_CATAGORY, // event category
Message, // event identifier
NULL, // user security identifier
1, // number of strings to merge
sizeof( Hr ), // size of binary data
Strings, // array of strings to merge
&Hr // binary data buffer
);
DeregisterEventSource( EventHandle );
} }
//---------------------------------------------------------------------------
// DeleteDirectoryTree()
//
// Recursive delete of a directory tree.
//
// Note: Do not follow or delete reparse points.
//---------------------------------------------------------------------------
void DeleteDirectoryTree( IN StringHandle Directory ) {
StringHandle SearchString = Directory + StringHandle(L"\\*"); HANDLE FindHandle = INVALID_HANDLE_VALUE; WIN32_FIND_DATA FindData; WIN32_FILE_ATTRIBUTE_DATA FileAttributes;
try { if (!GetFileAttributesEx(Directory, GetFileExInfoStandard, &FileAttributes)) { throw ComError(HRESULT_FROM_WIN32(GetLastError())); }
// If the specified directory is a reparse point then ignore it.
if (FileAttributes.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { return; }
FindHandle = FindFirstFile( SearchString, &FindData );
if ( INVALID_HANDLE_VALUE == FindHandle ) { throw ComError(HRESULT_FROM_WIN32(GetLastError())); }
do {
// Ignore reparse points.
if ( FindData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ) { continue; }
// Ignore this and parent directory references.
if ( ( _wcsicmp( L".", FindData.cFileName ) == 0 ) || ( _wcsicmp( L"..", FindData.cFileName ) == 0 ) ) { continue; }
StringHandle NewItem = Directory + StringHandle(L"\\") + StringHandle( FindData.cFileName );
if ( FILE_ATTRIBUTE_DIRECTORY & FindData.dwFileAttributes ) { DeleteDirectoryTree( NewItem ); } else { if ( !DeleteFile( NewItem ) ) { HRESULT DeleteHr = HRESULT_FROM_WIN32( GetLastError() ); LogDeleteError( BITSSRV_EVENTLOG_DELETEFILE_ERROR, NewItem, DeleteHr ); } }
} while( FindNextFile( FindHandle, &FindData ) );
FindClose( FindHandle ); FindHandle = INVALID_HANDLE_VALUE;
if ( !RemoveDirectory( Directory ) ) { HRESULT DeleteHr = HRESULT_FROM_WIN32( GetLastError() ); LogDeleteError( BITSSRV_EVENTLOG_REMOVEDIRECTORY_ERROR, Directory, DeleteHr ); }
} catch( const ComError & ) { if ( INVALID_HANDLE_VALUE != FindHandle) { FindClose( FindHandle ); } throw; }
}
void CreateBITSCacheDirectory( PropertyIDManager *PropertyManager, SmartIMSAdminBasePointer IISAdminBase, METADATA_HANDLE MdVDirKey, StringHandle GuidString ) {
DWORD BufferRequired; WCHAR VDirPath[ MAX_PATH ]; WCHAR VDirSessionDir[ MAX_PATH ];
METADATA_RECORD MdRecord; MdRecord.dwMDIdentifier = MD_VR_PATH; MdRecord.dwMDAttributes = METADATA_INHERIT; MdRecord.dwMDUserType = IIS_MD_UT_FILE; MdRecord.dwMDDataType = STRING_METADATA; MdRecord.dwMDDataLen = sizeof( VDirPath ); MdRecord.pbMDData = (unsigned char*)VDirPath; MdRecord.dwMDDataTag = 0;
THROW_COMERROR( IISAdminBase->GetData( MdVDirKey, NULL, &MdRecord, &BufferRequired ) );
MdRecord.dwMDIdentifier = PropertyManager->GetPropertyMetabaseID( MD_BITS_CONNECTION_DIR ); MdRecord.dwMDDataLen = sizeof( VDirSessionDir ); MdRecord.pbMDData = (unsigned char*)VDirSessionDir;
THROW_COMERROR( IISAdminBase->GetData( MdVDirKey, NULL, &MdRecord, &BufferRequired ) );
StringHandle VDirSessionDirPath = StringHandle( VDirPath ) + StringHandle( L"\\" ) + StringHandle( VDirSessionDir ); StringHandle CleanupGuids = VDirSessionDirPath + StringHandle( L"\\" ) + StringHandle( CLEANUP_GUIDS_NAME ); StringHandle CleanupGuidFile = CleanupGuids + StringHandle( L"\\" ) + GuidString;
StringHandle VDirRequestsPath = VDirSessionDirPath + StringHandle( L"\\" ) + StringHandle( REQUESTS_DIR_NAMEW ); StringHandle VDirRepliesPath = VDirSessionDirPath + StringHandle( L"\\" ) + StringHandle( REPLIES_DIR_NAMEW );
//
// Start some filesystem work
//
// *If* our VDir is located in a remote share, use the IIS
// connection account info to connect to the share
//
CAccessRemoteVDir oVDir; oVDir.LoginToUNC( IISAdminBase, MdVDirKey );
try { BITSCreateDirectory( VDirSessionDirPath, BITS_SESSIONS_DIR_ACL, FALSE, // turn on the PROTECTED flag on the ACL, such that inheritance is interupted from the parent
TRUE ); // explicitly add the SID of the creator owner to the ACL. Note that inheritance will be computed
BITSCreateDirectory( CleanupGuids, BITS_CLEANUPGUIDS_DIR_ACL, TRUE, // Let the ACL for this directory inherit from the parent
FALSE );// don't add the SID for the owner. It will be inherited
{
HANDLE GuidFile = CreateFile( CleanupGuidFile, GENERIC_ALL, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
if ( INVALID_HANDLE_VALUE == GuidFile ) throw ComError( HRESULT_FROM_WIN32( GetLastError() ) );
CloseHandle( GuidFile );
}
BITSCreateDirectory( VDirRequestsPath, BITS_REQUESTS_DIR_ACL, TRUE, // Let the ACL for this directory inherit from the parent
FALSE );// don't add the SID for the owner. It will be inherited
BITSCreateDirectory( VDirRepliesPath, BITS_REPLIES_DIR_ACL, TRUE, // Let the ACL for this directory inherit from the parent
FALSE );// don't add the SID for the owner. It will be inherited
} catch( ComError Error ) { // don't let this error propagate with the wrong user
oVDir.RevertFromUNCAccount(); throw; }
//
// Done with the filesystem access
//
oVDir.RevertFromUNCAccount();
StringHandle SessionDirKeyPath = StringHandle( VDirSessionDir ); StringHandle RequestsDirKeyPath = SessionDirKeyPath + StringHandle( L"\\" ) + StringHandle( REQUESTS_DIR_NAMEW ); StringHandle RepliesDirKeyPath = SessionDirKeyPath + StringHandle( L"\\" ) + StringHandle( REPLIES_DIR_NAMEW );
{ HRESULT Hr = IISAdminBase->AddKey( MdVDirKey, SessionDirKeyPath );
if ( FAILED( Hr ) && ( HRESULT_FROM_WIN32( ERROR_DUP_NAME ) != Hr ) ) throw ComError( Hr ); }
{
HRESULT Hr = IISAdminBase->AddKey( MdVDirKey, RepliesDirKeyPath );
if ( FAILED( Hr ) && ( HRESULT_FROM_WIN32( ERROR_DUP_NAME ) != Hr ) ) throw ComError( Hr ); } DWORD AccessPermission = 0;
MdRecord.dwMDIdentifier = MD_ACCESS_PERM; MdRecord.dwMDAttributes = METADATA_INHERIT; MdRecord.dwMDUserType = IIS_MD_UT_FILE; MdRecord.dwMDDataType = DWORD_METADATA; MdRecord.dwMDDataLen = sizeof( AccessPermission ); MdRecord.pbMDData = (unsigned char*)&AccessPermission; MdRecord.dwMDDataTag = 0;
THROW_COMERROR( IISAdminBase->SetData( MdVDirKey, //metadata handle..
SessionDirKeyPath, //path of the key relative to hMDHandle.
&MdRecord ) );
AccessPermission = 1; // read only permissions
THROW_COMERROR( IISAdminBase->SetData( MdVDirKey, //metadata handle..
RepliesDirKeyPath, //path of the key relative to hMDHandle.
&MdRecord ) );
//
// Set BITS-Sessions to disable browse.
//
DWORD BrowsePermission = 0;
MdRecord.dwMDIdentifier = MD_DIRECTORY_BROWSING; MdRecord.dwMDAttributes = METADATA_INHERIT; MdRecord.dwMDUserType = IIS_MD_UT_FILE; MdRecord.dwMDDataType = DWORD_METADATA; MdRecord.dwMDDataLen = sizeof( BrowsePermission ); MdRecord.pbMDData = (unsigned char*)&BrowsePermission; MdRecord.dwMDDataTag = 0;
THROW_COMERROR( IISAdminBase->GetData( MdVDirKey, NULL, &MdRecord, &BufferRequired ) );
BrowsePermission &= ~MD_DIRBROW_ENABLED; MdRecord.dwMDAttributes &= ~METADATA_ISINHERITED;
THROW_COMERROR( IISAdminBase->SetData( MdVDirKey, SessionDirKeyPath, &MdRecord ) ); }
void DeleteBITSCacheDirectory( PropertyIDManager *PropertyManager, SmartIMSAdminBasePointer IISAdminBase, METADATA_HANDLE MdVDirKey, const WCHAR *szObjectPath ) {
DWORD BufferRequired; WCHAR VDirPath[ MAX_PATH ]; WCHAR VDirSessionDir[ MAX_PATH ];
METADATA_RECORD MdRecord; MdRecord.dwMDIdentifier = MD_VR_PATH; MdRecord.dwMDAttributes = METADATA_INHERIT; MdRecord.dwMDUserType = IIS_MD_UT_FILE; MdRecord.dwMDDataType = STRING_METADATA; MdRecord.dwMDDataLen = sizeof( VDirPath ); MdRecord.pbMDData = (unsigned char*)VDirPath; MdRecord.dwMDDataTag = 0;
THROW_COMERROR( IISAdminBase->GetData( MdVDirKey, NULL, &MdRecord, &BufferRequired ) );
MdRecord.dwMDIdentifier = PropertyManager->GetPropertyMetabaseID( MD_BITS_CONNECTION_DIR ); MdRecord.dwMDDataLen = sizeof( VDirSessionDir ); MdRecord.pbMDData = (unsigned char*)VDirSessionDir;
THROW_COMERROR( IISAdminBase->GetData( MdVDirKey, NULL, &MdRecord, &BufferRequired ) );
WCHAR GuidString[ 255 ];
{
MdRecord.dwMDDataType = STRING_METADATA; MdRecord.dwMDAttributes = METADATA_NO_ATTRIBUTES; MdRecord.dwMDUserType = PropertyManager->GetPropertyUserType( MD_BITS_CLEANUP_WORKITEM_KEY ); MdRecord.dwMDIdentifier = PropertyManager->GetPropertyMetabaseID( MD_BITS_CLEANUP_WORKITEM_KEY ); MdRecord.dwMDDataLen = sizeof( GuidString ); MdRecord.pbMDData = (PBYTE)GuidString; MdRecord.dwMDDataTag = 0;
HRESULT Hr = IISAdminBase->GetData( MdVDirKey, NULL, &MdRecord, &BufferRequired );
if ( MD_ERROR_DATA_NOT_FOUND == Hr ) return; // The cache directory was never created.
THROW_COMERROR( Hr ); }
StringHandle VDirSessionDirPath = StringHandle( VDirPath ) + StringHandle( L"\\" ) + StringHandle( VDirSessionDir ); StringHandle CleanupGuids = VDirSessionDirPath + StringHandle( L"\\" ) + StringHandle( CLEANUP_GUIDS_NAME ); StringHandle CleanupGuidFile = CleanupGuids + StringHandle( L"\\" ) + GuidString;
//
// Prepare to do some filesystem work
//
// *If* our VDir is located in a remote share, use the IIS
// connection account info to impersonate that user
CAccessRemoteVDir oVDir;
oVDir.LoginToUNC( IISAdminBase, MdVDirKey );
try { DeleteFile( CleanupGuidFile );
BOOL RemovedCleanupDirs = RemoveDirectory( CleanupGuids );
if ( RemovedCleanupDirs || ERROR_PATH_NOT_FOUND == GetLastError() || ERROR_FILE_NOT_FOUND == GetLastError() ) { // This is the last "enlistment"
DeleteDirectoryTree( VDirSessionDirPath ); } } catch( ComError Error ) { // don't let this error propagate with the wrong user
oVDir.RevertFromUNCAccount(); throw; }
//
// Done with the filesystem access
//
oVDir.RevertFromUNCAccount();
IISAdminBase->DeleteKey( MdVDirKey, VDirSessionDir );
}
void DeleteOldBITSCacheDirectory( PropertyIDManager *PropertyManager, SmartIMSAdminBasePointer IISAdminBase, METADATA_HANDLE MdVDirKey, const WCHAR *szObjectPath ) {
DWORD BufferRequired; WCHAR VDirPath[ MAX_PATH ]; WCHAR VDirSessionDir[ MAX_PATH ];
METADATA_RECORD MdRecord; MdRecord.dwMDIdentifier = MD_VR_PATH; MdRecord.dwMDAttributes = METADATA_INHERIT; MdRecord.dwMDUserType = IIS_MD_UT_FILE; MdRecord.dwMDDataType = STRING_METADATA; MdRecord.dwMDDataLen = sizeof( VDirPath ); MdRecord.pbMDData = (unsigned char*)VDirPath; MdRecord.dwMDDataTag = 0;
THROW_COMERROR( IISAdminBase->GetData( MdVDirKey, NULL, &MdRecord, &BufferRequired ) );
MdRecord.dwMDIdentifier = PropertyManager->GetPropertyMetabaseID( MD_BITS_CONNECTION_DIR ); MdRecord.dwMDDataLen = sizeof( VDirSessionDir ); MdRecord.pbMDData = (unsigned char*)VDirSessionDir;
THROW_COMERROR( IISAdminBase->GetData( MdVDirKey, NULL, &MdRecord, &BufferRequired ) );
StringHandle VDirSessionDirPath = StringHandle( VDirPath ) + StringHandle( L"\\" ) + StringHandle( VDirSessionDir ); StringHandle VDirSessionDirPath2 = StringHandle( VDirPath ) + StringHandle( L"\\" ) + StringHandle( VDirSessionDir ) + StringHandle(L".bak");
StringHandle DirectoryToDelete;
//
// Prepare to do some filesystem work
//
// *If* our VDir is located in a remote share, use the IIS
// connection account info to impersonate that user
CAccessRemoteVDir oVDir;
oVDir.LoginToUNC( IISAdminBase, MdVDirKey );
try { if ( !MoveFileEx( VDirSessionDirPath, VDirSessionDirPath2, 0 ) ) {
DWORD dwError = GetLastError();
if ( ERROR_PATH_NOT_FOUND == dwError || ERROR_FILE_NOT_FOUND == dwError ) { oVDir.RevertFromUNCAccount(); return; }
DirectoryToDelete = VDirSessionDirPath;
} else { DirectoryToDelete = VDirSessionDirPath2; }
DeleteDirectoryTree( DirectoryToDelete ); } catch( ComError Error ) { // don't let this error propagate with the wrong user
oVDir.RevertFromUNCAccount(); throw; }
//
// Done with the filesystem access
//
oVDir.RevertFromUNCAccount(); }
void GetVDirPropertyVersion( PropertyIDManager *PropertyManager, SmartIMSAdminBasePointer IISAdminBase, METADATA_HANDLE MdVDirKey, bool * pIsEnabled, DWORD * pdwVersion ) { *pIsEnabled = false; *pdwVersion = 0;
HRESULT Hr; DWORD IsEnabled = 0; METADATA_RECORD MdRecord; DWORD BufferRequired;
MdRecord.dwMDIdentifier = PropertyManager->GetPropertyMetabaseID( MD_BITS_UPLOAD_ENABLED ); MdRecord.dwMDAttributes = METADATA_NO_ATTRIBUTES; MdRecord.dwMDUserType = ALL_METADATA; MdRecord.dwMDDataType = DWORD_METADATA; MdRecord.dwMDDataLen = sizeof(IsEnabled); MdRecord.pbMDData = (PBYTE)&IsEnabled; MdRecord.dwMDDataTag = 0;
Hr = IISAdminBase->GetData( MdVDirKey, NULL, &MdRecord, &BufferRequired );
if ( FAILED( Hr ) ) { if ( !( MD_ERROR_DATA_NOT_FOUND == Hr || HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) == Hr ) ) throw ComError( Hr );
}
*pIsEnabled = !!IsEnabled;
MdRecord.dwMDIdentifier = PropertyManager->GetPropertyMetabaseID( MD_BITS_UPLOAD_METADATA_VERSION ); MdRecord.dwMDDataLen = sizeof(*pdwVersion); MdRecord.pbMDData = (PBYTE)pdwVersion;
Hr = IISAdminBase->GetData( MdVDirKey, NULL, &MdRecord, &BufferRequired );
if ( FAILED( Hr ) ) { if ( !( MD_ERROR_DATA_NOT_FOUND == Hr || HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) == Hr ) ) throw ComError( Hr );
}
}
void SetVDirEnabled( PropertyIDManager *PropertyManager, SmartIMSAdminBasePointer IISAdminBase, METADATA_HANDLE MdVDirKey ) {
METADATA_RECORD MdRecord; DWORD EnableData = 1; DWORD MetadataVersion = CURRENT_UPLOAD_METADATA_VERSION; MdRecord.dwMDIdentifier = PropertyManager->GetPropertyMetabaseID( MD_BITS_UPLOAD_METADATA_VERSION ); MdRecord.dwMDAttributes = METADATA_NO_ATTRIBUTES; MdRecord.dwMDUserType = PropertyManager->GetPropertyUserType( MD_BITS_UPLOAD_METADATA_VERSION ); MdRecord.dwMDDataType = DWORD_METADATA; MdRecord.dwMDDataLen = sizeof(MetadataVersion); MdRecord.pbMDData = (PBYTE)&MetadataVersion; MdRecord.dwMDDataTag = 0;
THROW_COMERROR( IISAdminBase->SetData( MdVDirKey, NULL, &MdRecord ) );
MdRecord.dwMDIdentifier = PropertyManager->GetPropertyMetabaseID( MD_BITS_UPLOAD_ENABLED ); MdRecord.dwMDUserType = PropertyManager->GetPropertyUserType( MD_BITS_UPLOAD_ENABLED ); MdRecord.dwMDDataLen = sizeof(EnableData); MdRecord.pbMDData = (PBYTE)&EnableData;
THROW_COMERROR( IISAdminBase->SetData( MdVDirKey, NULL, &MdRecord ) );
}
void EnableBITSForVDIR( PropertyIDManager *PropertyManager, SmartIMSAdminBasePointer IISAdminBase, LPWSTR Path ) {
HRESULT Hr; METADATA_RECORD MdRecord; METADATA_HANDLE MdVDirKey = NULL; LPWSTR NewScriptMapBuffer = NULL; SmartITaskSchedulerPointer TaskScheduler; DWORD BufferRequired;
bool IsEnabled = 0; DWORD MetadataVersion = 0; try {
THROW_COMERROR( IISAdminBase->OpenKey( METADATA_MASTER_ROOT_HANDLE, Path, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE, METABASE_OPEN_KEY_TIMEOUT, &MdVDirKey ) );
GetVDirPropertyVersion( PropertyManager, IISAdminBase, MdVDirKey, &IsEnabled, &MetadataVersion );
if ( IsEnabled ) {
if ( MetadataVersion >= CURRENT_UPLOAD_METADATA_VERSION ) { // Nothing to do, just leave.
IISAdminBase->CloseKey( MdVDirKey ); return; }
IISAdminBase->CloseKey( MdVDirKey ); MdVDirKey = NULL;
DisableBITSForVDIR( PropertyManager, IISAdminBase, Path, false, true );
EnableBITSForVDIR( PropertyManager, IISAdminBase, Path );
return; }
// Generate the new GUID string
WCHAR GuidString[ 255 ];
// first try looking up the guid
MdRecord.dwMDAttributes = METADATA_NO_ATTRIBUTES; MdRecord.dwMDDataType = STRING_METADATA; MdRecord.dwMDUserType = PropertyManager->GetPropertyUserType( MD_BITS_CLEANUP_WORKITEM_KEY ); MdRecord.dwMDIdentifier = PropertyManager->GetPropertyMetabaseID( MD_BITS_CLEANUP_WORKITEM_KEY ); MdRecord.dwMDDataLen = sizeof( GuidString ); MdRecord.pbMDData = (PBYTE)GuidString; MdRecord.dwMDDataTag = 0; Hr = IISAdminBase->GetData( MdVDirKey, NULL, &MdRecord, &BufferRequired );
if ( MD_ERROR_DATA_NOT_FOUND == Hr || HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) == Hr ) {
// create a new guid and save it away
GUID guid; THROW_COMERROR( CoCreateGuid( &guid ) ); StringFromGUID2( guid, GuidString, 254 ); MdRecord.dwMDDataLen = sizeof(WCHAR) * ( wcslen(GuidString) + 1 ); MdRecord.pbMDData = (PBYTE)GuidString;
THROW_COMERROR( IISAdminBase->SetData( MdVDirKey, NULL, &MdRecord ) );
}
else if ( FAILED( Hr ) ) throw ComError( Hr );
// build the string to add to the scriptmap
WCHAR SystemDir[ MAX_PATH + 1 ];
if (!GetSystemDirectoryW( SystemDir, MAX_PATH ) ) throw ComError( HRESULT_FROM_WIN32( GetLastError() ) );
SystemDir[ MAX_PATH ] = L'\0'; WCHAR ScriptMapString[ MAX_PATH * 2 + 1 ];
StringCchPrintfW( ScriptMapString, ARRAY_ELEMENTS( ScriptMapString ), L"*,%s\\bitssrv.dll,1," BITS_COMMAND_VERBW, SystemDir );
int RetChars = wcslen( ScriptMapString ); ScriptMapString[ RetChars ] = L'\0'; ScriptMapString[ RetChars + 1] = L'\0';
RetChars += 2; // ScriptMapScript is now double NULL terminated
CreateBITSCacheDirectory( PropertyManager, IISAdminBase, MdVDirKey, StringHandle( GuidString ) );
DWORD AccessFlags; MdRecord.dwMDIdentifier = MD_ACCESS_PERM; MdRecord.dwMDAttributes = METADATA_INHERIT; MdRecord.dwMDUserType = IIS_MD_UT_FILE; MdRecord.dwMDDataType = DWORD_METADATA; MdRecord.dwMDDataLen = sizeof( AccessFlags ); MdRecord.pbMDData = (unsigned char*)&AccessFlags; MdRecord.dwMDDataTag = 0;
try { THROW_COMERROR( IISAdminBase->GetData( MdVDirKey, NULL, &MdRecord, &BufferRequired ) ); } catch( ComError Error ) { if ( MD_ERROR_DATA_NOT_FOUND == Error.m_Hr || HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) == Error.m_Hr ) { AccessFlags = 0; } else throw; }
if ( AccessFlags & ( MD_ACCESS_SCRIPT | MD_ACCESS_EXECUTE ) ) { AccessFlags &= ~( MD_ACCESS_SCRIPT | MD_ACCESS_EXECUTE ); MdRecord.dwMDAttributes &= ~METADATA_ISINHERITED;
THROW_COMERROR( IISAdminBase->SetData( MdVDirKey, NULL, &MdRecord ) );
}
//
// retrieve the current scriptmap adding room to the allocated memory
//
memset( &MdRecord, 0, sizeof( MdRecord ) );
MdRecord.dwMDDataType = MULTISZ_METADATA; MdRecord.dwMDAttributes = METADATA_INHERIT; MdRecord.dwMDUserType = IIS_MD_UT_FILE; MdRecord.dwMDIdentifier = MD_SCRIPT_MAPS; MdRecord.dwMDDataLen = 0; MdRecord.pbMDData = (PBYTE)NULL; MdRecord.dwMDDataTag = 0;
Hr = IISAdminBase->GetData( MdVDirKey, NULL, &MdRecord, &BufferRequired );
if ( MD_ERROR_DATA_NOT_FOUND == Hr || HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) == Hr ) { // The Current key doesn't exist.
MdRecord.pbMDData = (PBYTE)ScriptMapString; MdRecord.dwMDDataLen = RetChars * sizeof(WCHAR); } else if ( HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER ) == Hr ) {
NewScriptMapBuffer = new WCHAR[ ( BufferRequired / sizeof(WCHAR) ) + RetChars ]; MdRecord.pbMDData = (PBYTE)NewScriptMapBuffer; MdRecord.dwMDDataLen = BufferRequired + ( RetChars * sizeof(WCHAR) );
THROW_COMERROR( IISAdminBase->GetData( MdVDirKey, NULL, &MdRecord, &BufferRequired ) );
// append script entry at the end
for( WCHAR *p = NewScriptMapBuffer; *p != 0; p += ( wcslen( p ) + 1 ) ); memcpy( p, ScriptMapString, RetChars * sizeof(WCHAR) );
MdRecord.pbMDData = (PBYTE)NewScriptMapBuffer; MdRecord.dwMDDataLen = (DWORD)( ( (char*)p - (char*)NewScriptMapBuffer ) + ( RetChars * sizeof(WCHAR) ) ); } else throw ComError( Hr );
THROW_COMERROR( IISAdminBase->SetData( MdVDirKey, NULL, &MdRecord ) );
// Create the task scheduler cleanup work item
ConnectToTaskScheduler( NULL, &TaskScheduler ); CreateWorkItemForVDIR( TaskScheduler, Path, GuidString );
delete[] NewScriptMapBuffer; NewScriptMapBuffer = NULL;
SetVDirEnabled( PropertyManager, IISAdminBase, MdVDirKey );
IISAdminBase->CloseKey( MdVDirKey ); } catch( ComError Exception ) {
if ( MdVDirKey ) { delete[] NewScriptMapBuffer; IISAdminBase->CloseKey( MdVDirKey );
try { DisableBITSForVDIR( PropertyManager, IISAdminBase, Path, true, false );
} catch( const ComError & ) { } } throw; }
}
void DisableBITSForVDIR( PropertyIDManager *PropertyManager, SmartIMSAdminBasePointer IISAdminBase, LPCWSTR Path, bool RollbackCleanup, bool DisableForUpgrade ) {
METADATA_HANDLE MdVDirKey = NULL; LPWSTR OriginalScriptMap = NULL; LPWSTR NewScriptMap = NULL; SmartITaskSchedulerPointer TaskScheduler;
try {
#if 0
if ( !RollbackCleanup && !DisableForUpgrade ) CleanupForRemoval( Path ); #endif
// build the string to add to the scriptmap
WCHAR SystemDir[ MAX_PATH + 1 ];
if (!GetSystemDirectoryW( SystemDir, MAX_PATH ) ) throw ComError( HRESULT_FROM_WIN32( GetLastError() ) );
WCHAR ScriptMapString[ MAX_PATH * 2 + 1 ];
StringCchPrintfW( ScriptMapString, MAX_PATH * 2 + 1, L"*,%s\\bitssrv.dll,1,BITS_COMMAND", SystemDir );
int RetChars = wcslen( ScriptMapString ); ScriptMapString[ RetChars ] = L'\0'; ScriptMapString[ RetChars + 1] = L'\0';
// ScriptMapScript is now double NULL terminated
WCHAR ScriptMapString2[ MAX_PATH * 2 + 1];
StringCchPrintfW( ScriptMapString2, ARRAY_ELEMENTS( ScriptMapString2 ), L"*,%\\bitsserver.dll,1,BITS_COMMAND", SystemDir );
RetChars = wcslen( ScriptMapString2 ); ScriptMapString2[ RetChars ] = L'\0'; ScriptMapString2[ RetChars + 1 ] = L'\0';
// ScriptMapScript2 is not double NULL terminated
WCHAR ScriptMapString3[ MAX_PATH * 2 + 1 ];
StringCchPrintfW( ScriptMapString3, ARRAY_ELEMENTS( ScriptMapString3 ), L"*,%s\\bitssrv.dll,1," BITS_COMMAND_VERBW, SystemDir ); RetChars = wcslen( ScriptMapString3 ); ScriptMapString3[ RetChars ] = L'\0'; ScriptMapString3[ RetChars + 1] = L'\0';
// ScriptMapScript3 is now double NULL terminated
THROW_COMERROR( IISAdminBase->OpenKey( METADATA_MASTER_ROOT_HANDLE, Path, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE, METABASE_OPEN_KEY_TIMEOUT, &MdVDirKey ) );
if ( DisableForUpgrade ) {
DeleteOldBITSCacheDirectory( PropertyManager, IISAdminBase, MdVDirKey, Path );
} else {
DeleteBITSCacheDirectory( PropertyManager, IISAdminBase, MdVDirKey, Path );
}
//
// retrieve the current scriptmap adding room to the allocated memory
//
DWORD BufferRequired;
METADATA_RECORD MdRecord; memset( &MdRecord, 0, sizeof( MdRecord ) );
MdRecord.dwMDDataType = MULTISZ_METADATA; MdRecord.dwMDAttributes = METADATA_INHERIT; MdRecord.dwMDUserType = IIS_MD_UT_FILE; MdRecord.dwMDIdentifier = MD_SCRIPT_MAPS; MdRecord.dwMDDataLen = 0; MdRecord.pbMDData = (PBYTE)NULL;
HRESULT Hr = IISAdminBase->GetData( MdVDirKey, NULL, &MdRecord, &BufferRequired );
if ( HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER ) != Hr ) throw ComError( Hr );
OriginalScriptMap = new WCHAR[ BufferRequired / 2 + 2 ]; NewScriptMap = new WCHAR[ BufferRequired / 2 + 2 ];
OriginalScriptMap[0] = OriginalScriptMap[1] = L'\0';
MdRecord.dwMDDataLen = BufferRequired; MdRecord.pbMDData = (PBYTE)OriginalScriptMap;
THROW_COMERROR( IISAdminBase->GetData( MdVDirKey, NULL, &MdRecord, &BufferRequired ) );
// Copy the orignal Scriptmap to the new scriptmap
// removing bits goo in the process.
LPWSTR CurrentOriginalItem = OriginalScriptMap; LPWSTR CurrentNewItem = NewScriptMap;
for( ;L'\0' != *CurrentOriginalItem; CurrentOriginalItem += ( wcslen( CurrentOriginalItem ) + 1 ) ) {
if ( _wcsicmp( CurrentOriginalItem, ScriptMapString ) == 0 ) continue; //remove this item
if ( _wcsicmp( CurrentOriginalItem, ScriptMapString2 ) == 0 ) continue;
if ( _wcsicmp( CurrentOriginalItem, ScriptMapString3 ) == 0 ) continue;
SIZE_T CurrentOriginalItemSize = wcslen( CurrentOriginalItem ) + 1; memcpy( CurrentNewItem, CurrentOriginalItem, CurrentOriginalItemSize * sizeof( WCHAR ) ); CurrentNewItem += CurrentOriginalItemSize;
}
// Add the extra 0
*CurrentNewItem++ = L'\0';
MdRecord.dwMDDataLen = (DWORD)( (char*)CurrentNewItem - (char*)NewScriptMap ); MdRecord.pbMDData = (PBYTE)NewScriptMap;
// set the new scriptmap
THROW_COMERROR( IISAdminBase->SetData( MdVDirKey, NULL, &MdRecord ) );
// Set the enabled property first
DWORD EnableData = 0; METADATA_RECORD MdEnabledRecord;
MdEnabledRecord.dwMDAttributes = METADATA_NO_ATTRIBUTES; MdEnabledRecord.dwMDDataType = DWORD_METADATA; MdEnabledRecord.dwMDUserType = PropertyManager->GetPropertyUserType( MD_BITS_UPLOAD_ENABLED ); MdEnabledRecord.dwMDIdentifier = PropertyManager->GetPropertyMetabaseID( MD_BITS_UPLOAD_ENABLED ); MdEnabledRecord.dwMDDataLen = sizeof(EnableData); MdEnabledRecord.pbMDData = (PBYTE)&EnableData; MdEnabledRecord.dwMDDataTag = 0;
THROW_COMERROR( IISAdminBase->SetData( MdVDirKey, NULL, &MdEnabledRecord ) );
if ( !DisableForUpgrade ) {
WCHAR GuidString[ 255 ]; memset( &MdRecord, 0, sizeof( MdRecord ) );
MdRecord.dwMDDataType = STRING_METADATA; MdRecord.dwMDAttributes = METADATA_NO_ATTRIBUTES; MdRecord.dwMDUserType = PropertyManager->GetPropertyUserType( MD_BITS_CLEANUP_WORKITEM_KEY ); MdRecord.dwMDIdentifier = PropertyManager->GetPropertyMetabaseID( MD_BITS_CLEANUP_WORKITEM_KEY ); MdRecord.dwMDDataLen = sizeof( GuidString ); MdRecord.pbMDData = (PBYTE)GuidString;
Hr = IISAdminBase->GetData( MdVDirKey, NULL, &MdRecord, &BufferRequired );
if ( FAILED( Hr ) && Hr != MD_ERROR_DATA_NOT_FOUND ) throw ComError( Hr );
if ( SUCCEEDED( Hr ) ) {
try { ConnectToTaskScheduler( NULL, &TaskScheduler ); DeleteWorkItemForVDIR( TaskScheduler, GuidString );
THROW_COMERROR( IISAdminBase->DeleteData( MdVDirKey, NULL, PropertyManager->GetPropertyMetabaseID( MD_BITS_CLEANUP_WORKITEM_KEY ), ALL_METADATA ) );
} catch( const ComError & ) { if ( !RollbackCleanup ) throw; }
}
}
delete[] OriginalScriptMap; delete[] NewScriptMap;
IISAdminBase->CloseKey( MdVDirKey ); MdVDirKey = NULL;
} catch( ComError Exception ) { delete[] OriginalScriptMap; delete[] NewScriptMap;
if ( MdVDirKey ) IISAdminBase->CloseKey( MdVDirKey ); throw; }
}
void FindWorkItemForVDIR( PropertyIDManager *PropertyManager, SmartIMSAdminBasePointer AdminBase, LPCWSTR Path, LPWSTR *ReturnedTaskName ) {
if ( ReturnedTaskName ) *ReturnedTaskName = NULL;
try { WCHAR GuidString[ 255 ]; DWORD BufferRequired; METADATA_RECORD MdRecord; HRESULT Hr;
MdRecord.dwMDDataType = STRING_METADATA; MdRecord.dwMDAttributes = METADATA_NO_ATTRIBUTES; MdRecord.dwMDUserType = PropertyManager->GetPropertyUserType( MD_BITS_CLEANUP_WORKITEM_KEY ); MdRecord.dwMDIdentifier = PropertyManager->GetPropertyMetabaseID( MD_BITS_CLEANUP_WORKITEM_KEY ); MdRecord.dwMDDataLen = sizeof( GuidString ); MdRecord.pbMDData = (PBYTE)GuidString; MdRecord.dwMDDataTag = 0;
THROW_COMERROR( AdminBase->GetData( METADATA_MASTER_ROOT_HANDLE, Path, &MdRecord, &BufferRequired ) );
SmartITaskSchedulerPointer TaskScheduler; ConnectToTaskScheduler( NULL, &TaskScheduler );
FindWorkItemForVDIR( TaskScheduler, GuidString, NULL, ReturnedTaskName ); } catch( ComError Error ) { // simply return NULL if the task item isn't found.
if ( MD_ERROR_DATA_NOT_FOUND == Error.m_Hr || HRESULT_FROM_WIN32( ERROR_NOT_FOUND ) == Error.m_Hr ) throw ComError( S_FALSE ); }
}
CBITSExtensionSetupFactory::CBITSExtensionSetupFactory() : m_cref(1), m_TypeInfo(NULL) { OBJECT_CREATED } CBITSExtensionSetupFactory::~CBITSExtensionSetupFactory() { if ( m_TypeInfo ) m_TypeInfo->Release();
OBJECT_DESTROYED }
STDMETHODIMP CBITSExtensionSetupFactory::QueryInterface(REFIID riid, LPVOID *ppv) { if (!ppv) return E_FAIL; *ppv = NULL; if (IsEqualIID(riid, IID_IUnknown)) *ppv = static_cast<IUnknown *>(this); else if (IsEqualIID(riid, __uuidof(IBITSExtensionSetupFactory))) *ppv = static_cast<IBITSExtensionSetupFactory *>(this); if (*ppv) { reinterpret_cast<IUnknown *>(*ppv)->AddRef(); return S_OK; } return E_NOINTERFACE; }
STDMETHODIMP_(ULONG) CBITSExtensionSetupFactory::AddRef() { return InterlockedIncrement((LONG *)&m_cref); }
STDMETHODIMP_(ULONG) CBITSExtensionSetupFactory::Release() { if (InterlockedDecrement((LONG *)&m_cref) == 0) { // we need to decrement our object count in the DLL
delete this; return 0; } return m_cref; }
HRESULT CBITSExtensionSetupFactory::LoadTypeInfo() {
if ( m_TypeInfo ) return S_OK;
return ::GetTypeInfo( __uuidof( IBITSExtensionSetupFactory ), &m_TypeInfo );
}
STDMETHODIMP CBITSExtensionSetupFactory::GetIDsOfNames( REFIID, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID, DISPID FAR* rgDispId ) {
HRESULT Hr; Hr = LoadTypeInfo();
if ( FAILED( Hr ) ) return Hr;
return DispGetIDsOfNames( m_TypeInfo, rgszNames, cNames, rgDispId);
}
STDMETHODIMP CBITSExtensionSetupFactory::GetTypeInfo( unsigned int iTInfo, LCID lcid, ITypeInfo FAR* FAR* ppTInfo ) {
*ppTInfo = NULL;
if(iTInfo != 0) return ResultFromScode(DISP_E_BADINDEX);
HRESULT Hr; Hr = LoadTypeInfo();
if ( FAILED( Hr ) ) return Hr;
m_TypeInfo->AddRef(); *ppTInfo = m_TypeInfo;
return NOERROR; }
STDMETHODIMP CBITSExtensionSetupFactory::GetTypeInfoCount( unsigned int FAR* pctinfo ) { *pctinfo = 1; return NOERROR; }
STDMETHODIMP CBITSExtensionSetupFactory::Invoke( DISPID dispIdMember, REFIID, LCID, WORD wFlags, DISPPARAMS FAR* pDispParams, VARIANT FAR* pVarResult, EXCEPINFO FAR* pExcepInfo, unsigned int FAR* puArgErr ) {
HRESULT Hr; Hr = LoadTypeInfo();
if ( FAILED( Hr ) ) return Hr;
return DispInvoke( this, m_TypeInfo, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
}
STDMETHODIMP CBITSExtensionSetupFactory::GetObject( BSTR Path, IBITSExtensionSetup **ppExtensionSetup ) {
WCHAR *ObjectPath = NULL; IUnknown *Object = NULL;
try { if ( !Path || !ppExtensionSetup ) throw ComError( E_INVALIDARG );
*ppExtensionSetup = NULL; ObjectPath = CSimplePropertyReader::ConvertObjectPathToADSI( (WCHAR*)Path );
THROW_COMERROR( ADsGetObject( BSTR( ObjectPath ), __uuidof( IUnknown ), (void**)&Object ) );
delete ObjectPath; ObjectPath = NULL;
CBITSExtensionSetup *SetupObj = new CBITSExtensionSetup( NULL, Object );
if ( !SetupObj ) throw ComError( E_OUTOFMEMORY );
Object = NULL; *ppExtensionSetup = static_cast<IBITSExtensionSetup*>( SetupObj ); return S_OK; } catch( ComError Error ) { delete ObjectPath; if ( Object ) Object->Release(); return Error.m_Hr; }
}
STDMETHODIMP CNonDelegatingIUnknown::QueryInterface(REFIID riid, LPVOID *ppv) { if (!ppv) return E_FAIL; *ppv = NULL;
if ( riid == __uuidof(IUnknown) ) *ppv = static_cast<IUnknown *>(this); else if ( riid == __uuidof(IDispatch) ) *ppv = static_cast<IDispatch*>(m_DelegatingIUnknown); else if ( riid == __uuidof(IBITSExtensionSetup) ) *ppv = static_cast<IBITSExtensionSetup *>(m_DelegatingIUnknown); else if ( riid == __uuidof(IADsExtension) ) *ppv = static_cast<IADsExtension *>(m_DelegatingIUnknown);
if (*ppv) { reinterpret_cast<IUnknown *>(*ppv)->AddRef(); return S_OK; } return E_NOINTERFACE; }
STDMETHODIMP_(ULONG) CNonDelegatingIUnknown::AddRef() { return InterlockedIncrement((LONG *)&m_cref); }
STDMETHODIMP_(ULONG) CNonDelegatingIUnknown::Release() { if (InterlockedDecrement((LONG *)&m_cref) == 0) { // we need to decrement our object count in the DLL
delete m_DelegatingIUnknown; return 0; } return m_cref; }
CNonDelegatingIUnknown::CNonDelegatingIUnknown( CBITSExtensionSetup * DelegatingIUnknown ) : m_DelegatingIUnknown( DelegatingIUnknown ), m_cref(1) { }
CBITSExtensionSetup::CBITSExtensionSetup( IUnknown *Outer, IUnknown *Object ) : m_pOuter( Outer ), m_pObject( Object ), m_OuterDispatch( NULL ), m_TypeInfo( NULL ), m_ADSIPath( NULL ), m_Path( NULL ), m_PropertyMan( NULL ), m_DelegationIUnknown( this ), m_RemoteInterface( NULL ), m_InitComplete( false ), m_Lock( 0 ) {
if ( m_pOuter ) {
HRESULT Hr = m_pOuter->QueryInterface( __uuidof( IDispatch ), (void**)&m_OuterDispatch );
if ( FAILED( Hr ) ) m_OuterDispatch = NULL;
}
OBJECT_CREATED }
CBITSExtensionSetup::~CBITSExtensionSetup() { if ( m_pObject ) { m_pObject->Release(); m_pObject = NULL; }
if ( m_OuterDispatch ) m_OuterDispatch->Release();
if ( m_TypeInfo ) m_TypeInfo->Release();
delete[] m_Path; // Noop on NULL
m_Path = NULL;
if ( m_RemoteInterface ) m_RemoteInterface->Release();
delete m_PropertyMan;
SysFreeString( m_ADSIPath );
OBJECT_DESTROYED }
STDMETHODIMP CBITSExtensionSetup::QueryInterface(REFIID riid, LPVOID *ppv) { if ( m_pOuter ) return m_pOuter->QueryInterface( riid, ppv ); else return m_DelegationIUnknown.QueryInterface( riid, ppv ); }
STDMETHODIMP_(ULONG) CBITSExtensionSetup::AddRef() { if ( m_pOuter ) return m_pOuter->AddRef(); else return m_DelegationIUnknown.AddRef(); }
STDMETHODIMP_(ULONG) CBITSExtensionSetup::Release() { if ( m_pOuter ) return m_pOuter->AddRef(); else return m_DelegationIUnknown.AddRef(); }
HRESULT CBITSExtensionSetup::LoadTypeInfo() {
if ( m_TypeInfo ) return S_OK;
// Lock object
while( InterlockedExchange( &m_Lock, 1 ) ) Sleep( 0 );
HRESULT Hr = ::GetTypeInfo( __uuidof( IBITSExtensionSetup ), &m_TypeInfo );
// Unlock the object
InterlockedExchange( &m_Lock, 0 ); return Hr;
}
STDMETHODIMP CBITSExtensionSetup::Operate( ULONG dwCode, VARIANT varData1, VARIANT varData2, VARIANT varData3) {
return E_NOTIMPL;
}
STDMETHODIMP CBITSExtensionSetup::PrivateGetIDsOfNames( REFIID, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID, DISPID FAR* rgDispId ) {
HRESULT Hr; Hr = LoadTypeInfo();
if ( FAILED( Hr ) ) return Hr;
return DispGetIDsOfNames( m_TypeInfo, rgszNames, cNames, rgDispId);
}
STDMETHODIMP CBITSExtensionSetup::PrivateGetTypeInfo( unsigned int iTInfo, LCID lcid, ITypeInfo FAR* FAR* ppTInfo ) {
*ppTInfo = NULL;
if(iTInfo != 0) return ResultFromScode(DISP_E_BADINDEX);
HRESULT Hr; Hr = LoadTypeInfo();
if ( FAILED( Hr ) ) return Hr;
m_TypeInfo->AddRef(); *ppTInfo = m_TypeInfo;
return NOERROR; }
STDMETHODIMP CBITSExtensionSetup::PrivateGetTypeInfoCount( unsigned int FAR* pctinfo ) { *pctinfo = 1; return NOERROR; }
STDMETHODIMP CBITSExtensionSetup::PrivateInvoke( DISPID dispIdMember, REFIID, LCID, WORD wFlags, DISPPARAMS FAR* pDispParams, VARIANT FAR* pVarResult, EXCEPINFO FAR* pExcepInfo, unsigned int FAR* puArgErr ) {
HRESULT Hr; Hr = LoadTypeInfo();
if ( FAILED( Hr ) ) return Hr;
return DispInvoke( static_cast<IBITSExtensionSetup*>(this), m_TypeInfo, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
}
STDMETHODIMP CBITSExtensionSetup::GetIDsOfNames( REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgDispId ) {
if ( m_OuterDispatch ) return m_OuterDispatch->GetIDsOfNames( riid, rgszNames, cNames, lcid, rgDispId ); return PrivateGetIDsOfNames( riid, rgszNames, cNames, lcid, rgDispId );
}
STDMETHODIMP CBITSExtensionSetup::GetTypeInfo( unsigned int iTInfo, LCID lcid, ITypeInfo FAR* FAR* ppTInfo ) {
if ( m_OuterDispatch ) return m_OuterDispatch->GetTypeInfo( iTInfo, lcid, ppTInfo );
return PrivateGetTypeInfo( iTInfo, lcid, ppTInfo );
}
STDMETHODIMP CBITSExtensionSetup::GetTypeInfoCount( unsigned int FAR* pctinfo ) {
if ( m_OuterDispatch ) return m_OuterDispatch->GetTypeInfoCount( pctinfo );
return PrivateGetTypeInfoCount( pctinfo );
}
STDMETHODIMP CBITSExtensionSetup::Invoke( DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR* pDispParams, VARIANT FAR* pVarResult, EXCEPINFO FAR* pExcepInfo, unsigned int FAR* puArgErr ) {
if ( m_OuterDispatch ) return m_OuterDispatch->Invoke( dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr );
return PrivateInvoke( dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr );
}
HRESULT CBITSExtensionSetup::ConnectToRemoteExtension() { WCHAR *HostName = NULL; WCHAR *NewPath = NULL; BSTR NewPathBSTR = NULL; IBITSExtensionSetupFactory* Factory = NULL;
try {
// Extract out the host part of the path
const SIZE_T PrefixSize = sizeof(L"IIS://")/sizeof(WCHAR) - 1; if ( _wcsnicmp( (WCHAR*)m_ADSIPath, L"IIS://", PrefixSize ) != 0 ) throw ComError( E_INVALIDARG );
WCHAR *HostNameStart = ((WCHAR*)m_ADSIPath) + PrefixSize;
WCHAR *p = HostNameStart;
while( L'/' != *p ) { if ( L'\0' == *p ) throw ComError( E_INVALIDARG );
p++; }
SIZE_T HostNameSize = (char*)p - (char*)HostNameStart + sizeof(L'\0'); HostName = new WCHAR[ HostNameSize / sizeof(WCHAR) ]; memcpy( HostName, HostNameStart, HostNameSize - sizeof(WCHAR) ); HostName[ ( HostNameSize - sizeof(WCHAR) ) / sizeof(WCHAR) ] = L'\0';
if ( L'\0' == *++p ) throw ComError( E_INVALIDARG );
SIZE_T NewPathSize = wcslen( L"IIS://LocalHost/" ) + wcslen( p ) + 1; NewPath = new WCHAR[ NewPathSize ];
StringCchCopyW( NewPath, NewPathSize, L"IIS://LocalHost/" ); StringCchCatW( NewPath, NewPathSize, p );
NewPathBSTR = SysAllocString( NewPath );
if ( !NewPathBSTR ) throw ComError( E_OUTOFMEMORY );
COSERVERINFO coinfo; coinfo.dwReserved1 = 0; coinfo.dwReserved2 = 0; coinfo.pAuthInfo = NULL; coinfo.pwszName = HostName;
GUID guid = __uuidof( IBITSExtensionSetupFactory ); MULTI_QI mqi; mqi.hr = S_OK; mqi.pIID = &guid; mqi.pItf = NULL;
THROW_COMERROR( CoCreateInstanceEx( __uuidof(BITSExtensionSetupFactory), NULL, CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER, &coinfo, 1, &mqi ) ); THROW_COMERROR( mqi.hr );
Factory = (IBITSExtensionSetupFactory*)mqi.pItf; mqi.pItf = NULL;
THROW_COMERROR( Factory->GetObject( NewPathBSTR, &m_RemoteInterface ) );
Factory->Release();
SysFreeString( NewPathBSTR ); delete[] NewPath; delete[] HostName;
return S_OK; } catch( ComError Error ) { SysFreeString( NewPathBSTR ); delete[] HostName; delete[] NewPath;
if ( Factory ) Factory->Release();
return Error.m_Hr; }
}
HRESULT CBITSExtensionSetup::LoadPath() { if ( m_InitComplete ) return S_OK;
// Lock object
while( InterlockedExchange( &m_Lock, 1 ) ) Sleep( 0 );
try { if ( !m_PropertyMan ) {
m_PropertyMan = new PropertyIDManager(); HRESULT Hr = m_PropertyMan->LoadPropertyInfo();
if ( FAILED(Hr) ) { delete m_PropertyMan; m_PropertyMan = NULL; throw ComError( Hr ); }
}
if ( !m_ADSIPath ) {
SmartIADsPointer ObjectADS;
if ( m_pObject ) THROW_COMERROR( m_pObject->QueryInterface( __uuidof(*ObjectADS), (void**) ObjectADS.GetRecvPointer() ) ); else THROW_COMERROR( m_pOuter->QueryInterface( __uuidof(*ObjectADS), (void**) ObjectADS.GetRecvPointer() ) );
THROW_COMERROR( ObjectADS->get_ADsPath( &m_ADSIPath ) );
}
if ( !m_Path && !m_RemoteInterface ) {
if ( _wcsnicmp( (WCHAR*)m_ADSIPath, L"IIS://LocalHost/", wcslen( L"IIS://LocalHost/" ) ) == 0 ) { SIZE_T PathSize = wcslen( (WCHAR*)m_ADSIPath ) + 1; m_Path = new WCHAR[ PathSize ];
StringCchCopyW( m_Path, PathSize, L"/LM/" ); StringCchCatW( m_Path, PathSize, reinterpret_cast<WCHAR*>( m_ADSIPath ) + wcslen( L"IIS://LocalHost/" ) ); }
else { THROW_COMERROR( ConnectToRemoteExtension( ) ); }
}
m_InitComplete = true; // unlock
InterlockedExchange( &m_Lock, 0 ); return S_OK;
} catch( ComError Error ) { InterlockedExchange( &m_Lock, 0 ); return Error.m_Hr; } }
STDMETHODIMP CBITSExtensionSetup::EnableBITSUploads() {
try { THROW_COMERROR( LoadPath() );
if ( m_RemoteInterface ) return m_RemoteInterface->EnableBITSUploads();
SmartIMSAdminBasePointer AdminBase;
THROW_COMERROR( CoCreateInstance( GETAdminBaseCLSID(TRUE), NULL, CLSCTX_SERVER, AdminBase.GetUUID(), (LPVOID*)AdminBase.GetRecvPointer() ) );
EnableBITSForVDIR( m_PropertyMan, AdminBase, m_Path );
return S_OK; } catch( ComError Error ) { return Error.m_Hr; } }
STDMETHODIMP CBITSExtensionSetup::DisableBITSUploads() {
try { THROW_COMERROR( LoadPath() );
if ( m_RemoteInterface ) return m_RemoteInterface->DisableBITSUploads();
SmartIMSAdminBasePointer AdminBase;
THROW_COMERROR( CoCreateInstance( GETAdminBaseCLSID(TRUE), NULL, CLSCTX_SERVER, AdminBase.GetUUID(), (LPVOID*)AdminBase.GetRecvPointer() ) );
DisableBITSForVDIR( m_PropertyMan, AdminBase, m_Path, false, false );
return S_OK; } catch( ComError Error ) { return Error.m_Hr; }
}
STDMETHODIMP CBITSExtensionSetup::GetCleanupTaskName( BSTR *pTaskName ) {
LPWSTR TaskName = NULL;
try {
*pTaskName = NULL;
THROW_COMERROR( LoadPath() );
if ( m_RemoteInterface ) return m_RemoteInterface->GetCleanupTaskName( pTaskName );
SmartIMSAdminBasePointer AdminBase;
THROW_COMERROR( CoCreateInstance( GETAdminBaseCLSID(TRUE), NULL, CLSCTX_SERVER, AdminBase.GetUUID(), (LPVOID*)AdminBase.GetRecvPointer() ) );
FindWorkItemForVDIR( m_PropertyMan, AdminBase, m_Path, &TaskName );
if ( TaskName ) {
*pTaskName = SysAllocString( TaskName ); if ( !*pTaskName ) throw ComError( E_OUTOFMEMORY );
CoTaskMemFree( TaskName ); TaskName = NULL; } return S_OK;
} catch( ComError Error ) { CoTaskMemFree( TaskName ); return Error.m_Hr; }
}
STDMETHODIMP CBITSExtensionSetup::GetCleanupTask( [in] REFIID riid, [out,retval] IUnknown **ppUnk ) {
HRESULT Hr = S_OK; SmartITaskSchedulerPointer TaskScheduler; BSTR ItemName = NULL; WCHAR *HostName = NULL; if ( ppUnk ) *ppUnk = NULL;
try {
THROW_COMERROR( LoadPath() );
//
// Build the taskscheduler form of the host name
//
const SIZE_T PrefixSize = sizeof(L"IIS://")/sizeof(WCHAR) - 1; if ( _wcsnicmp( (WCHAR*)m_ADSIPath, L"IIS://", PrefixSize ) != 0 ) throw ComError( E_INVALIDARG );
WCHAR *HostNameStart = ((WCHAR*)m_ADSIPath) + PrefixSize; WCHAR *p = HostNameStart;
while( L'/' != *p ) { if ( L'\0' == *p ) throw ComError( E_INVALIDARG );
p++; }
SIZE_T HostNameSize = (char*)p - (char*)HostNameStart + sizeof(L'\0'); HostName = new WCHAR[ ( HostNameSize / sizeof(WCHAR) ) + 2 ];
HostName[0] = HostName[1] = L'\\'; memcpy( HostName + 2, HostNameStart, HostNameSize - sizeof(WCHAR) ); HostName[ ( ( HostNameSize - sizeof(WCHAR) ) / sizeof(WCHAR) ) + 2 ] = L'\0';
if ( _wcsicmp( HostName, L"\\\\LocalHost" ) == 0 ) { delete[] HostName; HostName = NULL; }
ConnectToTaskScheduler( HostName, &TaskScheduler ); THROW_COMERROR( GetCleanupTaskName( &ItemName ) );
if ( ItemName ) THROW_COMERROR( TaskScheduler->Activate( (LPCWSTR)ItemName, riid, ppUnk ) ); else Hr = S_FALSE;
} catch( ComError Error ) { Hr = Error.m_Hr; }
SysFreeString( ItemName ); delete[] HostName;
return Hr;
}
#include "bitssrvcfgimp.h"
|