/*++ Copyright (c) 1998-1999 Microsoft Corporation Module Name: flbuilder.cpp Abstract: This class uses the CXMLFileListParser, CFLHashList and CFLPathTree classses to take an a protected XML file and build a data file for the FL. Author: Kanwaljit Marok (kmarok) 01-May-2000 Revision History: --*/ #include #include #include #include #include #include "srdefs.h" //#include //#include //#include //#include #include #include #ifdef _ASSERT #undef _ASSERT #endif #include #include #include #include "xmlparser.h" #include "flbuilder.h" #include "flpathtree.h" #include "flhashlist.h" #include "commonlibh.h" #include "datastormgr.h" #ifdef THIS_FILE #undef THIS_FILE #endif static char __szTraceSourceFile[] = __FILE__; #define THIS_FILE __szTraceSourceFile #define TRACE_FILEID 0 #define FILEID 0 #define SAFEDELETE(p) if (p) { HeapFree( m_hHeapToUse, 0, p); p = NULL;} else ; // // redefine a new max buf // #ifdef MAX_BUFFER #undef MAX_BUFFER #define MAX_BUFFER 1024 #endif // // Some Registry keys used to merge registry info into the blob. // static TCHAR s_cszUserHivePrefix[] = TEXT("\\REGISTRY\\USER\\"); static TCHAR s_cszUserHiveClassesSuffix[] = TEXT("_CLASSES"); static TCHAR s_cszTempUserProfileKey[] = TEXT("FILELIST0102"); static TCHAR s_cszProfileImagePath[] = TEXT("ProfileImagePath"); static TCHAR s_cszUserHiveDefault[] = TEXT(".DEFAULT"); static TCHAR s_cszUserProfileEnv [] = TEXT("USERPROFILE"); static TCHAR s_cszFilesNotToBackup[] = TEXT("SYSTEM\\CurrentControlSet\\Control\\BackupRestore\\FilesNotToBackup"); static TCHAR s_cszProfileList[] = TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList"); static TCHAR s_cszUserShellFolderKey[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders"); static TCHAR s_cszWinLogonKey[] = TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\WinLogon"); static TCHAR s_cszSnapshotKey[] = TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\SystemRestore\\FilesToSnapshot"); static INT s_nSnapShotEntries = 0; static BOOL s_bSnapShotInit = FALSE; // // Some invalid patterns found in FilesNotToBackup Key. // TCHAR ArrInvalidPatterns[][64] = { TEXT("*."), TEXT("%USERPROFILE%"), TEXT("%TEMP%") }; #define INVALID_PATTERNS 3 // // CFLDatBuilder Implementation // CFLDatBuilder::CFLDatBuilder() { m_lNodeCount = m_lFileListCount = m_lNumFiles = m_lNumChars = 0; m_pRoot = NULL; m_chDefaultType = _TEXT('i'); if( ( m_hHeapToUse = HeapCreate( 0, 1048576 /* 1 meg */, 0 ) ) == NULL ) { m_hHeapToUse = GetProcessHeap(); } } CFLDatBuilder::~CFLDatBuilder() { if( m_hHeapToUse != GetProcessHeap() ) { HeapDestroy( m_hHeapToUse ); } } // // CFLDatBuilder::DeleteList - free'd up a a linked list of // FL_FILELIST structures and the attached strings. // BOOL CFLDatBuilder::DeleteList( LPFL_FILELIST pList ) { LPFL_FILELIST pListNext; TraceFunctEnter("CFLDatBuilder::DeleteList"); while( pList ) { if( pList->szFileName ) { HeapFree( m_hHeapToUse, 0, pList->szFileName ); } pListNext = pList->pNext; HeapFree( m_hHeapToUse, 0, pList ); pList = pListNext; } TraceFunctLeave(); return TRUE; } // // CFLDatBuilder::DeleteTree - Recurses through a FLTREE_NODE, deletes // all the nods, allocated strings for path and file lists attached // to the nodes. // BOOL CFLDatBuilder::DeleteTree( LPFLTREE_NODE pTree ) { TraceFunctEnter("CFLDatBuilder::DeleteTree"); if( pTree ) { if( pTree->szPath ) { HeapFree( m_hHeapToUse, 0, pTree->szPath ); } if( pTree->pFileList ) { DeleteList( pTree->pFileList ); } // // go depth first // if( pTree->pChild ) { DeleteTree( pTree->pChild ); } if( pTree->pSibling ) { DeleteTree( pTree->pSibling ); } HeapFree( m_hHeapToUse, 0, pTree ); } TraceFunctLeave( ); return TRUE; } // // CFLDatBuilder::CreateNode - Allocates space for a tree node and path // string and copies szPath into the newly allocated path. It also // sets the internal node parent pointer. // ->Increments the global ( m_lNodeCount ) node count. // ->Increments the global characters allocated ( m_lNumChars ) count // (These counts are used to reserve space in the FLDAT file) // LPFLTREE_NODE CFLDatBuilder::CreateNode( LPTSTR szPath, TCHAR chType, LPFLTREE_NODE pParent, BOOL fDisable) { LPFLTREE_NODE pNode=NULL; LONG lPathLen; TraceFunctEnter("CFLDatBuilder::CreateNode"); pNode = (LPFLTREE_NODE) HeapAlloc( m_hHeapToUse, 0, sizeof(FLTREE_NODE) ); if (pNode == NULL) { goto End; } memset( pNode, 0, sizeof( FLTREE_NODE ) ); lPathLen = _tcslen( szPath ); if ( (pNode->szPath = _MyStrDup( szPath ) ) == NULL) { HeapFree( m_hHeapToUse, 0, pNode); pNode = NULL; goto End; } pNode->chType = chType; // // give me a node number, used for indexing later. // pNode->lNodeNumber = m_lNodeCount++; m_lNumChars += lPathLen; // // set the parent // if( pParent ) { pNode->pParent = pParent; } // // is this a protected directory // pNode->fDisableDirectory = fDisable; End: TraceFunctLeave(); return( pNode ); } // // CFLDatBuilder::CreateList - Allocates a file list entry. // LPFL_FILELIST CFLDatBuilder::CreateList() { LPFL_FILELIST pList=NULL; TraceFunctEnter("CFLDatBuilder::CreateList"); pList = (LPFL_FILELIST) HeapAlloc( m_hHeapToUse, 0, sizeof( FL_FILELIST) ); if ( pList ) { memset( pList, 0, sizeof(LPFL_FILELIST) ); } TraceFunctLeave(); return( pList ); } // // CFLDatBuidler::AddfileToList // This method calls CreateList() and allocates a filelist node. // It then allocates memoery for the file name and copies it over. // It then links it into the pList file list. // // -> If *pList is null, it increments the number of file lists in system. // This is important as most nodes don't have file lists and we shouldn't // reserve space for them. // -> Like CreateNode(), this functions also adds to the number of // global allocated characters ( m_lNumChars ) // -> Increments the total number of files ( m_lFiles ), this number // is used by the HASHLIST in order to see how m any physical entries // to allocate. // -> This functions also nodes to the nods own NumofCharacere and NumFiles // counters. This is used to create it's own individual hash list. // BOOL CFLDatBuilder::AddFileToList( LPFLTREE_NODE pNode, LPFL_FILELIST *pList, LPTSTR szFile, TCHAR chType) { LPFL_FILELIST pNewList=NULL; LPTSTR pNewString=NULL; LONG lFileNameLength; TraceFunctEnter("CFLDatBuilder::AddFileToList"); _ASSERT(pList); _ASSERT(szFile); if( (pNewList = CreateList() ) == NULL) { ErrorTrace(FILEID, "Error allocating memory", 0); goto cleanup; } lFileNameLength = _tcslen( szFile ); if( (pNewString = _MyStrDup( szFile ) ) == NULL ) { ErrorTrace(FILEID,"Error allocating memory",0); goto cleanup; } pNewList->szFileName = pNewString; pNewList->chType = chType; // // this is a whole new list // if( *pList == NULL ) { m_lFileListCount++; } m_lNumFiles++; m_lNumChars += lFileNameLength; pNode->lNumFilesHashed++; pNode->lFileDataSize += lFileNameLength; pNewList->pNext = *pList; *pList = pNewList; TraceFunctLeave(); return TRUE; cleanup: SAFEDELETE( pNewString ); SAFEDELETE( pNewList ); TraceFunctLeave(); return FALSE; } // // CFLDatBuilder::AddTreeNode // This method is the core of the FL tree building process. // It takes a full path of a filename (or directory) and recurses down // the tree. If one of the intermediary nodes required by end node // (i.e a directory on the way to our final directory), it adds // it to the tree with the default type. if another directory is added // which explicitly references that directory, its type is changed to // the explicit type. // // Files are a special case since they are linked lists off direcory nodes. // BOOL CFLDatBuilder::AddTreeNode( LPFLTREE_NODE *pParent, LPTSTR szFullPath, TCHAR chType, LONG lNumElements, LONG lLevel, BOOL fFile, BOOL fDisable) { TCHAR szBuf[MAX_PATH]; LPFLTREE_NODE pNodePointer, pTempNode, pNewNode; BOOL fResult=FALSE; TraceFunctEnter("CFLDatBuilder::AddTreeNode"); // // we've hit the end of the recursion. // if( lLevel == lNumElements ) { return(TRUE); } // // make sure everything is null // pNodePointer = pTempNode = pNewNode = NULL; // // Get this element of the path structure // if( GetField( szFullPath, szBuf, lLevel, _TEXT('\\') ) == 0) { ErrorTrace(FILEID, "Error extracting path element.", 0 ); goto cleanup; } // // We are adding a file! // if( (lLevel == (lNumElements - 1) ) && fFile ) { if( AddFileToList( *pParent, &(*pParent)->pFileList, szBuf, chType ) == FALSE ) { ErrorTrace(FILEID, "Error adding a file to the filelist.", 0 ); goto cleanup; } TraceFunctLeave(); return(TRUE); } if( *pParent ) { // // lets see if i exist as sibling any where along the line. // if( lLevel == 0 ) { // // at level 0, we don't really have a parent->child relationship // manually set the pointer // pNodePointer = *pParent; } else { // // start searching for siblings // pNodePointer = (*pParent)->pChild; } for( ; pNodePointer != NULL; pNodePointer = pNodePointer->pSibling) { // // okay, we've already hashed this entry ! // if( _tcsicmp( pNodePointer->szPath, szBuf ) == 0 ) { if( lLevel == (lNumElements-1) ) { // // In this case, we at the leaf node on this addition // but it has been addded before implicitly // as a default node. we need to change this type to // our explicity type; // pNodePointer->chType = chType; // // brijeshk: we would have already created this // node ONLY if this node is a DIRECTORY // need to change the default protected attribute // to specified value as well // pNodePointer->fDisableDirectory = fDisable; fResult = TRUE; } else { fResult = AddTreeNode( &pNodePointer, szFullPath, chType, lNumElements, lLevel + 1, fFile, fDisable ); } TraceFunctLeave(); return( fResult ); } pTempNode = pNodePointer; } } if( (pNewNode = CreateNode(szBuf, chType, *pParent, fDisable) ) == NULL) { ErrorTrace(FILEID, "Error allocating memory", 0); goto cleanup; } // // We are a node implicitly created on the chain, set it to // the unknown type instead of the end node type. // if( lLevel != (lNumElements-1) ) { pNewNode->chType = NODE_TYPE_UNKNOWN; // // brijeshk: if we are an implicitly created node, then we need // to set the disable attribute to default (FALSE) // otherwise, protecting the directory c:\A\B would also // protect c:\ and A. // pNewNode->fDisableDirectory = FALSE; } // // Are we the first root // if( *pParent == NULL ) { *pParent = pNewNode; } else if( (*pParent)->pChild == NULL ) { // // We are the child off the root // (*pParent)->pChild = pNewNode; } else if( pTempNode ) { // // We are a sibling at this level, pTempNode is the last sibling // in the list // just tack pNewNode onto the end/ // pTempNode->pSibling = pNewNode; pNewNode->pSibling = NULL; } else { ErrorTrace( FILEID, "Uxpected error condition in AddTreeNode: no link determined",0); goto cleanup; } // // Parse the new level. // fResult = AddTreeNode( &(pNewNode), szFullPath, chType, lNumElements, lLevel + 1, fFile, fDisable ); cleanup: TraceFunctLeave(); return( fResult ); } BOOL CFLDatBuilder::AddRegistrySnapshotEntry( LPTSTR pszPath) { HKEY hKey; BOOL fRet = FALSE; if ( s_bSnapShotInit == FALSE ) { // // Delete the snapshot key // RegDeleteKey( HKEY_LOCAL_MACHINE, s_cszSnapshotKey ); s_nSnapShotEntries = 0; // // Add the snapshot key // if (RegCreateKeyEx( HKEY_LOCAL_MACHINE, s_cszSnapshotKey, 0, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL) == ERROR_SUCCESS) { s_bSnapShotInit = TRUE; RegCloseKey( hKey ); } } // // Set the value in the key // if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, s_cszSnapshotKey, 0, KEY_READ|KEY_WRITE, &hKey ) == ERROR_SUCCESS ) { TCHAR szSnapshotName[ MAX_PATH ]; s_nSnapShotEntries++; _stprintf(szSnapshotName, TEXT("snap#%d"), s_nSnapShotEntries); RegSetValueEx( hKey, szSnapshotName, 0, REG_SZ, (const BYTE * )pszPath, (_tcslen(pszPath) + 1)*sizeof(TCHAR) ); RegCloseKey( hKey ); fRet = TRUE; } return fRet; } // // CFLDatBuilder::AddMetaDriveFileDir - // BOOL CFLDatBuilder::AddMetaDriveFileDir( LPTSTR szInPath, TCHAR chType, BOOL fFile, BOOL fDisable ) { BOOL fRet = FALSE; TCHAR szFile[MAX_BUFFER]; TCHAR szOutFile[MAX_BUFFER]; LONG lNumTokens=0; TraceFunctEnter("AddMetaDriveFileDir"); if (szInPath && szInPath[0]==TEXT('*')) { // // if type is 's' make it exclude and add to the registry // setting fro snapshotted files // if ( chType == TEXT('s') ) { AddRegistrySnapshotEntry( szInPath ); chType = TEXT('e'); } _tcscpy( szFile, szInPath ); #ifdef USE_NTDEVICENAMES if(szFile[1] == TEXT(':') ) { _stprintf(szOutFile, _TEXT("NTROOT\\%s\\%s"), ALLVOLUMES_PATH_T, szFile+3); CharUpper( szOutFile ); } else #endif { _stprintf(szOutFile, _TEXT("NTROOT\\%s\\%s"), ALLVOLUMES_PATH_T, szFile ); } lNumTokens = CountTokens( szOutFile, _TEXT('\\') ); if( AddTreeNode( &m_pRoot, szOutFile, chType, lNumTokens, 0, fFile, fDisable ) == FALSE ) { ErrorTrace(FILEID, "Error adding tree node in metadrive fileadd.",0); goto cleanup; } fRet = TRUE; } cleanup: TraceFunctLeave(); return fRet; } // // CFLDatBuilder::VerifyVxdDat // BOOL CFLDatBuilder::VerifyVxdDat( LPCTSTR pszFile) { DWORD dwSize = 0; HANDLE hFile=NULL; TraceFunctEnter("VerifyVxdDat"); if( (hFile = CreateFile( pszFile, GENERIC_READ, 0, // exclusive file accces NULL, //security attributes OPEN_EXISTING, // don't make it if it don't exist FILE_FLAG_RANDOM_ACCESS, NULL ) ) == NULL ) { ErrorTrace(FILEID, "Error opening %s to verify FLDAT", pszFile ); goto cleanup; } dwSize = GetFileSize( hFile, NULL); if( (dwSize == 0xFFFFFFFF) || (dwSize == 0) ) { ErrorTrace(FILEID, "%s: 0 size file, unable to verify.", pszFile ); goto cleanup; } CloseHandle( hFile ); TraceFunctLeave(); return TRUE; cleanup: if( hFile ) { CloseHandle( hFile ); } TraceFunctLeave(); return FALSE; } // // Merge FileNotToBackup information into the Dat File // BOOL CFLDatBuilder::MergeSfcDllCacheInfo( ) { BOOL fRet; // // Try to get the value from the key first // fRet = AddNodeForKeyValue( HKEY_LOCAL_MACHINE, s_cszWinLogonKey, TEXT("SfcDllCache") ); if ( fRet == FALSE ) { TCHAR SfcPath[MAX_PATH + 1]; TCHAR SfcFullPath[MAX_PATH + 1]; LONG lNumTokens = 0; _stprintf( SfcPath, TEXT("%%WINDIR%%\\system32\\dllcache")); ExpandEnvironmentStrings( SfcPath, SfcFullPath, MAX_PATH ); SfcFullPath[MAX_PATH] = 0; ConvertToInternalFormat( SfcFullPath, SfcPath ); SfcPath[MAX_PATH] = 0; lNumTokens = CountTokens( SfcPath, _TEXT('\\') ); fRet = AddTreeNode(&m_pRoot, SfcPath, TEXT('e'), lNumTokens, 0, FALSE, FALSE ); } return fRet; } // // Merge FileNotToBackup information into the Dat File // BOOL CFLDatBuilder::MergeFilesNotToBackupInfo( ) { TCHAR ValueName[ MAX_PATH+1 ]; TCHAR ValueData[ MAX_PATH+1 ]; DWORD ValueType = 0; DWORD cbValueName = 0; DWORD cbValueData = 0; DWORD cbValueType = 0; LONG lNumTokens = 0; BOOL bExtension = FALSE, bRecursive = FALSE, bInvalidPattern = FALSE; HKEY hKey; PTCHAR ptr = NULL; TraceFunctEnter("CFLDatBuilder::MergeFilesNotToBackupInfo"); if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, s_cszFilesNotToBackup, 0, KEY_READ, &hKey ) == ERROR_SUCCESS ) { DWORD dwIndex = 0; while ( TRUE ) { bExtension = FALSE; bRecursive = FALSE; bInvalidPattern = FALSE; *ValueName = 0; cbValueName = sizeof(ValueName)/sizeof(TCHAR); *ValueData = 0; cbValueData = sizeof(ValueData); if ( RegEnumValue( hKey, dwIndex, ValueName, &cbValueName, 0, &ValueType, (PBYTE)ValueData, &cbValueData ) != ERROR_SUCCESS ) { break; } // trace(0, "Opened Registry Key %S\n", ValueData); // // We are interested in only string types // if ( ValueType != REG_EXPAND_SZ && ValueType != REG_SZ && ValueType != REG_MULTI_SZ ) { dwIndex++; continue; } CharUpper( ValueData ); // // Look for any invalid patterns in the value data // for (int i=0; i ValueData ) { if ( *ptr == TEXT(' ') || *ptr == TEXT('\t') || *ptr == TEXT('\\') || *ptr == TEXT('*') ) { *ptr = 0; } else { break; } ptr--; } // // Check if the path has extensions also // #if 0 if ( _tcsrchr( ValueData, TEXT('.') ) != NULL ) { bExtension = TRUE; } #else ptr = ValueData + _tcslen(ValueData) - 1; while ( ptr > ValueData ) { if ( *ptr == TEXT('\\') ) { break; } else if ( *ptr == TEXT('.') ) { bExtension = TRUE; break; } ptr--; } #endif if ( ( bExtension && bRecursive ) || ( !bExtension && !bRecursive) ) { dwIndex++; continue; } // // Check if the path starts with a "\\" // if ( ValueData[0] == TEXT('\\') ) { _stprintf( ValueName, TEXT("*:%s"), ValueData ); ExpandEnvironmentStrings( ValueName, ValueData, MAX_PATH ); if (_tcsstr( ValueData, TEXT("~")) != NULL ) { LPTSTR pFilePart = NULL; // // Convert into full path // if (ExpandShortNames(ValueData, sizeof(ValueData), ValueName, sizeof(ValueName))) { _tcscpy( ValueData, ValueName ); } } // trace(0, "Adding - %S\n\n", ValueData ); AddMetaDriveFileDir( ValueData, TEXT('e'), bExtension, FALSE); } else { TCHAR szDeviceName[ MAX_PATH ]; *szDeviceName=0; _tcscpy( ValueName, ValueData ); ExpandEnvironmentStrings( ValueName, ValueData, MAX_PATH ); if (_tcsstr( ValueData, TEXT("~")) != NULL ) { LPTSTR pFilePart = NULL; // // Convert into full path // if (ExpandShortNames(ValueData, sizeof(ValueData), ValueName, sizeof(ValueName))) { _tcscpy( ValueData, ValueName ); } } ConvertToInternalFormat( ValueData, ValueName ); lNumTokens = CountTokens( ValueName, _TEXT('\\') ); // trace(0, "Adding - %S\n\n", ValueName ); AddTreeNode( &m_pRoot, ValueName, TEXT('e'), lNumTokens, 0, bExtension, FALSE ); } dwIndex++; } RegCloseKey( hKey ); } TraceFunctLeave(); return TRUE; } BOOL CFLDatBuilder::AddNodeForKeyValue( HKEY hKeyUser, LPCTSTR pszSubKey, LPCTSTR pszValue ) { BOOL fRet = FALSE; HKEY hKeyEnv; TCHAR szDeviceName[ MAX_PATH ]; TCHAR szBuf [ MAX_PATH ]; TCHAR szBuf2 [ MAX_PATH ]; DWORD cbBuf; DWORD cbBuf2; LONG lNumTokens=0; DWORD Type, dwErr; TraceFunctEnter("CFLDatBuilder::AddNodeForKeyValue"); dwErr = RegOpenKeyEx( hKeyUser, pszSubKey, 0, KEY_READ, &hKeyEnv ); if ( dwErr == ERROR_SUCCESS ) { // // Read and add the value for TEMP from the user profile // cbBuf = sizeof( szBuf ); dwErr = RegQueryValueEx( hKeyEnv, pszValue, NULL, &Type, (PBYTE)szBuf, &cbBuf ); RegCloseKey( hKeyEnv ); if ( dwErr != ERROR_SUCCESS ) { trace( 0, "Cannot open :%S", pszValue ); goto Exit; } ExpandEnvironmentStrings ( szBuf, szBuf2, sizeof( szBuf2 ) / sizeof( TCHAR ) ); ConvertToInternalFormat ( szBuf2, szBuf ); lNumTokens = CountTokens( szBuf, _TEXT('\\') ); // trace(0, "Adding - %S\n\n", szBuf ); fRet = AddTreeNode( &m_pRoot, szBuf, TEXT('e'), lNumTokens, 0, FALSE, FALSE ); } Exit: TraceFunctLeave(); return fRet; } BOOL CFLDatBuilder::AddUserProfileInfo( HKEY hKeyUser, LPCTSTR pszUserProfile ) { HKEY hKeyEnv; DWORD dwErr; TCHAR OldUserProfileEnv[ MAX_PATH ]; LPTSTR pszOldUserProfileEnv = NULL; TraceFunctEnter("CFLDatBuilder::AddUserProfileInfo"); // // Save the current value of %UserProfile% in the env // *OldUserProfileEnv = 0; if ( GetEnvironmentVariable( s_cszUserProfileEnv, OldUserProfileEnv, sizeof( OldUserProfileEnv )/sizeof(TCHAR))>0 ) { pszOldUserProfileEnv = OldUserProfileEnv; } SetEnvironmentVariable( s_cszUserProfileEnv, pszUserProfile ); AddNodeForKeyValue( hKeyUser, TEXT("Environment"), TEXT("TEMP") ); AddNodeForKeyValue( hKeyUser, TEXT("Environment"), TEXT("TMP") ); AddNodeForKeyValue( hKeyUser, s_cszUserShellFolderKey, TEXT("Favorites") ); AddNodeForKeyValue( hKeyUser, s_cszUserShellFolderKey, TEXT("Cache") ); AddNodeForKeyValue( hKeyUser, s_cszUserShellFolderKey, TEXT("Cookies") ); AddNodeForKeyValue( hKeyUser, s_cszUserShellFolderKey, TEXT("Personal") ); AddNodeForKeyValue( hKeyUser, s_cszUserShellFolderKey, TEXT("nethood") ); AddNodeForKeyValue( hKeyUser, s_cszUserShellFolderKey, TEXT("history") ); // // Put back the user Profile Env variable // SetEnvironmentVariable ( s_cszUserProfileEnv, pszOldUserProfileEnv ); TraceFunctLeave(); return TRUE; } // // This funtion merges the drive table info into the Xml Blob // BOOL CFLDatBuilder::MergeDriveTableInfo( ) { BOOL fRet = FALSE; TCHAR szSystemDrive[MAX_PATH]; TCHAR *szBuf2 = NULL; LONG lNumTokens = 0; TraceFunctEnter("CFLDatBuilder::MergeDriveTableInfo"); szBuf2 = new TCHAR[MAX_BUFFER+7]; if (! szBuf2) { ErrorTrace(0, "Cannot allocate memory for szBuf2"); goto cleanup; } // // Enumerate the drive table information and merge it into // the filelist // if (GetSystemDrive(szSystemDrive)) { TCHAR szPath[MAX_PATH]; CDriveTable dt; SDriveTableEnumContext dtec = {NULL, 0}; MakeRestorePath(szPath, szSystemDrive, s_cszDriveTable); // // remove terminating slash // if (szPath[_tcslen( szPath ) - 1] == _TEXT('\\')) szPath[_tcslen( szPath ) - 1] = 0; if (dt.LoadDriveTable(szPath) == ERROR_SUCCESS) { CDataStore *pds; pds = dt.FindFirstDrive (dtec); while (pds) { BOOLEAN bDisable = FALSE; DWORD dwFlags = pds->GetFlags(); if ( !(dwFlags & SR_DRIVE_MONITORED) ) { bDisable = TRUE; } if (dwFlags & SR_DRIVE_FROZEN) { bDisable = TRUE; } if ( bDisable ) { // // Enter this information into the tree // swprintf(szBuf2,_TEXT("NTROOT%s"), pds->GetNTName()); // // remove terminating slash // if (szBuf2[_tcslen( szBuf2 ) - 1] == _TEXT('\\')) szBuf2[_tcslen( szBuf2 ) - 1] = 0; CharUpper (szBuf2); lNumTokens = CountTokens( szBuf2, _TEXT('\\') ); if( AddTreeNode( &m_pRoot, szBuf2, NODE_TYPE_UNKNOWN, lNumTokens, 0, FALSE, bDisable ) == FALSE ) { ErrorTrace(FILEID, "Error adding node.",0); goto cleanup; } } pds = dt.FindNextDrive (dtec); } } fRet = TRUE; } cleanup: if (szBuf2) delete [] szBuf2; TraceFunctLeave(); return fRet; } // // This function merges per user information either from HKEY_USER or from // the user hive on the disk // BOOL CFLDatBuilder::MergeUserRegistryInfo( LPCTSTR pszUserProfilePath, LPCTSTR pszUserProfileHive, LPCTSTR pszUserSid ) { BOOL fRet = TRUE; HKEY hKeyUser; DWORD dwErr; TraceFunctEnter("CFLDatBuilder::MergeUserRegistryInfo"); // trace(0, "UserProfilePath: %S", pszUserProfilePath ); // trace(0, "UserProfileHive: %S", pszUserProfileHive ); // // Try to open the user specific key from HKEY_USER // dwErr = RegOpenKeyEx( HKEY_USERS, pszUserSid, 0, KEY_READ, &hKeyUser); if ( dwErr == ERROR_SUCCESS ) { // // Succeeded : copy the setting from this key // AddUserProfileInfo( hKeyUser, pszUserProfilePath ); RegCloseKey( hKeyUser ); } else { // // Failed : Now load the hive for this user // dwErr = RegLoadKey( HKEY_LOCAL_MACHINE, s_cszTempUserProfileKey, pszUserProfileHive ); if ( dwErr == ERROR_SUCCESS ) { // trace(0, "Loaded Hive : %S", pszUserProfileHive ); // // Open temporary key where the hive was loaded // dwErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, s_cszTempUserProfileKey, 0, KEY_READ, &hKeyUser); if ( dwErr == ERROR_SUCCESS ) { AddUserProfileInfo( hKeyUser, pszUserProfilePath ); RegCloseKey( hKeyUser ); } // // Unload the hive from the temp key // RegUnLoadKey( HKEY_LOCAL_MACHINE, s_cszTempUserProfileKey ); } } fRet = TRUE; TraceFunctLeave(); return fRet; } // // This function enumerats all the available user profiles and calls // MergeUserRegistryInfo for each user. // BOOL CFLDatBuilder::MergeAllUserRegistryInfo( ) { BOOL fRet = FALSE; TCHAR UserSid[ MAX_PATH ]; DWORD ValueType = 0; DWORD cbUserSid = 0; DWORD cbValueType = 0; HKEY hKey; PTCHAR ptr = NULL; FILETIME ft; DWORD dwErr; TraceFunctEnter("CFLDatBuilder::MergeAllUserRegistryInfo"); dwErr = SetPrivilegeInAccessToken(SE_RESTORE_NAME); if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, s_cszProfileList, 0, KEY_READ, &hKey ) == ERROR_SUCCESS ) { DWORD dwIndex = 0; // // Enumerate and get the Sids for each user. // while ( TRUE ) { *UserSid = 0; cbUserSid = sizeof(UserSid)/sizeof(TCHAR); if ( RegEnumKeyEx( hKey, dwIndex, UserSid, &cbUserSid, 0, NULL, 0, &ft ) != ERROR_SUCCESS ) { break; } CharUpper( UserSid ); // // Look for intersting values // if (cbUserSid > 0) { DWORD dwErr; HKEY hKeyUser, hKeyEnv, hKeyProfileList; TCHAR UserProfilePath[MAX_PATH]; TCHAR UserProfileHive[MAX_PATH]; DWORD cbUserProfilePath = 0; // trace(0,"UserSid = %S", UserSid); dwErr = RegOpenKeyEx( hKey, UserSid, 0, KEY_READ, &hKeyProfileList ); if ( dwErr == ERROR_SUCCESS ) { DWORD Type; cbUserProfilePath = sizeof( UserProfilePath ); dwErr = RegQueryValueEx( hKeyProfileList, s_cszProfileImagePath, NULL, &Type, (PBYTE)UserProfilePath, &cbUserProfilePath ); RegCloseKey( hKeyProfileList ); if ( dwErr != ERROR_SUCCESS ) { trace(0, "Query ProfileImagePath failed: %d", dwErr ); dwIndex++; continue; } } else { trace(0, "Opening UserSid failed: %d", dwErr ); dwIndex++; continue; } // // Create NTUSER.Dat path from the user profile path // ExpandEnvironmentStrings( UserProfilePath, UserProfileHive, sizeof(UserProfileHive) / sizeof(TCHAR) ); _tcscpy( UserProfilePath, UserProfileHive ); _tcscat( UserProfileHive, TEXT("\\NTUSER.DAT") ); MergeUserRegistryInfo( UserProfilePath, UserProfileHive, UserSid ); } dwIndex++; } fRet = TRUE; RegCloseKey( hKey ); } else { trace( 0, "Failed to open %S", s_cszProfileList ); } TraceFunctLeave(); return fRet; } // // CFLDatBuilder::BuildTree // This methods takes an XML file (the PCHealth Protected file) // and outsputs a FLDAT file ( pszOutFile ). // It basically just opens up the xml, iterates through // all the files and then adds them to the tree. It then // creates blobs based on the data gathered and then sends the // tree to the CFLPathTree blob class which transforms the tree // into the contigious blob format. It then writes it out. // // -> The method of actually passing the FLDAT file has not be defined, // this function just demonstrates the process. // // BOOL CFLDatBuilder::BuildTree( LPCTSTR pszFile, LPCTSTR pszOutFile) { TCHAR *szBuf = NULL; TCHAR *szBuf2 = NULL; TCHAR chType; LONG lLoop,lMax,lNumTokens; BOOL fRet = FALSE; s_bSnapShotInit = FALSE; // // ext list blob // CFLHashList ExtListBlob( m_hHeapToUse ); LONG lNumChars, lNumExt, lNumExtTotal; // // config blob // BlobHeader ConfigBlob; // // CFLPathTree blob // CFLPathTree PathTreeBlob( m_hHeapToUse ); // // outfile // HANDLE hOutFile=NULL; DWORD dwWritten; // // array opf all the file types, Include, Exclude, SNAPSHOT // TCHAR achType[3] = { _TEXT('i'), _TEXT('e'), _TEXT('s') }; LONG lTypeLoop; // // numeric counterpart of m_chDefaultType; // DWORD dwDefaultType; // // should we protect this directory // BOOL fDisable = FALSE; TraceFunctEnter("CFLDatBuilder::BuildTree"); if( m_pRoot ) { DeleteTree( m_pRoot ); m_pRoot = NULL; } if(m_XMLParser.Init(pszFile) == FALSE) { ErrorTrace(FILEID, "There was an error parsing the protected XML file.",0); goto cleanup; } szBuf = new TCHAR[MAX_BUFFER]; szBuf2 = new TCHAR[MAX_BUFFER+7]; if (! szBuf || ! szBuf2) { ErrorTrace(0, "Cannot allocate memory"); goto cleanup; } // // Calculate the tree default type info // m_chDefaultType = m_XMLParser.GetDefaultType(); if( m_chDefaultType == _TEXT('I') ) dwDefaultType = NODE_TYPE_INCLUDE; else if( m_chDefaultType == _TEXT('E') ) dwDefaultType = NODE_TYPE_EXCLUDE; else dwDefaultType = NODE_TYPE_UNKNOWN; // // Loop through the directory/files for each file type (include, exclude ) // for(lTypeLoop = 0; lTypeLoop < 3;lTypeLoop++) { // // Find directories for the type // lMax = m_XMLParser.GetDirectoryCount( achType[lTypeLoop] ); for(lLoop = 0;lLoop < lMax;lLoop++) { fDisable = FALSE; if( m_XMLParser.GetDirectory( lLoop, szBuf, MAX_BUFFER, achType[lTypeLoop], &fDisable) != MAX_BUFFER ) { ErrorTrace(FILEID, "Not enough buffer space.",0); goto cleanup; } if( szBuf[0] == _TEXT('*') ) { if( AddMetaDriveFileDir( szBuf, achType[lTypeLoop], FALSE, fDisable) == FALSE ) { ErrorTrace(FILEID, "error adding meta drive directory.",0); goto cleanup; } } else { TCHAR szDeviceName[ MAX_PATH ]; *szDeviceName=0; // ankor all nods at Root.. so tree actually looks // like Root\C:\Windows etc ConvertToInternalFormat( szBuf, szBuf2 ); lNumTokens = CountTokens( szBuf2, _TEXT('\\') ); if( AddTreeNode( &m_pRoot, szBuf2, achType[lTypeLoop], lNumTokens, 0, FALSE, fDisable ) == FALSE ) { ErrorTrace(FILEID, "Error adding node.",0); goto cleanup; } } } // // Find files for the type // lMax = m_XMLParser.GetFileCount( achType[lTypeLoop] ); for(lLoop = 0;lLoop < lMax;lLoop++) { if( m_XMLParser.GetFile(lLoop, szBuf, MAX_BUFFER, achType[lTypeLoop] ) != MAX_BUFFER ) { ErrorTrace(FILEID, "Not enough buffer space.",0); goto cleanup; } if( szBuf[0] == _TEXT('*') ) { if( AddMetaDriveFileDir( szBuf, achType[lTypeLoop], TRUE, FALSE ) == FALSE ) { ErrorTrace(FILEID, "error adding meta drive file.",0); goto cleanup; } } else { int iType = lTypeLoop; // // if type is 's' make it exclude and add to the registry // setting fro snapshotted files // if ( achType[lTypeLoop] == TEXT('s') ) { AddRegistrySnapshotEntry( szBuf ); iType = 1; // exclude } // // Ankor all nods at Root.. so tree actually looks like // Root\C:\Windows etc // ConvertToInternalFormat( szBuf, szBuf2 ); lNumTokens = CountTokens( szBuf2, _TEXT('\\') ); if( AddTreeNode( &m_pRoot, szBuf2, achType[iType], lNumTokens, 0, TRUE, FALSE ) == FALSE ) { ErrorTrace(FILEID, "Error adding node.",0); goto cleanup; } } } } // // Merge information from the drivetable in to the blob // if ( MergeDriveTableInfo() == FALSE ) { ErrorTrace(FILEID, "Error merging drive table info.",0); goto cleanup; } // // Merge Information under FilesNotToBackup key in to the blob ... // if ( MergeFilesNotToBackupInfo() == FALSE ) { ErrorTrace(FILEID, "Error merging FilesNotToBackup Info.",0); goto cleanup; } // // Merge Per user information from the registry / user hives // if ( MergeAllUserRegistryInfo() == FALSE ) { ErrorTrace(FILEID, "Error merging user registry info.",0); goto cleanup; } #if 0 // // Commented out: We monitor sfc cache ... // Merge information for sfcdllcache // if ( MergeSfcDllCacheInfo() == FALSE ) { ErrorTrace(FILEID, "Error merging SfcDllCache info.",0); goto cleanup; } #endif // // Build the path tree based on our tree and the data we collected // about it ( filecounts, nodecounts, # chars, etc) // if( PathTreeBlob.BuildTree( m_pRoot, m_lNodeCount, dwDefaultType, m_lFileListCount, m_lNumFiles, CalculateNumberOfHashBuckets( m_pRoot ), m_lNumChars) == FALSE ) { ErrorTrace(FILEID, "Error buildign pathtree blob.",0); goto cleanup; } // // Okay, now build a ext list hash blob // lNumChars = 0; lNumExtTotal = 0; for(lTypeLoop = 0; lTypeLoop < 3;lTypeLoop++) { lNumExt = m_XMLParser.GetExtCount( achType[ lTypeLoop ] ); lNumExtTotal += lNumExt; for(lLoop = 0;lLoop < lNumExt ;lLoop++) { if( m_XMLParser.GetExt( lLoop, szBuf, MAX_BUFFER, achType[ lTypeLoop ] ) != MAX_BUFFER ) { ErrorTrace(FILEID, "Not enough buffer space.",0); goto cleanup; } lNumChars += _tcslen( szBuf ); } } ExtListBlob.Init( lNumExtTotal, lNumChars ); for(lTypeLoop = 0; lTypeLoop < 3;lTypeLoop++) { lNumExt = m_XMLParser.GetExtCount( achType[ lTypeLoop ] ); for(lLoop = 0;lLoop < lNumExt; lLoop++) { m_XMLParser.GetExt(lLoop, szBuf, MAX_BUFFER, achType[ lTypeLoop ] ); ExtListBlob.AddFile( szBuf, achType[lTypeLoop] ); } } // // now we have both blobs, lets write to disk // if( (hOutFile = CreateFile( pszOutFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, // security attributes OPEN_ALWAYS, FILE_FLAG_RANDOM_ACCESS, NULL) // template file ) == INVALID_HANDLE_VALUE) { ErrorTrace( FILEID, "CreateFile Failed 0x%x", GetLastError()); goto cleanup; } // // Prepare the header blob // ConfigBlob.m_dwMaxSize = sizeof(BlobHeader) + PathTreeBlob.GetSize() + ExtListBlob.GetSize(); ConfigBlob.m_dwVersion = BLOB_VERSION_NUM; ConfigBlob.m_dwMagicNum = BLOB_MAGIC_NUM ; ConfigBlob.m_dwBlbType = BLOB_TYPE_CONTAINER; ConfigBlob.m_dwEntries = 2; if ( WriteFile(hOutFile, &ConfigBlob, sizeof(BlobHeader), &dwWritten, NULL) == 0) { ErrorTrace( FILEID, "WriteFile Failed 0x%x", GetLastError()); goto cleanup; } if ( WriteFile(hOutFile, PathTreeBlob.GetBasePointer(), PathTreeBlob.GetSize(), &dwWritten, NULL) == 0) { ErrorTrace( FILEID, "WriteFile Failed 0x%x", GetLastError()); goto cleanup; } if ( WriteFile(hOutFile, ExtListBlob.GetBasePointer(), ExtListBlob.GetSize(), &dwWritten, NULL) == 0) { ErrorTrace( FILEID, "WriteFile Failed 0x%x", GetLastError()); goto cleanup; } fRet = TRUE; cleanup: if (szBuf) delete [] szBuf; if (szBuf2) delete [] szBuf2; if( hOutFile ) { CloseHandle( hOutFile ); } ExtListBlob.CleanUpMemory(); PathTreeBlob.CleanUpMemory(); if( m_pRoot ) { DeleteTree(m_pRoot); m_pRoot = NULL; } TraceFunctLeave(); return(fRet); } // // CFLDatBuilder::CountTokens // CountTokens(LPTSTR szStr, TCHAR chDelim) // Counts the number of tokens seperated by (chDelim) in a string. // LONG CFLDatBuilder::CountTokens( LPTSTR szStr, TCHAR chDelim) { LONG lNumTokens=1; TraceFunctEnter("CFLDatBuilder::CountTokens"); _ASSERT( szStr ); if( *szStr == 0 ) { TraceFunctLeave(); return(0); } while( *szStr != 0 ) { if( *szStr == chDelim ) { lNumTokens++; } szStr = _tcsinc( szStr ); } TraceFunctLeave(); return(lNumTokens); } // // CFLDatBuilder::_MyStrDup( LPTSTR szIn ) // Same as _tcsdup or strdup but it does it our own local // heap space. // LPTSTR CFLDatBuilder::_MyStrDup( LPTSTR szIn ) { LONG lLen; LPTSTR pszOut=NULL; if( szIn ) { lLen = _tcslen( szIn ); pszOut = (LPTSTR) HeapAlloc( m_hHeapToUse, 0, (sizeof(TCHAR) * (lLen+1)) ); if( pszOut ) { _tcscpy( pszOut, szIn ); } } return( pszOut ); } // // CFLDatBuilder::CalculateNumberOfHashBuckets // Calculates the number of hash buckets needed by the dynamic hashes // in the hashlist. // LONG CFLDatBuilder::CalculateNumberOfHashBuckets( LPFLTREE_NODE pRoot ) { LONG lNumNeeded=0; if( pRoot ) { if( pRoot->pChild ) { lNumNeeded += CalculateNumberOfHashBuckets( pRoot->pChild ); } if( pRoot->pSibling ) { lNumNeeded += CalculateNumberOfHashBuckets( pRoot->pSibling ); } if( pRoot->lNumFilesHashed > 0 ) { lNumNeeded += GetNextHighestPrime( pRoot->lNumFilesHashed ); } } return( lNumNeeded ); } // // Debugging Methods // // // CFLDatBuilder::PrintList // void CFLDatBuilder::PrintList( LPFL_FILELIST pList, LONG lLevel) { LONG lCount; if( !pList ) { return; } for(lCount = 0;lCount < lLevel;lCount++) { printf(" "); } printf(" f: %s\n", pList->szFileName ); PrintList(pList->pNext, lLevel ); } void CFLDatBuilder::PrintTree( LPFLTREE_NODE pTree, LONG lLevel) { LONG lCount; if( pTree ) { for(lCount = 0;lCount < lLevel;lCount++) { printf(" "); } printf("%s", pTree->szPath); if( pTree->pFileList ) { printf(" (%d) \n", pTree->lNumFilesHashed); } else { printf("\n"); } PrintList( pTree->pFileList, lLevel ); PrintTree( pTree->pChild, lLevel + 1 ); PrintTree( pTree->pSibling, lLevel ); } return; } // // CFLDatBuilder::IsPrime // BOOL CFLDatBuilder::IsPrime( LONG lNumber) { LONG cl; // // prevent divide by 0 problems // if( lNumber == 0 ) { return FALSE; } if( lNumber == 1 ) { return TRUE; } for(cl = 2;cl < lNumber;cl++) { if( (lNumber % cl ) == 0 ) { return FALSE; } } return TRUE; } // // CFLDatBuilder::GetNextHighestPrime // LONG CFLDatBuilder::GetNextHighestPrime( LONG lNumber ) { LONG clLoop; if( lNumber >= LARGEST_HASH_SIZE ) { return( LARGEST_HASH_SIZE ); } for( clLoop = lNumber; clLoop < LARGEST_HASH_SIZE;clLoop++) { if( IsPrime( clLoop ) ) { return( clLoop ); } } // nothing found, return large hash size. return( LARGEST_HASH_SIZE ); } // // Some C helper API ( should be removed ?? ) // DWORD HeapUsed( HANDLE hHeap ) { PROCESS_HEAP_ENTRY HeapEntry; DWORD dwAllocSize=0; HeapEntry.lpData = NULL; while( HeapWalk( hHeap, &HeapEntry) != FALSE ) { if( HeapEntry.wFlags & PROCESS_HEAP_ENTRY_BUSY ) dwAllocSize += HeapEntry.cbData; } return( dwAllocSize ); } // // Convert to internal NT namespace format + additional formatiing for // required to Add the tree node. // BOOL CFLDatBuilder::ConvertToInternalFormat( LPTSTR szFrom, LPTSTR szTo ) { BOOL fRet = FALSE; #ifdef USE_NTDEVICENAMES if(szFrom[1] == TEXT(':') ) { TCHAR szDeviceName[MAX_PATH]; szFrom[2] = 0; QueryDosDevice( szFrom, szDeviceName, sizeof(szDeviceName) ); _stprintf(szTo, _TEXT("NTROOT%s\\%s"), szDeviceName, szFrom+3 ); // // remove terminating slash // if (szTo[_tcslen( szTo ) - 1] == _TEXT('\\')) szTo[_tcslen( szTo ) - 1] = 0; CharUpper( szTo ); } else #endif { _stprintf(szTo,_TEXT("NTROOT\\%s"), szFrom); } fRet = TRUE; return fRet; } // // Adjust the process privileges so that we can load other user's hives. // DWORD CFLDatBuilder::SetPrivilegeInAccessToken( LPCTSTR pszPrivilegeName ) { TraceFunctEnter("CSnapshot::SetPrivilegeInAccessToken"); HANDLE hProcess; HANDLE hAccessToken=NULL; LUID luidPrivilegeLUID; TOKEN_PRIVILEGES tpTokenPrivilege; DWORD dwReturn = ERROR_INTERNAL_ERROR, dwErr; hProcess = GetCurrentProcess(); if (!hProcess) { dwReturn = GetLastError(); trace(0, "GetCurrentProcess failed ec=%d", dwReturn); goto done; } if (!OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hAccessToken)) { dwErr=GetLastError(); trace(0, "OpenProcessToken failed ec=%d", dwErr); if (ERROR_SUCCESS != dwErr) { dwReturn = dwErr; } goto done; } if (!LookupPrivilegeValue(NULL, pszPrivilegeName, &luidPrivilegeLUID)) { dwErr=GetLastError(); trace(0, "LookupPrivilegeValue failed ec=%d",dwErr); if (ERROR_SUCCESS != dwErr) { dwReturn = dwErr; } goto done; } tpTokenPrivilege.PrivilegeCount = 1; tpTokenPrivilege.Privileges[0].Luid = luidPrivilegeLUID; tpTokenPrivilege.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; if (!AdjustTokenPrivileges(hAccessToken, FALSE, // Do not disable all &tpTokenPrivilege, sizeof(TOKEN_PRIVILEGES), NULL, // Ignore previous info NULL)) // Ignore previous info { dwErr=GetLastError(); trace(0, "AdjustTokenPrivileges"); if (dwErr != NO_ERROR) { dwReturn = dwErr; } goto done; } dwReturn = ERROR_SUCCESS; done: if (hAccessToken != NULL) { CloseHandle(hAccessToken); } TraceFunctLeave(); return dwReturn; }