//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1997 - 2000. // // File: cimbmgr.cxx // // Contents: Content Index Meta Base Manager // // Classes: CMetaDataMgr // // History: 07-Feb-1997 dlee Created // 24-Apr-1997 dlee Converted to new Unicode interface // //---------------------------------------------------------------------------- #include #pragma hdrstop #include #define MYDEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ EXTERN_C const GUID name \ = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } MYDEFINE_GUID(CLSID_MSAdminBase_W, 0xa9e69610, 0xb80d, 0x11d0, 0xb9, 0xb9, 0x0, 0xa0, 0xc9, 0x22, 0xe7, 0x50); MYDEFINE_GUID(IID_IMSAdminBase_W, 0x70b51430, 0xb6ca, 0x11d0, 0xb9, 0xb9, 0x0, 0xa0, 0xc9, 0x22, 0xe7, 0x50); MYDEFINE_GUID(CLSID_MSAdminBaseExe_W, 0xa9e69611, 0xb80d, 0x11d0, 0xb9, 0xb9, 0x0, 0xa0, 0xc9, 0x22, 0xe7, 0x50); MYDEFINE_GUID(IID_IMSAdminBaseSink_W, 0xa9e69612, 0xb80d, 0x11d0, 0xb9, 0xb9, 0x0, 0xa0, 0xc9, 0x22, 0xe7, 0x50); //+------------------------------------------------------------------------- // // Member: CMetaDataMgr::CMetaDataMgr, public // // Synopsis: Creates an object for talking to the IIS metabase. // // Arguments: [fTopLevel] - TRUE for the top level, FALSE for a // vserver instance // [dwInstance] - instance # of the server // [eType] - type of vroot provider -- W3, NNTP, or IMAP // [pwcMachine] - the machine to open, L"." for local machine // // History: 07-Feb-1997 dlee Created // //-------------------------------------------------------------------------- CMetaDataMgr::CMetaDataMgr( BOOL fTopLevel, CiVRootTypeEnum eType, DWORD dwInstance, WCHAR const * pwcMachine ) : _fNotifyEnabled( FALSE ), _fTopLevel( fTopLevel ) { // -1 is a valid instance number, so this is a bogus assert, but it'll // never be hit unless something else is broken or someone hacked the // registry. #if CIDBG == 1 if ( fTopLevel ) Win4Assert( 0xffffffff == dwInstance ); else Win4Assert( 0xffffffff != dwInstance ); #endif // CIDBG == 1 if ( fTopLevel ) swprintf( _awcInstance, L"/lm/%ws", GetVRootService( eType ) ); else swprintf( _awcInstance, L"/lm/%ws/%d", GetVRootService( eType ), dwInstance ); IMSAdminBase * pcAdmCom; if ( !_wcsicmp( pwcMachine, L"." ) ) { SCODE sc = CoCreateInstance( GETAdminBaseCLSID(TRUE), NULL, CLSCTX_ALL, IID_IMSAdminBase, (void **) &pcAdmCom ); if ( FAILED(sc) ) { ciDebugOut(( DEB_WARN, "CMetaDataMgr can't CoCreateInstance: %x\n", sc )); THROW( CException(sc) ); } } else { COSERVERINFO info; RtlZeroMemory( &info, sizeof info ); info.pwszName = (WCHAR *) pwcMachine; XInterface xFactory; SCODE sc = CoGetClassObject( GETAdminBaseCLSID(TRUE), CLSCTX_SERVER, &info, IID_IClassFactory, xFactory.GetQIPointer() ); if ( FAILED(sc) ) { ciDebugOut(( DEB_WARN, "CMetaDataMgr can't CoGetClassObject: %x\n", sc )); THROW( CException(sc) ); } sc = xFactory->CreateInstance( 0, IID_IMSAdminBase, (void**) &pcAdmCom ); if ( FAILED(sc) ) { ciDebugOut(( DEB_WARN, "CMetaDataMgr can't CreateInstance: %x\n", sc )); THROW( CException(sc) ); } } _xAdminBase.Set( pcAdmCom ); } //CMetaDataMgr //+------------------------------------------------------------------------- // // Member: CMetaDataMgr::~CMetaDataMgr, public // // Synopsis: Destroys an object for talking to the IIS metabase // // History: 07-Feb-1997 dlee Created // //-------------------------------------------------------------------------- CMetaDataMgr::~CMetaDataMgr() { if ( !_xAdminBase.IsNull() ) { // just in case we are still connected DisableVPathNotify(); } } //~CMetaDataMgr //+------------------------------------------------------------------------- // // Member: CMetaDataMgr::IsIISAdminUp, public/static // // Synopsis: Returns TRUE if iisadmin svc is up // // Arguments: [fIISAdminInstalled] - returns TRUE if it's installed, // FALSE otherwise // // History: 07-Feb-1997 dlee Created // //-------------------------------------------------------------------------- BOOL CMetaDataMgr::IsIISAdminUp( BOOL & fIISAdminInstalled ) { fIISAdminInstalled = TRUE; BOOL fIsUp = TRUE; TRY { // The constructor will throw if the iisadmin svc is unavailable. CMetaDataMgr( TRUE, W3VRoot ); } CATCH( CException, e ) { fIsUp = FALSE; if ( REGDB_E_CLASSNOTREG == e.GetErrorCode() ) fIISAdminInstalled = FALSE; } END_CATCH return fIsUp; } //IsIISAdminUp //+------------------------------------------------------------------------- // // Member: CMetaDataMgr::EnumVPaths, public // // Synopsis: Enumerates vpaths by calling the callback // // Arguments: [callBack] - called for each vpath // // History: 07-Feb-1997 dlee Created // //-------------------------------------------------------------------------- void CMetaDataMgr::EnumVPaths( CMetaDataCallBack & callBack ) { Win4Assert( !_fTopLevel ); CMetaDataHandle mdRoot( _xAdminBase, _awcInstance ); CVRootStack vrootStack; Enum( vrootStack, callBack, mdRoot, L"" ); } //EnumVPaths //+------------------------------------------------------------------------- // // Member: CMetaDataMgr::AddVRoot, public // // Synopsis: Adds a VRoot to the metabase // // Arguments: [pwcVRoot] - name of the vroot, e.g.: /here // [pwcPRoot] - physical path of the vroot, e.g.: x:\here // [dwAccess] - access rights to the vroot // // History: 07-Feb-1997 dlee Created // //-------------------------------------------------------------------------- void CMetaDataMgr::AddVRoot( WCHAR const * pwcVRoot, WCHAR const * pwcPRoot, DWORD dwAccess ) { Win4Assert( !_fTopLevel ); // blow it away if it currently exists RemoveVRoot( pwcVRoot ); { unsigned cwc = wcslen( _awcInstance ) + wcslen( L"/Root" ); if ( cwc >= METADATA_MAX_NAME_LEN ) THROW( CException( E_INVALIDARG ) ); WCHAR awc[ METADATA_MAX_NAME_LEN ]; wcscpy( awc, _awcInstance ); wcscat( awc, L"/Root" ); CMetaDataHandle mdRoot( _xAdminBase, awc, TRUE ); _xAdminBase->AddKey( mdRoot.Get(), pwcVRoot ); } WCHAR awcVRootPath[ METADATA_MAX_NAME_LEN ]; unsigned cwc = wcslen( _awcInstance ) + wcslen( L"/Root" ) + wcslen( pwcVRoot ); if ( cwc >= METADATA_MAX_NAME_LEN ) THROW( CException( E_INVALIDARG ) ); wcscpy( awcVRootPath, _awcInstance ); wcscat( awcVRootPath, L"/Root" ); wcscat( awcVRootPath, pwcVRoot ); CMetaDataHandle mdVRoot( _xAdminBase, awcVRootPath, TRUE ); { METADATA_RECORD mdr; RtlZeroMemory( &mdr, sizeof mdr ); mdr.dwMDIdentifier = MD_VR_PATH; mdr.dwMDAttributes = METADATA_INHERIT; mdr.dwMDUserType = IIS_MD_UT_FILE; mdr.dwMDDataType = STRING_METADATA; mdr.pbMDData = (BYTE *) pwcPRoot; mdr.dwMDDataLen = sizeof WCHAR * ( 1 + wcslen( pwcPRoot ) ); DWORD cbRequired = 0; SCODE sc = _xAdminBase->SetData( mdVRoot.Get(), L"", &mdr ); if ( FAILED( sc ) ) { ciDebugOut(( DEB_WARN, "SetData PRoot failed: 0x%x\n", sc )); THROW( CException( sc ) ); } } { // must set a null username to enforce metadata consistency METADATA_RECORD mdr; RtlZeroMemory( &mdr, sizeof mdr ); mdr.dwMDIdentifier = MD_VR_USERNAME; mdr.dwMDAttributes = METADATA_INHERIT; mdr.dwMDUserType = IIS_MD_UT_SERVER; mdr.dwMDDataType = STRING_METADATA; mdr.pbMDData = (BYTE *) L""; mdr.dwMDDataLen = sizeof WCHAR; DWORD cbRequired = 0; SCODE sc = _xAdminBase->SetData( mdVRoot.Get(), L"", &mdr ); if ( FAILED( sc ) ) { ciDebugOut(( DEB_WARN, "SetData user failed: 0x%x\n", sc )); THROW( CException( sc ) ); } } { METADATA_RECORD mdr; RtlZeroMemory( &mdr, sizeof mdr ); mdr.dwMDIdentifier = MD_ACCESS_PERM; mdr.dwMDAttributes = METADATA_INHERIT; mdr.dwMDUserType = IIS_MD_UT_FILE; mdr.dwMDDataType = DWORD_METADATA; mdr.pbMDData = (BYTE *) &dwAccess; mdr.dwMDDataLen = sizeof dwAccess; DWORD cbRequired = 0; SCODE sc = _xAdminBase->SetData( mdVRoot.Get(), L"", &mdr ); if ( FAILED( sc ) ) { ciDebugOut(( DEB_WARN, "SetData accessperm failed: 0x%x\n", sc )); THROW( CException( sc ) ); } } } //AddVRoot //+------------------------------------------------------------------------- // // Member: CMetaDataMgr::Flush, public // // Synopsis: Flushes the metabase, since it's not robust. // // History: 4-Dec-1998 dlee Created // //-------------------------------------------------------------------------- void CMetaDataMgr::Flush() { SCODE sc = _xAdminBase->SaveData(); if ( FAILED( sc ) ) { ciDebugOut(( DEB_WARN, "CMetaDataMgr::Flush failed: %#x\n", sc )); THROW( CException( sc ) ); } } //Flush //+------------------------------------------------------------------------- // // Member: CMetaDataMgr::RemoveVRoot, public // // Synopsis: Removes a VRoot from the metabase // // Arguments: [pwcVRoot] - name of the vroot. e.g.: /scripts // // Notes: Doesn't throw on failure to remove the root. // // History: 07-Feb-1997 dlee Created // //-------------------------------------------------------------------------- SCODE CMetaDataMgr::RemoveVRoot( WCHAR const * pwcVRoot ) { Win4Assert( !_fTopLevel ); unsigned cwc = wcslen( _awcInstance ) + wcslen( L"/Root" ); if ( cwc >= METADATA_MAX_NAME_LEN ) THROW( CException( E_INVALIDARG ) ); WCHAR awcRoot[ METADATA_MAX_NAME_LEN ]; wcscpy( awcRoot, _awcInstance ); wcscat( awcRoot, L"/Root" ); CMetaDataHandle mdRoot( _xAdminBase, awcRoot, TRUE ); // don't throw on error deleting vroot -- the root may not exist return _xAdminBase->DeleteKey( mdRoot.Get(), pwcVRoot ); } //RemoveVRoot //+------------------------------------------------------------------------- // // Member: CMetaDataMgr::WriteRootValue, private // // Synopsis: Retrieves data for the key and identifier // // Arguments: [mdRoot] - Metabase key where data reside // [mdr] - Scratch pad for the record. On output, can be // used to write the data, since all the // fields are initialized properly. // [xData] - Where data is written // [dwIdentifier] - The metabase id // // History: 24-Feb-1998 dlee Created // //-------------------------------------------------------------------------- void CMetaDataMgr::ReadRootValue( CMetaDataHandle & mdRoot, METADATA_RECORD & mdr, XGrowable & xData, DWORD dwIdentifier ) { RtlZeroMemory( &mdr, sizeof mdr ); mdr.dwMDIdentifier = dwIdentifier; // script maps, etc. can be enormous due to bugs in ISV apps do { mdr.pbMDData = (BYTE *) xData.Get(); mdr.dwMDDataLen = xData.SizeOf(); DWORD cbRequired = 0; SCODE sc = _xAdminBase->GetData( mdRoot.Get(), L"", &mdr, &cbRequired ); if ( HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER ) == sc ) { xData.SetSizeInBytes( cbRequired ); continue; } else if ( FAILED( sc ) ) { ciDebugOut(( DEB_WARN, "GetData root value failed: 0x%x\n", sc )); THROW( CException( sc ) ); } break; } while ( TRUE ); } //ReadRootValue //+------------------------------------------------------------------------- // // Member: CMetaDataMgr::WriteRootValue, private // // Synopsis: Writes data to the key // // Arguments: [mdRoot] - Metabase key where data resides // [mdr] - Metadata record suitable for writing data // [pwcData] - Multi-sz string with data // [cwcData] - Total length including all terminating nulls // // History: 24-Feb-1998 dlee Created // //-------------------------------------------------------------------------- void CMetaDataMgr::WriteRootValue( CMetaDataHandle & mdRoot, METADATA_RECORD & mdr, WCHAR const * pwcData, unsigned cwcData ) { // note: the other fields in mdr were initialized properly by a call // to ReadRootValue. mdr.dwMDDataLen = sizeof WCHAR * cwcData; mdr.pbMDData = (BYTE *) pwcData; SCODE sc = _xAdminBase->SetData( mdRoot.Get(), L"", &mdr ); if ( FAILED( sc ) ) { ciDebugOut(( DEB_WARN, "SetData root value failed: 0x%x\n", sc )); THROW( CException( sc ) ); } } //WriteRootValue //+------------------------------------------------------------------------- // // Member: CMetaDataMgr::AddApplicationDependency, public // // Synopsis: Adds an entry to the application dependency list // // Arguments: [pwcApp] - The entry to add, like this: // "Indexing Service;IndexingService" // // History: 01-Jun-2002 dlee Created // //-------------------------------------------------------------------------- void CMetaDataMgr::AddApplicationDependency( WCHAR const * pwcApp ) { CMetaDataHandle mdRoot( _xAdminBase, L"/lm/w3svc", TRUE ); XGrowable xApps; METADATA_RECORD mdr; ReadRootValue( mdRoot, mdr, xApps, MD_APP_DEPENDENCIES ); // add the new entry to the existing ones XGrowable xTemp; xTemp.SetSize( xApps.Count() + wcslen( pwcApp ) + 1 ); WCHAR *pwcTemp = xTemp.Get(); wcscpy( pwcTemp, pwcApp ); pwcTemp += ( 1 + wcslen( pwcTemp ) ); WCHAR * pwcOldApps = xApps.Get(); while ( 0 != *pwcOldApps ) { wcscpy( pwcTemp, pwcOldApps ); int x = 1 + wcslen( pwcOldApps ); pwcTemp += x; pwcOldApps += x; } *pwcTemp++ = 0; // write the new set of apps WriteRootValue( mdRoot, mdr, xTemp.Get(), (UINT)( pwcTemp - xTemp.Get() ) ); } //AddApplicationDependency //+------------------------------------------------------------------------- // // Member: CMetaDataMgr::AddRestrictionList, public // // Synopsis: Adds an entry to the restriction list. // // Arguments: [pwcRestriction] - The entry to add, like this: // "0,c:\windows\system32\webhits.dll,0,IndexingService,Indexing Service" // // History: 01-Jun-2002 dlee Created // //-------------------------------------------------------------------------- void CMetaDataMgr::AddRestrictionList( WCHAR const * pwcRestriction ) { CMetaDataHandle mdRoot( _xAdminBase, L"/lm/w3svc", TRUE ); XGrowable xList; METADATA_RECORD mdr; ReadRootValue( mdRoot, mdr, xList, MD_WEB_SVC_EXT_RESTRICTION_LIST ); // add the new entry to the existing ones XGrowable xTemp; xTemp.SetSize( xList.Count() + wcslen( pwcRestriction ) + 1 ); WCHAR *pwcTemp = xTemp.Get(); wcscpy( pwcTemp, pwcRestriction ); pwcTemp += ( 1 + wcslen( pwcTemp ) ); WCHAR * pwcOldEntries = xList.Get(); while ( 0 != *pwcOldEntries ) { wcscpy( pwcTemp, pwcOldEntries ); int x = 1 + wcslen( pwcOldEntries ); pwcTemp += x; pwcOldEntries += x; } *pwcTemp++ = 0; // write the new set of restrictions WriteRootValue( mdRoot, mdr, xTemp.Get(), (UINT)( pwcTemp - xTemp.Get() ) ); } //AddRestrictionList //+------------------------------------------------------------------------- // // Member: CMetaDataMgr::RemoveApplicationDependency, public // // Synopsis: Removes an entry from the application dependency list // // Arguments: [pwcKey] - Name of the key. e.g. // "IndexingService" // for entry like this one: // "Indexing Service;IndexingService" // // History: 01-Jun-2002 dlee Created // //-------------------------------------------------------------------------- void CMetaDataMgr::RemoveApplicationDependency( WCHAR const * pwcKey ) { // retrieve the existing apps CMetaDataHandle mdRoot( _xAdminBase, L"/lm/w3svc", TRUE ); XGrowable xApps; METADATA_RECORD mdr; ReadRootValue( mdRoot, mdr, xApps, MD_APP_DEPENDENCIES ); // awcApps is a multi-sz string XGrowable xNew( xApps.Count() ); WCHAR *pwcNew = xNew.Get(); pwcNew[0] = 0; BOOL fFound = FALSE; // re-add all Apps other than those containing pwcKey WCHAR const *pwcCur = xApps.Get(); while ( 0 != *pwcCur ) { // if we didn't find the key, copy what we did find. WCHAR const * pwcSemi = wcschr( pwcCur, L';' ); if ( ( 0 == pwcSemi ) || ( 0 != wcscmp( pwcSemi + 1, pwcKey ) ) ) { wcscpy( pwcNew, pwcCur ); pwcNew += ( 1 + wcslen( pwcNew ) ); } else { fFound = TRUE; } int cwc = wcslen( pwcCur ); pwcCur += ( cwc + 1 ); } // If the key wasn't found, don't do the write if ( !fFound ) return; *pwcNew++ = 0; // got the string, now pound it in the metabase WriteRootValue( mdRoot, mdr, xNew.Get(), (UINT)(pwcNew - xNew.Get()) ); } //RemoveApplicationDependency //+------------------------------------------------------------------------- // // Member: CMetaDataMgr::RemoveRestrictionList, public // // Synopsis: Removes entries from the restriction list that references // the application specified. // // Arguments: [pwcKey] - Name of the key. e.g. // "IndexingService" // for entries like: // "0,c:\windows\system32\idq.dll,0,IndexingService,Indexing Service" // "0,c:\windows\system32\webhits.dll,0,IndexingService,Indexing Service" // // History: 01-Jun-2002 dlee Created // //-------------------------------------------------------------------------- void CMetaDataMgr::RemoveRestrictionList( WCHAR const * pwcKey ) { // retrieve the existing apps CMetaDataHandle mdRoot( _xAdminBase, L"/lm/w3svc", TRUE ); XGrowable xList; METADATA_RECORD mdr; ReadRootValue( mdRoot, mdr, xList, MD_WEB_SVC_EXT_RESTRICTION_LIST ); // awcApps is a multi-sz string XGrowable xNew( xList.Count() ); WCHAR *pwcNew = xNew.Get(); pwcNew[0] = 0; int cwcKey = wcslen( pwcKey ); BOOL fFound = FALSE; // re-add all Entries other than those containing pwcKey WCHAR const *pwcCur = xList.Get(); while ( 0 != *pwcCur ) { // if we didn't find the key, then copy the entry WCHAR const * pwcFound = wcsstr( pwcCur, pwcKey ); if ( ( 0 == pwcFound ) || ( pwcFound == pwcCur ) || ( L',' != * ( pwcFound - 1 ) ) || ( L',' != pwcFound[ cwcKey ] ) ) { wcscpy( pwcNew, pwcCur ); pwcNew += ( 1 + wcslen( pwcNew ) ); } else { fFound = TRUE; } int cwc = wcslen( pwcCur ); pwcCur += ( cwc + 1 ); } // If the key wasn't found, don't do the write if ( !fFound ) return; *pwcNew++ = 0; // got the string, now pound it in the metabase WriteRootValue( mdRoot, mdr, xNew.Get(), (UINT)(pwcNew - xNew.Get()) ); } //RemoveRestrictionList //+------------------------------------------------------------------------- // // Member: CMetaDataMgr::AddScriptMap, public // // Synopsis: Adds a script map to the metabase // // Arguments: [pwcMap] - script map of the form: // L".idq,d:\\winnt\\system32\\idq.dll,0" // // History: 07-Feb-1997 dlee Created // //-------------------------------------------------------------------------- void CMetaDataMgr::AddScriptMap( WCHAR const * pwcMap ) { // remove the existing script map if it exists. have to get the // extension first. if ( wcslen( pwcMap ) > MAX_PATH ) THROW( CException( HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ) ) ); WCHAR awcExt[ MAX_PATH ]; wcscpy( awcExt, pwcMap ); WCHAR *pwc = wcschr( awcExt, L',' ); if ( !pwc ) THROW( CException( HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ) ) ); *pwc = 0; RemoveScriptMap( awcExt ); CMetaDataHandle mdRoot( _xAdminBase, L"/lm/w3svc", TRUE ); XGrowable xMaps; METADATA_RECORD mdr; ReadRootValue( mdRoot, mdr, xMaps, MD_SCRIPT_MAPS ); // add the new script map to the existing ones XGrowable xTemp; xTemp.SetSize( xMaps.Count() + wcslen( pwcMap ) + 1 ); WCHAR *pwcTemp = xTemp.Get(); wcscpy( pwcTemp, pwcMap ); pwcTemp += ( 1 + wcslen( pwcTemp ) ); WCHAR * pwcOldMaps = xMaps.Get(); while ( 0 != *pwcOldMaps ) { wcscpy( pwcTemp, pwcOldMaps ); int x = 1 + wcslen( pwcOldMaps ); pwcTemp += x; pwcOldMaps += x; } *pwcTemp++ = 0; // write the new set of script maps WriteRootValue( mdRoot, mdr, xTemp.Get(), (UINT)( pwcTemp - xTemp.Get() ) ); } //AddScriptMap //+------------------------------------------------------------------------- // // Member: CMetaDataMgr::RemoveScriptMap, public // // Synopsis: Removes a script map from the metabase // // Arguments: [pwcExt] - extension of map to remove: L".idq" // // History: 07-Feb-1997 dlee Created // //-------------------------------------------------------------------------- void CMetaDataMgr::RemoveScriptMap( WCHAR const * pwcExt ) { // retrieve the existing script maps CMetaDataHandle mdRoot( _xAdminBase, L"/lm/w3svc", TRUE ); XGrowable xMaps; METADATA_RECORD mdr; ReadRootValue( mdRoot, mdr, xMaps, MD_SCRIPT_MAPS ); // awcMaps is a multi-sz string XGrowable xNew( xMaps.Count() ); WCHAR *pwcNew = xNew.Get(); pwcNew[0] = 0; int cwcExt = wcslen( pwcExt ); BOOL fFound = FALSE; // re-add all mappings other than pwcExt WCHAR const *pwcCur = xMaps.Get(); while ( 0 != *pwcCur ) { if ( _wcsnicmp( pwcCur, pwcExt, cwcExt ) || L',' != pwcCur[cwcExt] ) { wcscpy( pwcNew, pwcCur ); pwcNew += ( 1 + wcslen( pwcNew ) ); } else { fFound = TRUE; } int cwc = wcslen( pwcCur ); pwcCur += ( cwc + 1 ); } // If the script map wasn't found, don't do the write if ( !fFound ) return; *pwcNew++ = 0; // got the string, now pound it in the metabase WriteRootValue( mdRoot, mdr, xNew.Get(), (UINT)(pwcNew - xNew.Get()) ); } //RemoveScriptMap //+------------------------------------------------------------------------- // // Member: CMetaDataMgr::ExtensionHasScriptMap, public // // Synopsis: Finds a script map in the metabase // // Arguments: [pwcExt] - extension of map to lookup: L".idq" // // Returns: TRUE if the extension has a script map association // FALSE otherwise // // History: 10-Jul-1997 dlee Created // //-------------------------------------------------------------------------- BOOL CMetaDataMgr::ExtensionHasScriptMap( WCHAR const * pwcExt ) { CMetaDataHandle mdRoot( _xAdminBase, L"/lm/w3svc", FALSE ); XGrowable xMaps; METADATA_RECORD mdr; ReadRootValue( mdRoot, mdr, xMaps, MD_SCRIPT_MAPS ); // xMaps is a multi-sz string, look for pwcExt int cwcExt = wcslen( pwcExt ); WCHAR *pwcCur = xMaps.Get(); while ( 0 != *pwcCur ) { if ( !_wcsnicmp( pwcCur, pwcExt, cwcExt ) && L',' == pwcCur[cwcExt] ) return TRUE; int cwc = wcslen( pwcCur ); pwcCur += ( cwc + 1 ); } return FALSE; } //ExtensionHasScriptMap //+------------------------------------------------------------------------- // // Member: CMetaDataMgr::ExtensionHasTargetScriptMap, public // // Synopsis: Sees if a scriptmap is pointing at a given dll // // Arguments: [pwcExt] - extension of map to lookup: L".idq" // [pwcDll] - DLL to check, e.g. L"idq.dll" // // Returns: TRUE if the extension has a script map association // FALSE otherwise // // History: 10-Jul-1997 dlee Created // // Note: scriptmaps look like ".idq,c:\\windows\\system32\\idq.dll,3,GET,HEAD,POST" // //-------------------------------------------------------------------------- BOOL CMetaDataMgr::ExtensionHasTargetScriptMap( WCHAR const * pwcExt, WCHAR const * pwcDll ) { CMetaDataHandle mdRoot( _xAdminBase, L"/lm/w3svc", FALSE ); XGrowable xMaps; METADATA_RECORD mdr; ReadRootValue( mdRoot, mdr, xMaps, MD_SCRIPT_MAPS ); // xMaps is a multi-sz string, look for pwcExt int cwcExt = wcslen( pwcExt ); WCHAR *pwcCur = xMaps.Get(); int cwcDll = wcslen( pwcDll ); while ( 0 != *pwcCur ) { if ( !_wcsnicmp( pwcCur, pwcExt, cwcExt ) && L',' == pwcCur[cwcExt] ) { // Skip to the end of the full path and check the dll name WCHAR const * pwcSlash = wcsrchr( pwcCur, L'\\' ); if ( 0 != pwcSlash ) { if ( !_wcsnicmp( pwcSlash + 1, pwcDll, cwcDll ) ) return TRUE; } } int cwc = wcslen( pwcCur ); pwcCur += ( cwc + 1 ); } return FALSE; } //ExtensionHasTargetScriptMap //+------------------------------------------------------------------------- // // Member: CMetaDataMgr::AddInProcessApp, public // // Synopsis: Adds an app to the list of in-process apps // // Arguments: [pwcApp] - App in the form "d:\\winnt\\system32\\idq.dll" // // History: 09-Dec-1998 dlee Created // //-------------------------------------------------------------------------- void CMetaDataMgr::AddInProcessIsapiApp( WCHAR const * pwcApp ) { // // Read the existing multi-sz value // CMetaDataHandle mdRoot( _xAdminBase, L"/lm/w3svc", TRUE ); XGrowable xApps; METADATA_RECORD mdr; ReadRootValue( mdRoot, mdr, xApps, MD_IN_PROCESS_ISAPI_APPS ); WCHAR *pwcCur = xApps.Get(); // // Look for an existing entry so a duplicate isn't added // while ( 0 != *pwcCur ) { // // If it's already there, leave it alone // if ( !_wcsicmp( pwcCur, pwcApp ) ) return; int cwc = wcslen( pwcCur ); pwcCur += ( cwc + 1 ); } unsigned cwcOld = 1 + (unsigned) ( pwcCur - xApps.Get() ); // // It wasn't found, so add it // unsigned cwc = wcslen( pwcApp ) + 1; XGrowable xNew( cwcOld + cwc ); RtlCopyMemory( xNew.Get(), pwcApp, cwc * sizeof WCHAR ); RtlCopyMemory( xNew.Get() + cwc, xApps.Get(), cwcOld * sizeof WCHAR ); WriteRootValue( mdRoot, mdr, xNew.Get(), cwcOld + cwc ); } //AddInProcessIsapiApp //+------------------------------------------------------------------------- // // Member: CMetaDataMgr::EnableVPathNotify, public // // Synopsis: Enables notification of vpaths // // Arguments: [pCallBack] - called on a change to any vpaths // // History: 07-Feb-1997 dlee Created // //-------------------------------------------------------------------------- void CMetaDataMgr::EnableVPathNotify( CMetaDataVPathChangeCallBack *pCallBack ) { Win4Assert( !_fTopLevel ); Win4Assert( !_fNotifyEnabled ); if ( _fNotifyEnabled ) THROW( CException( HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ) ) ); ciDebugOut(( DEB_WARN, "enabling vpath notifications on '%ws'\n", _awcInstance )); Win4Assert( _xSink.IsNull() ); // // NOTE: This new will be reported as a leak if iisamin dies or fails // to call Release() on the sink the right number of times. // XInterface xSink( new CMetaDataComSink() ); xSink->SetCallBack( pCallBack ); xSink->SetInstance( _awcInstance ); XInterface< IConnectionPointContainer > xCPC; SCODE sc = _xAdminBase->QueryInterface( IID_IConnectionPointContainer, xCPC.GetQIPointer() ); if ( FAILED( sc ) ) { ciDebugOut(( DEB_WARN, "could not get cpc: 0x%x\n", sc )); THROW( CException( sc ) ); } XInterface< IConnectionPoint> xCP; sc = xCPC->FindConnectionPoint( IID_IMSAdminBaseSink, xCP.GetPPointer() ); if ( FAILED( sc ) ) { ciDebugOut(( DEB_WARN, "could not get cp: 0x%x\n", sc )); THROW( CException( sc ) ); } // // Tell COM to impersonate at IMPERSONATE level instead of the default // IDENTITY level. This is to work-around a change made in IIS in // Windows 2000 SP1. // sc = CoSetProxyBlanket( xCP.GetPointer(), RPC_C_AUTHN_WINNT, // use NT default security RPC_C_AUTHZ_NONE, // use NT default authentication NULL, // must be null if default RPC_C_AUTHN_LEVEL_CALL, // call RPC_C_IMP_LEVEL_IMPERSONATE, NULL, // use process token EOAC_STATIC_CLOAKING ); if ( FAILED( sc ) ) { ciDebugOut(( DEB_WARN, "could not set proxy blanket: %#x\n", sc )); THROW( CException( sc ) ); } sc = xCP->Advise( xSink.GetPointer(), &_dwCookie); if ( FAILED( sc ) ) { ciDebugOut(( DEB_WARN, "could not advise cp: 0x%x\n", sc )); THROW( CException( sc ) ); } _xCP.Set( xCP.Acquire() ); _xSink.Set( xSink.Acquire() ); _fNotifyEnabled = TRUE; } //EnableVPathNotify //+------------------------------------------------------------------------- // // Member: CMetaDataMgr::DisableVPathNotify, public // // Synopsis: Disables notification on VPaths // // History: 07-Feb-1997 dlee Created // //-------------------------------------------------------------------------- void CMetaDataMgr::DisableVPathNotify() { if ( _fNotifyEnabled ) { SCODE sc = _xCP->Unadvise( _dwCookie ); ciDebugOut(( DEB_ITRACE, "result of unadvise: 0x%x\n", sc )); _fNotifyEnabled = FALSE; // // Note: The sink may still have a refcount after the free if // iisadmin has a bug or their process died. We can't just // delete it here because CoUninitialize() will realize // iisadmin messed up and try to help by calling Release() // for iisadmin. // _xSink.Free(); _xCP.Free(); } } //DisableVPathNotify //+------------------------------------------------------------------------- // // Member: CMetaDataMgr::ReportVPath, private // // Synopsis: Helper method for reporting a vpath via callback // // Arguments: [vrootStack] - stack of vroots for depth-first search // [mdRoot] - handle to the root of the enumeration // [callBack] - callback to call for vpath // [pwcRelative] - relative path in metabase // // Returns: TRUE if the vpath is a vroot and was pushed on vrootStack // // History: 07-Feb-1997 dlee Created // //-------------------------------------------------------------------------- BOOL CMetaDataMgr::ReportVPath( CVRootStack & vrootStack, CMetaDataCallBack & callBack, CMetaDataHandle & mdRoot, WCHAR const * pwcRelative ) { Win4Assert( !_fTopLevel ); // read the path, username, access permissions, and password WCHAR awcPPath[ METADATA_MAX_NAME_LEN ]; awcPPath[0] = 0; WCHAR awcUser[ METADATA_MAX_NAME_LEN ]; awcUser[0] = 0; DWORD dwAccess = 0; WCHAR awcPassword[ METADATA_MAX_NAME_LEN ]; awcPassword[0] = 0; BOOL fIsIndexed = TRUE; BOOL fVRoot = TRUE; // Get the metabase access permission mask { METADATA_RECORD mdr; RtlZeroMemory( &mdr, sizeof mdr ); mdr.dwMDIdentifier = MD_ACCESS_PERM; mdr.dwMDAttributes = METADATA_INHERIT; mdr.pbMDData = (BYTE *) &dwAccess; mdr.dwMDDataLen = sizeof dwAccess; DWORD cbRequired = 0; SCODE sc = _xAdminBase->GetData( mdRoot.Get(), pwcRelative, &mdr, &cbRequired ); if ( ( FAILED( sc ) ) && ( (MD_ERROR_DATA_NOT_FOUND) != sc ) ) { ciDebugOut(( DEB_WARN, "GetData awccessperm failed: 0x%x\n", sc )); THROW( CException( sc ) ); } } // Get the physical path if one exists { METADATA_RECORD mdr; RtlZeroMemory( &mdr, sizeof mdr ); mdr.dwMDIdentifier = MD_VR_PATH; mdr.pbMDData = (BYTE *) awcPPath; mdr.dwMDDataLen = sizeof awcPPath; DWORD cbRequired = 0; SCODE sc = _xAdminBase->GetData( mdRoot.Get(), pwcRelative, &mdr, &cbRequired ); if ( ( FAILED( sc ) ) && ( (MD_ERROR_DATA_NOT_FOUND) != sc ) ) { ciDebugOut(( DEB_WARN, "GetData PRoot failed: 0x%x\n", sc )); THROW( CException( sc ) ); } } // // Only look for a username/access/password if there is a physical path, // since it can only be a virtual root if it has a physical path. // if ( 0 != awcPPath[0] ) { // Trim any trailing backslash from the physical path unsigned cwcPRoot = wcslen( awcPPath ); Win4Assert( 0 != cwcPRoot ); if ( L'\\' == awcPPath[ cwcPRoot - 1 ] ) awcPPath[ cwcPRoot - 1 ] = 0; { METADATA_RECORD mdr; RtlZeroMemory( &mdr, sizeof mdr ); mdr.dwMDIdentifier = MD_VR_USERNAME; mdr.pbMDData = (BYTE *) awcUser; mdr.dwMDDataLen = sizeof awcUser; DWORD cbRequired = 0; SCODE sc = _xAdminBase->GetData( mdRoot.Get(), pwcRelative, &mdr, &cbRequired ); if ( ( FAILED( sc ) ) && ( (MD_ERROR_DATA_NOT_FOUND) != sc ) ) { ciDebugOut(( DEB_WARN, "GetData user failed: 0x%x\n", sc )); THROW( CException( sc ) ); } } { METADATA_RECORD mdr; RtlZeroMemory( &mdr, sizeof mdr ); mdr.dwMDIdentifier = MD_VR_PASSWORD; mdr.pbMDData = (BYTE *) awcPassword; mdr.dwMDDataLen = sizeof awcPassword; DWORD cbRequired = 0; SCODE sc = _xAdminBase->GetData( mdRoot.Get(), pwcRelative, &mdr, &cbRequired ); if ( ( FAILED( sc ) ) && ( (MD_ERROR_DATA_NOT_FOUND) != sc ) ) { ciDebugOut(( DEB_WARN, "GetData password failed: 0x%x\n", sc )); THROW( CException( sc ) ); } } } { METADATA_RECORD mdr; RtlZeroMemory( &mdr, sizeof mdr ); mdr.dwMDIdentifier = MD_IS_CONTENT_INDEXED; mdr.dwMDAttributes = METADATA_INHERIT; mdr.pbMDData = (BYTE *) &fIsIndexed; mdr.dwMDDataLen = sizeof fIsIndexed; DWORD cbRequired = 0; SCODE sc = _xAdminBase->GetData( mdRoot.Get(), pwcRelative, &mdr, &cbRequired ); if ( MD_ERROR_DATA_NOT_FOUND == sc ) { fIsIndexed = FALSE; } else if ( FAILED( sc ) ) { ciDebugOut(( DEB_WARN, "GetData isindexed failed: 0x%x\n", sc )); THROW( CException( sc ) ); } } WCHAR awcVPath[METADATA_MAX_NAME_LEN]; wcscpy( awcVPath, pwcRelative ); WCHAR *pwcVPath = awcVPath; // Important: The metabase names root "/Root" the rest of the world // names root "/". if ( !_wcsicmp( awcVPath, L"/Root" ) ) awcVPath[1] = 0; else if ( !_wcsnicmp( awcVPath, L"/Root", 5 ) ) { Win4Assert( L'/' == awcVPath[5] ); pwcVPath = awcVPath + 5; } if ( 0 == awcPPath[0] ) { // if there isn't a physical path, it isn't a virtual root. fVRoot = FALSE; if ( vrootStack.IsEmpty() ) { awcPPath[0] = 0; } else { // generate a physical path based on the virtual path and // the most recent vroot parent on the stack ciDebugOut(( DEB_ITRACE, "making vpath from vroot '%ws' proot '%ws' vpath '%ws'\n", vrootStack.PeekTopVRoot(), vrootStack.PeekTopPRoot(), pwcVPath )); wcscpy( awcPPath, vrootStack.PeekTopPRoot() ); unsigned cwcVRoot = wcslen( vrootStack.PeekTopVRoot() ); unsigned cwcPRoot = wcslen( vrootStack.PeekTopPRoot() ); // The metabase can contain trailing backslashes in physical paths if ( L'\\' == awcPPath[ cwcPRoot - 1 ] ) cwcPRoot--; wcscpy( awcPPath + cwcPRoot, pwcVPath + ( ( 1 == cwcVRoot ) ? 0 : cwcVRoot ) ); for ( WCHAR *pwc = awcPPath + cwcPRoot; 0 != *pwc; pwc++ ) { if ( L'/' == *pwc ) *pwc = L'\\'; } ciDebugOut(( DEB_ITRACE, "resulting ppath: '%ws'\n", awcPPath )); } } // now we can finally call the callback if ( 0 != awcPPath[0] ) callBack.CallBack( pwcVPath, awcPPath, fIsIndexed, dwAccess, awcUser, awcPassword, fVRoot ); if ( fVRoot ) vrootStack.Push( pwcVPath, awcPPath, dwAccess ); return fVRoot; } //ReportVPath //+------------------------------------------------------------------------- // // Member: CMetaDataMgr::EnumVServers, public // // Synopsis: Enumerates virtual servers by calling the callback // // Arguments: [callBack] - called for each vroot // // History: 07-Feb-1997 dlee Created // //-------------------------------------------------------------------------- void CMetaDataMgr::EnumVServers( CMetaDataVirtualServerCallBack & callBack ) { Win4Assert( _fTopLevel ); CMetaDataHandle mdRoot( _xAdminBase, _awcInstance ); Enum( callBack, mdRoot, L"" ); } //EnumVRoots //+------------------------------------------------------------------------- // // Member: CMetaDataMgr::ReportVirtualServer, private // // Synopsis: Helper method for reporting a virtual server via callback // // Arguments: [callBack] - callback to call for virtual server // [pwcRelative] - relative path in metabase // // History: 07-Feb-1997 dlee Created // //-------------------------------------------------------------------------- void CMetaDataMgr::ReportVirtualServer( CMetaDataVirtualServerCallBack & callBack, CMetaDataHandle & mdRoot, WCHAR const * pwcRelative ) { Win4Assert( _fTopLevel ); // read the comment WCHAR awcComment[ METADATA_MAX_NAME_LEN ]; awcComment[0] = 0; { METADATA_RECORD mdr; RtlZeroMemory( &mdr, sizeof mdr ); mdr.dwMDIdentifier = MD_SERVER_COMMENT; mdr.pbMDData = (BYTE *) awcComment; mdr.dwMDDataLen = sizeof awcComment; DWORD cbRequired = 0; SCODE sc = _xAdminBase->GetData( mdRoot.Get(), pwcRelative, &mdr, &cbRequired ); if ( ( FAILED( sc ) ) && ( (MD_ERROR_DATA_NOT_FOUND) != sc ) ) { ciDebugOut(( DEB_WARN, "GetData virtual server failed: 0x%x\n", sc )); THROW( CException( sc ) ); } } // // Convert ID to integer // DWORD iInstance = wcstoul( pwcRelative, 0, 10 ); // now we can finally call the callback callBack.CallBack( iInstance, awcComment ); } //ReportVirtualServer //+------------------------------------------------------------------------- // // Member: CMetaDataMgr::Enum, private // // Synopsis: Helper method for enumerating vpaths // // Arguments: [vrootStack] - stack of vroots for depth-first search // [callBack] - callback to call when a vpath is found // [mdRoot] - root of the enumeration // [pwcRelative] - relative location in enumeration // // History: 07-Feb-1997 dlee Created // //-------------------------------------------------------------------------- void CMetaDataMgr::Enum( CVRootStack & vrootStack, CMetaDataCallBack & callBack, CMetaDataHandle & mdRoot, WCHAR const * pwcRelative ) { // enumerate looking for vpaths int c = wcslen( pwcRelative ); WCHAR awcNewRelPath[ METADATA_MAX_NAME_LEN ]; RtlCopyMemory( awcNewRelPath, pwcRelative, (c + 1) * sizeof WCHAR ); if ( 0 == c || L'/' != pwcRelative[c-1] ) { wcscpy( awcNewRelPath + c, L"/" ); c++; } for ( int i = 0; ; i++ ) { WCHAR NameBuf[METADATA_MAX_NAME_LEN]; SCODE sc =_xAdminBase->EnumKeys( mdRoot.Get(), pwcRelative, NameBuf, i ); if ( RETURNCODETOHRESULT(ERROR_NO_MORE_ITEMS) == sc ) break; if ( FAILED( sc ) ) { ciDebugOut(( DEB_WARN, "EnumKeys error 0x%x\n", sc )); THROW( CException( sc ) ); } Win4Assert( 0 != NameBuf[0] ); Win4Assert( ( c + wcslen( NameBuf ) ) < METADATA_MAX_NAME_LEN ); wcscpy( awcNewRelPath + c, NameBuf ); BOOL fVRoot = ReportVPath( vrootStack, callBack, mdRoot, awcNewRelPath ); Enum( vrootStack, callBack, mdRoot, awcNewRelPath ); if ( fVRoot ) vrootStack.Pop(); } } //Enum //+------------------------------------------------------------------------- // // Member: CMetaDataMgr::Enum, private // // Synopsis: Helper method for enumerating virtual servers // // Arguments: [callBack] - callback to call when a vserver is found // [mdRoot] - root of the enumeration // [pwcRelative] - relative location in enumeration // // History: 07-Feb-1997 dlee Created // //-------------------------------------------------------------------------- void CMetaDataMgr::Enum( CMetaDataVirtualServerCallBack & callBack, CMetaDataHandle & mdRoot, WCHAR const * pwcRelative ) { // enumerate looking for virtual servers for ( int i = 0; ; i++ ) { WCHAR NameBuf[METADATA_MAX_NAME_LEN]; SCODE sc =_xAdminBase->EnumKeys( mdRoot.Get(), pwcRelative, NameBuf, i ); if ( RETURNCODETOHRESULT(ERROR_NO_MORE_ITEMS) == sc ) break; if ( FAILED( sc ) ) { ciDebugOut(( DEB_WARN, "EnumKeys error 0x%x\n", sc )); THROW( CException( sc ) ); } ciDebugOut(( DEB_WARN, "Key: %ws\n", NameBuf )); // // Ignore things that don't look like virtual servers. // if ( !isdigit( NameBuf[0] ) ) continue; // // Assume we just got a virtual server. // ReportVirtualServer( callBack, mdRoot, NameBuf ); } } //Enum //+------------------------------------------------------------------------- // // Member: CMetaDataMgr::GetVRoot, public // // Synopsis: Returns the physical root corresponding to a virtual root // // Arguments: [pwcVRoot] - VRoot to lookup // [pwcPRoot] - where pwcVRoot's physical root is returned // // History: 07-Feb-1997 dlee Created // //-------------------------------------------------------------------------- void CMetaDataMgr::GetVRoot( WCHAR const * pwcVRoot, WCHAR * pwcPRoot ) { Win4Assert( !_fTopLevel ); unsigned cwc = wcslen( _awcInstance ) + wcslen( L"/Root" ) + wcslen( pwcVRoot ); if ( cwc >= METADATA_MAX_NAME_LEN ) THROW( CException( E_INVALIDARG ) ); WCHAR awcVRootPath[ METADATA_MAX_NAME_LEN ]; wcscpy( awcVRootPath, _awcInstance ); wcscat( awcVRootPath, L"/Root" ); wcscat( awcVRootPath, pwcVRoot ); CMetaDataHandle mdVRoot( _xAdminBase, awcVRootPath, FALSE ); *pwcPRoot = 0; { METADATA_RECORD mdr; RtlZeroMemory( &mdr, sizeof mdr ); mdr.dwMDIdentifier = MD_VR_PATH; mdr.pbMDData = (BYTE *) pwcPRoot; mdr.dwMDDataLen = METADATA_MAX_NAME_LEN * sizeof WCHAR; DWORD cbRequired = 0; SCODE sc = _xAdminBase->GetData( mdVRoot.Get(), L"", &mdr, &cbRequired ); if ( FAILED( sc ) ) { ciDebugOut(( DEB_WARN, "GetData PRoot failed: 0x%x\n", sc )); THROW( CException( sc ) ); } } } //GetVRoot //+------------------------------------------------------------------------- // // Member: CMetaDataMgr::GetVRootPW, public // // Synopsis: Returns the physical root corresponding to a virtual root // // Arguments: [pwcVRoot] - VRoot to lookup // [pwcPRoot] - where pwcVRoot's physical root is returned // // History: 07-Feb-1997 dlee Created // //-------------------------------------------------------------------------- void CMetaDataMgr::GetVRootPW( WCHAR const * pwcVRoot, WCHAR * pwcPW ) { Win4Assert( !_fTopLevel ); unsigned cwc = wcslen( _awcInstance ) + wcslen( L"/Root" ) + wcslen( pwcVRoot ); if ( cwc >= METADATA_MAX_NAME_LEN ) THROW( CException( E_INVALIDARG ) ); WCHAR awcVRootPath[ METADATA_MAX_NAME_LEN ]; wcscpy( awcVRootPath, _awcInstance ); wcscat( awcVRootPath, L"/Root" ); wcscat( awcVRootPath, pwcVRoot ); CMetaDataHandle mdVRoot( _xAdminBase, awcVRootPath, FALSE ); *pwcPW = 0; { METADATA_RECORD mdr; RtlZeroMemory( &mdr, sizeof mdr ); mdr.dwMDIdentifier = MD_VR_PASSWORD; mdr.pbMDData = (BYTE *) pwcPW; mdr.dwMDDataLen = METADATA_MAX_NAME_LEN * sizeof WCHAR; DWORD cbRequired = 0; SCODE sc = _xAdminBase->GetData( mdVRoot.Get(), L"", &mdr, &cbRequired ); //char ac[ 1000 ]; //sprintf( ac, "result: 0x%x, cbResult: 0x%x, string: '%ws', char 1: 0x%x\n", // sc, mdr.dwMDDataLen, pwcPW, (ULONG) *pwcPW ); //DbgPrint( ac ); if ( FAILED( sc ) ) { ciDebugOut(( DEB_WARN, "GetData PRoot failed: 0x%x\n", sc )); THROW( CException( sc ) ); } } } //GetVRootPW //+------------------------------------------------------------------------- // // Member: CMetaDataMgr::SetIsIndexed, public // // Synopsis: Sets the indexed state of a virtual path // // Arguments: [pwcPath] - Virtual path (optionally a vroot) to set // [fIsIndexed] - if TRUE, path is indexed, if FALSE it isn't // // History: 19-Mar-1997 dlee Created // //-------------------------------------------------------------------------- void CMetaDataMgr::SetIsIndexed( WCHAR const * pwcVPath, BOOL fIsIndexed ) { // Add the key if it doesn't exist yet { unsigned cwc = wcslen( _awcInstance ) + wcslen( L"/Root" ); if ( cwc >= METADATA_MAX_NAME_LEN ) THROW( CException( E_INVALIDARG ) ); WCHAR awc[ METADATA_MAX_NAME_LEN ]; wcscpy( awc, _awcInstance ); wcscat( awc, L"/Root" ); CMetaDataHandle mdRoot( _xAdminBase, awc, TRUE ); _xAdminBase->AddKey( mdRoot.Get(), pwcVPath ); } unsigned cwc = wcslen( _awcInstance ) + wcslen( L"/Root" ) + wcslen( pwcVPath ); if ( cwc >= METADATA_MAX_NAME_LEN ) THROW( CException( E_INVALIDARG ) ); WCHAR awcCompleteVPath[ METADATA_MAX_NAME_LEN ]; wcscpy( awcCompleteVPath, _awcInstance ); wcscat( awcCompleteVPath, L"/Root" ); wcscat( awcCompleteVPath, pwcVPath ); CMetaDataHandle mdVRoot( _xAdminBase, awcCompleteVPath, TRUE ); { METADATA_RECORD mdr; RtlZeroMemory( &mdr, sizeof mdr ); mdr.dwMDIdentifier = MD_IS_CONTENT_INDEXED; mdr.dwMDAttributes = METADATA_INHERIT; mdr.dwMDUserType = IIS_MD_UT_FILE; mdr.dwMDDataType = DWORD_METADATA; mdr.pbMDData = (BYTE *) &fIsIndexed; mdr.dwMDDataLen = sizeof fIsIndexed; DWORD cbRequired = 0; SCODE sc = _xAdminBase->SetData( mdVRoot.Get(), L"", &mdr ); if ( FAILED( sc ) ) { ciDebugOut(( DEB_WARN, "SetData isindexed failed: 0x%x\n", sc )); THROW( CException( sc ) ); } } } //SetIsIndexed //+------------------------------------------------------------------------- // // Member: CMetaDataMgr::IsIndexed, public // // Synopsis: Checks the path to return the state of the IsIndexed flag. // The default for no value is TRUE. No checking is made to // if a parent directory is indexed or not. // // Arguments: [pwcVPath] - Virtual path (optionally a vroot) to check // // History: 19-Mar-1997 dlee Created // //-------------------------------------------------------------------------- BOOL CMetaDataMgr::IsIndexed( WCHAR const * pwcVPath ) { BOOL fIsIndexed = TRUE; unsigned cwc = wcslen( _awcInstance ) + wcslen( L"/Root" ) + wcslen( pwcVPath ); if ( cwc >= METADATA_MAX_NAME_LEN ) THROW( CException( E_INVALIDARG ) ); WCHAR awcCompletePath[ METADATA_MAX_NAME_LEN ]; wcscpy( awcCompletePath, _awcInstance ); wcscat( awcCompletePath, L"/Root" ); wcscat( awcCompletePath, pwcVPath ); TRY { CMetaDataHandle mdVRoot( _xAdminBase, awcCompletePath, FALSE ); { METADATA_RECORD mdr; RtlZeroMemory( &mdr, sizeof mdr ); mdr.dwMDIdentifier = MD_IS_CONTENT_INDEXED; mdr.dwMDAttributes = METADATA_INHERIT; mdr.pbMDData = (BYTE *) &fIsIndexed; mdr.dwMDDataLen = sizeof fIsIndexed; DWORD cbRequired = 0; SCODE sc = _xAdminBase->GetData( mdVRoot.Get(), L"", &mdr, &cbRequired ); if ( MD_ERROR_DATA_NOT_FOUND == sc ) { fIsIndexed = FALSE; } else if ( FAILED( sc ) ) { ciDebugOut(( DEB_WARN, "GetData isindexed failed: 0x%x\n", sc )); THROW( CException( sc ) ); } } } CATCH( CException, e ) { // ignore -- assume IsIndexed } END_CATCH; return fIsIndexed; } //IsIndexed //+------------------------------------------------------------------------- // // Member: CMetaDataMgr::GetVPathFlags, public // // Synopsis: Returns flag settings on a virtual path // // Arguments: [pwcVPath] - Virtual path (optionally a vroot) to check // [mdID] - MD_x constant for the data // [ulDefault] - Default if no value is in the metabase // // History: 18-Aug-1997 dlee Created // //-------------------------------------------------------------------------- ULONG CMetaDataMgr::GetVPathFlags( WCHAR const * pwcVPath, ULONG mdID, ULONG ulDefault ) { unsigned cwc = wcslen( _awcInstance ) + wcslen( L"/Root" ) + wcslen( pwcVPath ); if ( cwc >= METADATA_MAX_NAME_LEN ) THROW( CException( E_INVALIDARG ) ); WCHAR awcCompletePath[ METADATA_MAX_NAME_LEN ]; wcscpy( awcCompletePath, _awcInstance ); wcscat( awcCompletePath, L"/Root" ); wcscat( awcCompletePath, pwcVPath ); DWORD dwFlags = ulDefault; // Keep removing path components on the right of the path until // either out of path or the metabase recognizes the path. METADATA_HANDLE h; do { SCODE sc = _xAdminBase->OpenKey( METADATA_MASTER_ROOT_HANDLE, awcCompletePath, METADATA_PERMISSION_READ, cmsCIMetabaseTimeout, &h ); if ( S_OK == sc ) { break; } else if ( HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) == sc ) { WCHAR * pwc = wcsrchr( awcCompletePath, L'/' ); if ( 0 == pwc ) THROW( CException( sc ) ); *pwc = 0; } else THROW( CException( sc ) ); } while ( TRUE ); CMetaDataHandle mdVRoot( _xAdminBase, h ); { METADATA_RECORD mdr; RtlZeroMemory( &mdr, sizeof mdr ); mdr.dwMDIdentifier = mdID; mdr.dwMDAttributes = METADATA_INHERIT; mdr.pbMDData = (BYTE *) &dwFlags; mdr.dwMDDataLen = sizeof dwFlags; DWORD cbRequired = 0; SCODE sc = _xAdminBase->GetData( mdVRoot.Get(), L"", &mdr, &cbRequired ); if ( MD_ERROR_DATA_NOT_FOUND == sc ) { // no value specified for this flag; use default dwFlags = ulDefault; } else if ( FAILED( sc ) ) { ciDebugOut(( DEB_WARN, "GetData mdid %d failed: 0x%x on '%ws'\n", mdID, sc, awcCompletePath )); THROW( CException( sc ) ); } } return dwFlags; } //GetVPathFlags //+------------------------------------------------------------------------- // // Member: CMetaDataMgr::GetVPathAccess, public // // Synopsis: Returns access permission settings on a virtual path // // Arguments: [pwcVPath] - Virtual path (optionally a vroot) to check // // History: 18-Aug-1997 dlee Created // //-------------------------------------------------------------------------- ULONG CMetaDataMgr::GetVPathAccess( WCHAR const * pwcVPath ) { // note: the default of 0 is from IIS' metabase guru return GetVPathFlags( pwcVPath, MD_ACCESS_PERM, 0 ); } //GetVPathAccess //+------------------------------------------------------------------------- // // Member: CMetaDataMgr::GetVPathSSLAccess, public // // Synopsis: Returns SSL access permission settings on a virtual path // // Arguments: [pwcVPath] - Virtual path (optionally a vroot) to check // // History: 18-Aug-1997 dlee Created // //-------------------------------------------------------------------------- ULONG CMetaDataMgr::GetVPathSSLAccess( WCHAR const * pwcVPath ) { // note: the default of 0 is from IIS' metabase guru return GetVPathFlags( pwcVPath, MD_SSL_ACCESS_PERM, 0 ); } //GetVPathSSLAccess //+------------------------------------------------------------------------- // // Member: CMetaDataMgr::GetVPathAuthorization, public // // Synopsis: Returns authorization on a virtual path // // Arguments: [pwcVPath] - Virtual path (optionally a vroot) to check // // History: 18-Aug-1997 dlee Created // //-------------------------------------------------------------------------- ULONG CMetaDataMgr::GetVPathAuthorization( WCHAR const * pwcVPath ) { // note: the default of MD_AUTH_ANONYMOUS is from IIS' metabase guru return GetVPathFlags( pwcVPath, MD_AUTHORIZATION, MD_AUTH_ANONYMOUS ); } //GetVPathAuthorization //+------------------------------------------------------------------------- // // Member: CMetaDataComSink::SinkNotify, public // // Synopsis: Called for any metadata change // // Arguments: [cChanges] - # of changes in pcoChangeList // [pcoChangeList] - list of changes // // History: 07-Feb-1997 dlee Created // //-------------------------------------------------------------------------- SCODE STDMETHODCALLTYPE CMetaDataComSink::SinkNotify( DWORD cChanges, MD_CHANGE_OBJECT pcoChangeList[] ) { // This is called by an RPC worker thread -- assimilate it TRANSLATE_EXCEPTIONS; TRY { int cwcInstance = wcslen( _awcInstance ); BOOL fInterestingChange = FALSE; ciDebugOut(( DEB_WARN, "iis sinknotify '%ws', cchanges: %d\n", _awcInstance, cChanges )); for ( DWORD i = 0; !fInterestingChange && i < cChanges; i++ ) { MD_CHANGE_OBJECT & co = pcoChangeList[i]; // we only care about notifications to our instance if ( _wcsnicmp( co.pszMDPath, _awcInstance, cwcInstance ) != 0 || ( L'/' != co.pszMDPath[cwcInstance] && L'\0' != co.pszMDPath[cwcInstance] ) ) continue; // Ignore adds of vroots -- we'll get a set_data for its // parameters and trigger on that. if ( ( MD_CHANGE_TYPE_DELETE_OBJECT & co.dwMDChangeType ) || ( MD_CHANGE_TYPE_RENAME_OBJECT & co.dwMDChangeType ) ) { // guess that the deletion was a vroot fInterestingChange = TRUE; } else if ( ( MD_CHANGE_TYPE_SET_DATA & co.dwMDChangeType ) || ( MD_CHANGE_TYPE_DELETE_DATA & co.dwMDChangeType ) ) { for ( DWORD x = 0; x < co.dwMDNumDataIDs; x++ ) { DWORD id = co.pdwMDDataIDs[x]; if ( MD_VR_PATH == id || MD_VR_USERNAME == id || MD_VR_PASSWORD == id || MD_ACCESS_PERM == id || MD_IS_CONTENT_INDEXED == id ) { fInterestingChange = TRUE; break; } } } } if ( fInterestingChange && ( 0 != _pCallBack ) ) _pCallBack->CallBack( FALSE ); } CATCH (CException, e) { ciDebugOut(( DEB_WARN, "SinkNotify caught 0x%x\n", e.GetErrorCode() )); } END_CATCH UNTRANSLATE_EXCEPTIONS; return S_OK; } //SinkNotify //+------------------------------------------------------------------------- // // Member: CMetaDataComSink::ShutdownNotify, public // // Synopsis: Called when iisadmin is going down cleanly // // History: 07-Feb-1997 dlee Created // //-------------------------------------------------------------------------- SCODE STDMETHODCALLTYPE CMetaDataComSink::ShutdownNotify() { // This is called by an RPC worker thread -- assimilate it TRANSLATE_EXCEPTIONS; TRY { ciDebugOut(( DEB_WARN, "iis shutdownnotify '%ws'\n", _awcInstance )); // in case we get more random notifications, ignore them CMetaDataVPathChangeCallBack * pCallBack = _pCallBack; _pCallBack = 0; pCallBack->CallBack( TRUE ); } CATCH (CException, e) { ciDebugOut(( DEB_WARN, "ShutdownNotify caught 0x%x\n", e.GetErrorCode() )); } END_CATCH UNTRANSLATE_EXCEPTIONS; return S_OK; } //ShutdownNotify