#include "StdAfx.h" #include "ACShim.h" #include #include #include "reg.hxx" // Undef PathAppend, or TSTR::PathAppend will not work #undef PathAppend // ProcessIISShims // // Open the app compat database and process all the IIS // entries // BOOL ProcessIISShims() { PDB hCompatDB = NULL; BOOL bRet = TRUE; TSTR_PATH strCompatDB; iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Processeing AppCompat DB.\n") ) ); if ( !strCompatDB.RetrieveWindowsDir() || !strCompatDB.PathAppend( APPCOMPAT_DBNAME ) ) { // Failed to create path return FALSE; } hCompatDB = SdbOpenDatabase( strCompatDB.QueryStr(), DOS_PATH ); if ( hCompatDB == NULL ) { // Failed to open DB return FALSE; } bRet = ProcessAppCompatDB( hCompatDB ); SdbCloseDatabase( hCompatDB ); return bRet; } // ProcessAppCompatDB // // Loop through all of the App Compat entries, and process // the ones that are IIS's // BOOL ProcessAppCompatDB( PDB hCompatDB ) { TAGID tagDB; TAGID tagExe; BOOL bRet = TRUE; HRESULT hrCoInit; tagDB = SdbFindFirstTag( hCompatDB, TAGID_ROOT, TAG_DATABASE ); if ( tagDB == NULL ) { // Failed to open DB return FALSE; } hrCoInit = CoInitialize( NULL ); if ( FAILED( hrCoInit ) ) { iisDebugOut((LOG_TYPE_WARN, _T("Failed to CoInitialize to process AppCompat tag's, hr=0x%8x.\n"), hrCoInit)); return FALSE; } tagExe = SdbFindFirstTag( hCompatDB, tagDB, TAG_EXE ); while( tagExe != NULL ) { if ( !ProcessExeTag( hCompatDB, tagExe ) ) { // Failed to process tag iisDebugOut((LOG_TYPE_WARN, _T("Failed to process AppCompat EXE tag.\n"))); bRet = FALSE; } // Get the next one tagExe = SdbFindNextTag( hCompatDB, tagDB, tagExe ); } CoUninitialize(); return bRet; } // ProcessExeTag // // Process All of the Exe Tags that we have // BOOL ProcessExeTag( PDB hCompatDB, TAGID tagExe ) { TAGID tagExeInfo; BOOL bRet = TRUE; tagExeInfo = SdbGetFirstChild( hCompatDB, tagExe ); while ( tagExeInfo != NULL ) { if ( IsIISShim( hCompatDB, tagExeInfo ) ) { iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Processing IIS Exe AppCompat Info tag.\n"))); if ( !ProcessShimTag( hCompatDB, tagExeInfo ) ) { iisDebugOut((LOG_TYPE_WARN, _T("Failed to process AppCompat EXE Info tag.\n"))); bRet = FALSE; } } // Get next tag tagExeInfo = SdbGetNextChild( hCompatDB, tagExe, tagExeInfo ); } return bRet; } // ProcessShimTag // // Process the Shim Tag // BOOL ProcessShimTag( PDB hCompatDB, TAGID tagShim ) { TSTR_PATH strBasePath; CExtensionList ExtenstionList; if ( !GetBasePath( &strBasePath, hCompatDB, tagShim ) ) { // This entry does not have a base path, so ignore return TRUE; } if ( !PathIsDirectory( strBasePath.QueryStr() ) ) { // The directory does not exist, so it must not be installed return TRUE; } if ( !BuildExtensionList( hCompatDB, tagShim, strBasePath.QueryStr(), &ExtenstionList ) ) { // Failed to construct List return FALSE; } if ( ExtenstionList.DoesAnItemExist() ) { if ( !InstallAppInMB( hCompatDB, tagShim, ExtenstionList ) ) { return FALSE; } } return TRUE; } // GetBasePath // // Get the Base Path for the Shim Tag we are talking about. // This is either going to be a physical path or a registry entry with // the path // BOOL GetBasePath( TSTR_PATH *pstrBasePath, PDB hCompatDB, TAGID tagShim ) { TSTR strDBPath; TSTR strType; ASSERT( hCompatDB != NULL ); ASSERT( tagShim != NULL ); if ( !GetValueFromName( &strDBPath, hCompatDB, tagShim, APPCOMPAT_TAG_BASEPATH ) || !GetValueFromName( &strType, hCompatDB, tagShim, APPCOMPAT_TAG_PATHTYPE ) ) { // Failed to get Base Path return FALSE; } if ( strType.IsEqual( APPCOMPAT_TYPE_PHYSICALPATH ) ) { // This is a phsycial path, so expand environment variables and return if ( !pstrBasePath->Copy( strDBPath ) || !pstrBasePath->ExpandEnvironmentVariables() ) { // Failed return FALSE; } return TRUE; } // It is a registry key instead, so lets retrieve it return GetBasePathFromRegistry( pstrBasePath, strDBPath ); } // GetBasePathFromRegistry // // Retrieve the Base Path for an entry, by reading the registry key // that contains it // // Parameters // pstrBasePath - [out] The path from the registry // strFullRegPath - [in] The registry path to check // BOOL GetBasePathFromRegistry( TSTR_PATH *pstrBasePath, TSTR &strFullRegPath ) { TSTR strRegBase; TSTR strRegPath; TSTR strRegName; LPTSTR szFirstSlash; LPTSTR szLastSlash; szFirstSlash = _tcschr( strFullRegPath.QueryStr(), _T('\\') ); szLastSlash = _tcsrchr( strFullRegPath.QueryStr(), _T('\\') ); if ( ( szFirstSlash == NULL ) || ( szLastSlash == NULL ) || ( szLastSlash == szFirstSlash ) ) { // If there are not atleast 2 '\'s then it is not a correct registry path return FALSE; } // Temporarily Null terminate strings *szFirstSlash = _T('\0'); *szLastSlash = _T('\0'); if ( !strRegBase.Copy( strFullRegPath.QueryStr() ) || !strRegPath.Copy( szFirstSlash + 1 ) || !strRegName.Copy( szLastSlash + 1 ) ) { // Failed to copy path's *szFirstSlash = _T('\\'); *szLastSlash = _T('\\'); return FALSE; } // Insert back the slashes *szFirstSlash = _T('\\'); *szLastSlash = _T('\\'); return RetrieveRegistryString( pstrBasePath, strRegBase, strRegPath, strRegName ); } // RetrieveRegistryString // // Retrieve a string from the registry // // Parameters: // pstrValue - [out] The value retrieved from the registry // strRegBase - [in] The base path, ie HKEY_LOCAL_MACHINE // strRegPath - [in] The path to the registry key // strRegName - [in] The name of the registry value // BOOL RetrieveRegistryString( TSTR_PATH *pstrValue, TSTR &strRegBase, TSTR &strRegPath, TSTR &strRegName ) { CRegistry Reg; HKEY hRoot; if ( strRegBase.IsEqual( APPCOMPAT_REG_HKLM, FALSE ) ) { hRoot = HKEY_LOCAL_MACHINE; } else if ( strRegBase.IsEqual( APPCOMPAT_REG_HKCU, FALSE ) ) { hRoot = HKEY_CURRENT_USER; } else if ( strRegBase.IsEqual( APPCOMPAT_REG_HKCR, FALSE ) ) { hRoot = HKEY_CLASSES_ROOT; } else if ( strRegBase.IsEqual( APPCOMPAT_REG_HKU, FALSE ) ) { hRoot = HKEY_USERS; } else if ( strRegBase.IsEqual( APPCOMPAT_REG_HKCC, FALSE ) ) { hRoot = HKEY_CURRENT_CONFIG; } else { return FALSE; } if ( !Reg.OpenRegistry( hRoot, strRegPath.QueryStr(), KEY_READ ) ) { // Failed to open registry return FALSE; } if ( !Reg.ReadValueString( strRegName.QueryStr(), pstrValue ) ) { // Failed to read string from registry return FALSE; } return TRUE; } // BuildExtensionList // // Build the extension list from the Compat DB for this tag // // Parameters: // hCompatDB - [in] Pointer to compat DB // tagShim - [in] Tag to process // szBasePath - [in] Base path for these extensions // pExtensions - [out] Extensions class to add them too // BOOL BuildExtensionList( PDB hCompatDB, TAGID tagShim, LPTSTR szBasePath, CExtensionList *pExtensions ) { TSTR_PATH strExtFullPath; TSTR strExtensions; TSTR strIndicatorFile; LPTSTR szExtensions; LPTSTR szNext; iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Building extension list.\n") ) ); if ( GetValueFromName( &strIndicatorFile, hCompatDB, tagShim, APPCOMPAT_TAG_SETUPINDICATOR ) ) { // SetupIndicator File is Set if ( !strExtFullPath.Copy( szBasePath ) || !strExtFullPath.PathAppend( strIndicatorFile ) || !pExtensions->SetIndicatorFile( strExtFullPath.QueryStr() ) ) { // Failed to set indicator file return FALSE; } iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Indicator File found, it is '%s'.\n"), strExtFullPath.QueryStr() ) ); } if ( !GetValueFromName( &strExtensions, hCompatDB, tagShim, APPCOMPAT_TAG_WEBSVCEXT ) ) { // No WebSvcExtension to retrieve return TRUE; } iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Building extension list with '%s'.\n"), strExtensions.QueryStr() ) ); // Get pointer to begining of list szExtensions = strExtensions.QueryStr(); while ( szExtensions && *szExtensions ) { szNext = _tcschr( szExtensions, _T(',') ); if ( szNext ) { *szNext = _T('\0'); szNext++; } if ( !strExtFullPath.Copy( szBasePath ) || !strExtFullPath.PathAppend( szExtensions ) ) { // Failed to construct path return FALSE; } if ( !pExtensions->AddItem( strExtFullPath.QueryStr(), PathFileExists( strExtFullPath.QueryStr() ) ) ) { // Failed to add item to list return FALSE; } szExtensions = szNext; } return TRUE; } // InstallAppInMB // // Installs the Application Extensions and dependencies into the metabase // tagShim points to the Shim entry in the AppCompat DB where all App settings reside // BOOL InstallAppInMB( PDB hCompatDB, TAGID tagShim, CExtensionList &ExtensionList ) { TSTR strGroupId; TSTR strGroupDesc; TSTR strAppName; TSTR strExtGroups; TSTR strPath; BOOL bExists; CSecConLib Helper; DWORD i; BOOL bRet; HRESULT hr; // Ignore if we can not get this value, since it is not necessary GetValueFromName( &strExtGroups, hCompatDB, tagShim, APPCOMPAT_DB_ENABLE_EXT_GROUPS ); if ( !GetValueFromName( &strGroupId, hCompatDB, tagShim, APPCOMPAT_DB_GROUPID ) || !GetValueFromName( &strGroupDesc, hCompatDB, tagShim, APPCOMPAT_DB_GROUPDESC ) || !GetValueFromName( &strAppName, hCompatDB, tagShim, APPCOMPAT_DB_APPNAME ) ) { iisDebugOut( ( LOG_TYPE_PROGRAM_FLOW, _T("Could not retrieve all values for App from DB, so will not add to RestrictionList. ('%s','%s','%s','%s')\n"), strGroupId.QueryStr() ? strGroupId.QueryStr() : _T(""), strGroupDesc.QueryStr() ? strGroupDesc.QueryStr() : _T(""), strAppName.QueryStr() ? strAppName.QueryStr() : _T(""), strExtGroups.QueryStr() ? strExtGroups.QueryStr() : _T("")) ); // Failed to retrieve value return TRUE; } iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Adding '%s' group to WebSvcRestriction List from AppCompat DB.\n"), strGroupId.QueryStr() ) ); // Add Extensions for ( i = 0; i < ExtensionList.QueryNumberofItems(); i++ ) { if ( !ExtensionList.QueryItem( i, &strPath, &bExists ) ) { // Failed to retrieve return FALSE; } hr = Helper.AddExtensionFile( strPath.QueryStr(), // Path g_pTheApp->IsUpgrade() ? true : false, // Image should be enabled strGroupId.QueryStr(), // GroupID FALSE, // Not UI deletable strGroupDesc.QueryStr(),// Group description METABASEPATH_WWW_ROOT ); // MB location if ( FAILED( hr ) && ( hr != HRESULT_FROM_WIN32(ERROR_DUP_NAME) ) ) { bRet = FALSE; iisDebugOut((LOG_TYPE_ERROR, _T("Failed to add extension %s to group %s, hr=0x%8x\n"), strPath.QueryStr(), strGroupId.QueryStr(), hr )); } } // Add Dependencies if ( *(strGroupId.QueryStr()) != _T('\0') ) { hr = Helper.AddDependency( strAppName.QueryStr(), strGroupId.QueryStr(), METABASEPATH_WWW_ROOT ); if ( FAILED( hr ) && ( hr != HRESULT_FROM_WIN32(ERROR_DUP_NAME) ) ) { bRet = FALSE; iisDebugOut((LOG_TYPE_ERROR, _T("Failed to add dependence ( App: %s on GroupID %s ), hr=0x%8x\n"), strAppName.QueryStr(), strGroupId.QueryStr(), hr )); } } // Add all the other "external" groups it depends on if ( ( *strExtGroups.QueryStr() ) != _T('\0') ) { LPTSTR szCurrentGroup = strExtGroups.QueryStr(); LPTSTR szNextGroup; while ( szCurrentGroup && *szCurrentGroup ) { szNextGroup = _tcschr( szCurrentGroup, _T(',') ); if ( szNextGroup ) { *szNextGroup = _T('\0'); szNextGroup++; } hr = Helper.AddDependency( strAppName.QueryStr(), szCurrentGroup, METABASEPATH_WWW_ROOT ); if ( FAILED( hr ) && ( hr != HRESULT_FROM_WIN32(ERROR_DUP_NAME) ) ) { bRet = FALSE; iisDebugOut((LOG_TYPE_ERROR, _T("Failed to add dependence ( App: %s on Group %s ), hr = %8x\n"), strAppName.QueryStr(), szCurrentGroup, hr )); } szCurrentGroup = szNextGroup; } } return bRet; } // IsIISShim // // Is the Tag an IIS Shim Tag // BOOL IsIISShim( PDB hCompatDB, TAGID tagCurrentTag ) { TAG tagType; TAGID tagShimName; TSTR strTagName; tagType = SdbGetTagFromTagID( hCompatDB, tagCurrentTag ); if ( tagType != TAG_SHIM_REF ) { // We handle only tags return FALSE; } if ( !strTagName.Resize( MAX_PATH ) ) { // Failed to widen buffer return FALSE; } tagShimName = SdbFindFirstTag( hCompatDB, tagCurrentTag, TAG_NAME ); if ( tagShimName == NULL ) { // There is not tag name, so this is not an IIS one. return FALSE; } if ( !SdbReadStringTag( hCompatDB, tagShimName, strTagName.QueryStr(), strTagName.QuerySize() ) ) { // Failed to read string tag return FALSE; } return strTagName.IsEqual( APPCOMPAT_TAG_SHIM_IIS, FALSE ); } // GetValueFromName // // Frab a value out of the Database with the Name we have given // // Parameters: // pstrValue - [out] The value that was in the database // hCompatDB - [in] Handle to DB // tagData - [in] The tag to retrieve it from // szTagName - [in] The name of the tag to retrieve // BOOL GetValueFromName( TSTR *pstrValue, PDB hCompatDB, TAGID tagData, LPCTSTR szTagName ) { TAGID tagChild; TAGID tagValue; LPTSTR szValue; tagChild = SdbFindFirstNamedTag( hCompatDB, tagData, TAG_DATA, TAG_NAME, szTagName ); if ( tagChild == NULL ) { // Failed to find tag return FALSE; } tagValue = SdbFindFirstTag( hCompatDB, tagChild, TAG_DATA_STRING ); if ( tagValue == NULL ) { // Failed to retrieve tag return FALSE; } szValue = SdbGetStringTagPtr( hCompatDB, tagValue ); if ( szValue == NULL ) { // Not value found, so lets just set to an empty string szValue = _T(""); } return pstrValue->Copy( szValue ); } // Constructor // // CExtensionList::CExtensionList() { m_dwNumberofItems = 0; m_pRoot = NULL; m_bUseIndicatorFile = FALSE; m_bIndicatorFileExists = FALSE; } // Destructor // // CExtensionList::~CExtensionList() { sExtensionItem *pCurrent; sExtensionItem *pTemp; pCurrent = m_pRoot; while ( pCurrent ) { pTemp = pCurrent; pCurrent = pCurrent->pNext; delete pTemp; } m_pRoot = NULL; m_dwNumberofItems = 0; } // AddItem // // Add an Item to the list // // Parameters: // szPath - Data for item // bExists - Data for Item BOOL CExtensionList::AddItem( LPTSTR szPath, BOOL bExists ) { sExtensionItem *pNewItem; sExtensionItem *pLastItem = NULL; iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Adding item '%s',0x%8x.\n"), szPath, bExists ) ); if ( QueryNumberofItems() != 0 ) { pLastItem = RetrieveItem( QueryNumberofItems() - 1 ); if ( pLastItem == NULL ) { // For some read we can not get the nth item, which should exist ASSERT( FALSE ); return FALSE; } } pNewItem = new sExtensionItem; if ( pNewItem == NULL ) { return FALSE; } if ( !pNewItem->strName.Copy( szPath ) ) { delete pNewItem; return FALSE; } pNewItem->bExists = bExists; pNewItem->pNext = NULL; m_dwNumberofItems++; if ( pLastItem ) { pLastItem->pNext = pNewItem; } else { m_pRoot = pNewItem; } return TRUE; } // QueryItem // // Query the Data on a particular item // BOOL CExtensionList::QueryItem( DWORD dwIndex, TSTR *pstrPath, LPBOOL pbExists) { sExtensionItem *pCurrent; pCurrent = RetrieveItem( dwIndex ); if ( pCurrent == NULL ) { // That item does not exist return FALSE; } if ( !pstrPath->Copy( pCurrent->strName ) ) { // Could not copy name return FALSE; } *pbExists = pCurrent->bExists; return TRUE; } // QueryNumberofItems // // Query the number of items in the list // DWORD CExtensionList::QueryNumberofItems() { return m_dwNumberofItems; } // RetrieveItem // // Retrieve a specific item by its index // sExtensionItem * CExtensionList::RetrieveItem( DWORD dwIndex ) { sExtensionItem *pCurrent = m_pRoot; while ( ( pCurrent ) && ( dwIndex != 0 ) ) { pCurrent = pCurrent->pNext; dwIndex--; } return pCurrent; } // DoesAnItemExist // // Go through all of the items in our list, // and determine if any of them have the bExists flag // set // BOOL CExtensionList::DoesAnItemExist() { sExtensionItem *pCurrent = m_pRoot; if ( m_bUseIndicatorFile ) { // If an indicator file is used, then just use this return m_bIndicatorFileExists; } while ( pCurrent ) { if ( pCurrent->bExists ) { // Found one that exists return TRUE; } pCurrent = pCurrent->pNext; } // None existed return FALSE; } // SetIndicatorFile // // If an indicator file is set, then use the fact that this is installed // instead of checking all the other files // BOOL CExtensionList::SetIndicatorFile( LPTSTR szIndicatorFile ) { m_bUseIndicatorFile = TRUE; m_bIndicatorFileExists = PathFileExists( szIndicatorFile ); return TRUE; }