//-------------------------------------------------------------- // // File: loaduser // // Contents: Load a user hive. // //--------------------------------------------------------------- #include "loadhead.cxx" #pragma hdrstop #include #include #include #include #include #include class CRegFileList { public: inline CRegFileList(TCHAR *ptsRoot, TCHAR *ptsKey, TCHAR *ptsVal, TCHAR *ptsData, DWORD dwValueType); inline ~CRegFileList(); inline void SetNext(CRegFileList *prfl); inline CRegFileList * GetNext(void) const; inline void GetData(const TCHAR **pptsRoot, const TCHAR **pptsKey, const TCHAR **pptsVal, const TCHAR **pptsData, DWORD *pdwValType) const; private: TCHAR _tsRootName[MAX_PATH + 1]; TCHAR _tsKeyName[MAX_PATH + 1]; TCHAR _tsValueName[MAX_PATH + 1]; TCHAR _tsData[MAX_PATH + 1]; DWORD _dwValueType; CRegFileList *_prflNext; }; inline CRegFileList::CRegFileList(TCHAR *ptsRoot, TCHAR *ptsKey, TCHAR *ptsVal, TCHAR *ptsData, DWORD dwValueType) { if (ptsRoot != NULL && _tcslen(ptsRoot) <= MAX_PATH) _tcscpy(_tsRootName, ptsRoot); else _tsRootName[0] = 0; if (ptsKey != NULL && _tcslen(ptsKey) <= MAX_PATH) _tcscpy(_tsKeyName, ptsKey); else _tsKeyName[0] = 0; if (ptsVal != NULL && _tcslen(ptsVal) <= MAX_PATH) _tcscpy(_tsValueName, ptsVal); else _tsValueName[0] = 0; if (ptsData != NULL && _tcslen(ptsData) <= MAX_PATH) _tcscpy(_tsData, ptsData); else _tsData[0] = 0; _dwValueType = dwValueType; _prflNext = NULL; } inline CRegFileList::~CRegFileList(void) { } inline void CRegFileList::SetNext(CRegFileList *prfl) { _prflNext = prfl; } inline CRegFileList * CRegFileList::GetNext(void) const { return _prflNext; } inline void CRegFileList::GetData(const TCHAR **pptsRoot, const TCHAR **pptsKey, const TCHAR **pptsVal, const TCHAR **pptsData, DWORD *pdwValType) const { *pptsRoot = _tsRootName; *pptsKey = _tsKeyName; *pptsVal = _tsValueName; *pptsData = _tsData; *pdwValType = _dwValueType; } CRegFileList *g_prflStart; //--------------------------------------------------------------- // Constants. const DWORD SID_GUESS = 80; const TCHAR HIVEFILE[] = TEXT("\\ntuser.dat"); const TCHAR HIVEPATH[] = TEXT("%temp%\\ntuser.dat"); const DWORD NUM_HASH_BUCKETS = 121; const TCHAR FORCE_SECTION[] = TEXT("Force Win9x Settings"); const TCHAR RENAME_SECTION[] = TEXT("Map Win9x to WinNT"); const TCHAR FUNCTION_SECTION[] = TEXT("Win9x Data Conversion"); const TCHAR SUPPRESS_SECTION[] = TEXT("Suppress Win9x Settings"); const TCHAR FILE_SECTION[] = TEXT("Map paths"); const TCHAR DELETE_SECTION[] = TEXT("Suppress WinNT Settings"); //--------------------------------------------------------------- // Macros // If this symbol is defined, loaduser will apply the state to the // specified user and cannot be run as that user. // If this symbols is not defined, loaduser will apply state to the // current user. #define SPECIFIC_USER 1 //--------------------------------------------------------------- // Globals. HASH_HEAD HashTable[NUM_HASH_BUCKETS]; FUNCTION_FA_MAP FunctionTable[] = { { TEXT("ConvertRecentDocsMRU"), ConvertRecentDocsMRU }, { TEXT("ConvertAppearanceScheme"), ConvertAppearanceScheme }, { TEXT("ConvertLogFont"), ConvertLogFont }, { TEXT("ConvertToDword"), ConvertToDword }, { TEXT("ConvertToString"), ConvertToString }, { TEXT("AntiAlias"), AntiAlias }, { TEXT("FixActiveDesktop"), FixActiveDesktop }, { NULL, NULL } }; //--------------------------------------------------------------- DWORD ShiftXOR( DWORD x, TCHAR c ) { if (x & 0x80000000) return (x << 1) ^ c | 1; else return (x << 1) ^ c; } //--------------------------------------------------------------- // Create a case insensitive hash of the input. DWORD Hash( TCHAR *ptsRoot, TCHAR *ptsKey, TCHAR *ptsValue ) { DWORD x = 0; DWORD i; // Hash the ptsRoot. if (ptsRoot != NULL) for (i = 0; ptsRoot[i] != 0; i++) x = ShiftXOR( x, _totupper(ptsRoot[i]) ); // Hash the key. if (ptsKey != NULL) for (i = 0; ptsKey[i] != 0; i++) x = ShiftXOR( x, _totupper(ptsKey[i]) ); // Hash the value. if (ptsValue != NULL) for (i = 0; ptsValue[i] != 0; i++) x = ShiftXOR( x, _totupper(ptsValue[i]) ); return x; } //--------------------------------------------------------------- DWORD null_tcsicmp( TCHAR *x, TCHAR *y ) { if (x == NULL) if (y == NULL) return 0; else return -1; else if (y == NULL) return 1; else return _tcsicmp( x, y ); } //--------------------------------------------------------------- // Do a case insensitive comparision of the input. BOOL Match( HASH_NODE *phnCurrent, DWORD dwHash, TCHAR *ptsRoot, TCHAR *ptsKey, TCHAR *ptsValue) { return phnCurrent->dwHash == dwHash && null_tcsicmp( phnCurrent->ptsRoot, ptsRoot ) == 0 && null_tcsicmp( phnCurrent->ptsKey, ptsKey ) == 0 && null_tcsicmp( phnCurrent->ptsValue, ptsValue ) == 0; } //--------------------------------------------------------------- HASH_NODE *Lookup( TCHAR *ptsRoot, TCHAR *ptsKey, TCHAR *ptsValue ) { DWORD dwHash = Hash( ptsRoot, ptsKey, ptsValue ); DWORD dwBucket = dwHash % NUM_HASH_BUCKETS; HASH_NODE *phnCurrent = (HASH_NODE *) HashTable[dwBucket].phhNext; // Look at all the nodes in the bucket. while (phnCurrent != (HASH_NODE *) &HashTable[dwBucket]) if (Match( phnCurrent, dwHash, ptsRoot, ptsKey, ptsValue )) return phnCurrent; else phnCurrent = phnCurrent->phnNext; return NULL; } //--------------------------------------------------------------- void Insert( HASH_NODE *phnNode ) { DWORD dwHash = Hash( phnNode->ptsRoot, phnNode->ptsKey, phnNode->ptsValue ); DWORD dwBucket = dwHash % NUM_HASH_BUCKETS; HASH_NODE *phnCurrent; // Look for an existing node. phnCurrent = Lookup( phnNode->ptsRoot, phnNode->ptsKey, phnNode->ptsValue ); // If found, copy in the state of the new node and free it. if (phnCurrent != NULL) { // Assume that the new value or key have not been set. if (phnNode->dwAction & rename_value_fa) { if (phnCurrent->ptsNewValue != NULL) { //Skip if (_tcsicmp(phnCurrent->ptsNewValue, phnNode->ptsNewValue)) Win32Printf(LogFile, "Warning: Skipping rename rule for %s\\%s [%s]" " to %s due to previous rename rule " "to %s.\r\n", phnNode->ptsRoot, phnNode->ptsKey, phnNode->ptsValue, phnNode->ptsNewValue, phnCurrent->ptsNewValue); goto cleanup; } else phnCurrent->ptsNewValue = phnNode->ptsNewValue; } if (phnNode->dwAction & (rename_leaf_fa | rename_path_fa)) { if (phnCurrent->ptsNewKey != NULL) { //Skip if (_tcsicmp(phnCurrent->ptsNewKey, phnNode->ptsNewKey)) Win32Printf(LogFile, "Warning: Skipping rename rule for %s\\%s " "to %s due to previous rename rule to %s.\r\n", phnNode->ptsRoot, phnNode->ptsKey, phnNode->ptsNewKey, phnCurrent->ptsNewKey); goto cleanup; } else phnCurrent->ptsNewKey = phnNode->ptsNewKey; } if (phnNode->dwAction & function_fa) { if (phnCurrent->ptsFunction != NULL) { //Skip if (_tcsicmp(phnCurrent->ptsNewKey, phnNode->ptsNewKey)) Win32Printf(LogFile, "Warning: Skipping function rule for %s\\%s " "to %s due to previous function call" " to %s.\r\n", phnNode->ptsRoot, phnNode->ptsKey, phnNode->ptsNewKey, phnCurrent->ptsFunction); goto cleanup; } else phnCurrent->ptsFunction = phnNode->ptsNewKey; } phnCurrent->dwAction |= phnNode->dwAction; if (VerboseReg) LogReadRule( phnNode ); cleanup: free( phnNode->ptsRoot ); free( phnNode->ptsKey ); free( phnNode->ptsValue ); free( phnNode ); } // Insert the node. else { phnCurrent = (HASH_NODE *) &HashTable[dwBucket]; phnNode->dwHash = dwHash; phnNode->phnNext = phnCurrent->phnNext; phnNode->phnPrev = phnCurrent; phnCurrent->phnNext->phnPrev = phnNode; phnCurrent->phnNext = phnNode; if (phnNode->dwAction & function_fa) { phnNode->ptsFunction = phnNode->ptsNewKey; phnNode->ptsNewKey = NULL; } if (VerboseReg) LogReadRule( phnNode ); } } //+--------------------------------------------------------------------------- // // Function: DeleteInf // // Synopsis: deletes values copied from .DEFAULT user hive // // Arguments: // // Returns: Appropriate status code // // History: 20-Sep-99 HenryLee Created // //---------------------------------------------------------------------------- DWORD DeleteInf () { DWORD dwResult = ERROR_SUCCESS; HKEY hRootKey = NULL; HKEY hKey = NULL; for (DWORD dwBucket = 0; dwBucket < NUM_HASH_BUCKETS; dwBucket++) { HASH_NODE *phnCurrent = (HASH_NODE *) HashTable[dwBucket].phhNext; // Look at all the nodes in the bucket. while (phnCurrent != (HASH_NODE *) &HashTable[dwBucket]) { if (phnCurrent->dwAction & delete_fa) { if (phnCurrent->ptsRoot != NULL) { if (_tcsicmp( TEXT("HKLM"), phnCurrent->ptsRoot ) == 0) hRootKey = HKEY_LOCAL_MACHINE; else hRootKey = CurrentUser; dwResult = RegOpenKeyEx( hRootKey, phnCurrent->ptsKey, NULL, KEY_ALL_ACCESS, &hKey ); if (dwResult == ERROR_SUCCESS) { dwResult = RegDeleteValue (hKey, phnCurrent->ptsValue); RegCloseKey (hKey); if (dwResult != ERROR_SUCCESS) { if (Verbose) Win32Printf(LogFile, "Warning. Cannot delete %s\\%s\n", phnCurrent->ptsKey, phnCurrent->ptsValue); dwResult = ERROR_SUCCESS; } } else dwResult = ERROR_SUCCESS; // keep on going } } phnCurrent = phnCurrent->phnNext; } } return dwResult; } DWORD ApplyRule(HASH_NODE *phnRule, TCHAR *ptsKeyMatch, TCHAR **pptsRoot, TCHAR **pptsKey, TCHAR **pptsValue, DWORD *pdwType, BYTE **ppbData, DWORD *pdwDataLen, BOOL *pfForce) { DWORD dwResult = ERROR_SUCCESS; if (phnRule->dwAction & force_fa) { if (DebugOutput || VerboseReg) Win32Printf(LogFile, "Applying force rule to %s\\%s [%s]\r\n", *pptsRoot, *pptsKey, (*pptsValue) ? *pptsValue : TEXT("NULL")); *pfForce = TRUE; } if (phnRule->dwAction & function_fa) { FUNCTION_FA_MAP *pMap = FunctionTable; while (pMap != NULL && pMap->ptsName != NULL) { if (lstrcmp (pMap->ptsName, phnRule->ptsFunction) == 0 && pMap->pfunction) { dwResult = (pMap->pfunction) (pdwType, ppbData, pdwDataLen); LOG_ASSERT (dwResult); } pMap++; } if (DebugOutput || VerboseReg) Win32Printf(LogFile, "Applying function_fa rule to %s\\%s [%s] " "(function %s)\r\n", *pptsRoot, *pptsKey, (*pptsValue) ? *pptsValue : TEXT("NULL"), phnRule->ptsFunction); } // Replace the path matched with the new path and leave the // portion of the path that was not matched. if (phnRule->dwAction & rename_path_fa) { DWORD dwLen = _tcslen( phnRule->ptsNewKey ) + _tcslen(ptsKeyMatch); TCHAR * ptsBuffer = (TCHAR *) malloc( (dwLen + 1) *sizeof(TCHAR) ); LOG_ASSERT_EXPR( ptsBuffer != NULL, IDS_NOT_ENOUGH_MEMORY, dwResult, ERROR_NOT_ENOUGH_MEMORY ); _tcscpy( ptsBuffer, phnRule->ptsNewKey ); _tcscat( ptsBuffer, ptsKeyMatch ); if (DebugOutput || VerboseReg) Win32Printf(LogFile, "Applying rename_path rule to %s\\%s [%s], " "result %s\r\n", *pptsRoot, *pptsKey, (*pptsValue) ? *pptsValue : TEXT("NULL"), ptsBuffer); free( *pptsKey ); *pptsKey = ptsBuffer; } // Replace the entire key with the new key. if (phnRule->dwAction & rename_leaf_fa) { DWORD dwLen = _tcslen( phnRule->ptsNewKey ) + 1; TCHAR *ptsBuffer = (TCHAR *) malloc( dwLen*sizeof(TCHAR) ); LOG_ASSERT_EXPR( ptsBuffer != NULL, IDS_NOT_ENOUGH_MEMORY, dwResult, ERROR_NOT_ENOUGH_MEMORY ); _tcscpy( ptsBuffer, phnRule->ptsNewKey ); if (DebugOutput || VerboseReg) Win32Printf(LogFile, "Applying rename_leaf rule to %s\\%s [%s], " "result %s\r\n", *pptsRoot, *pptsKey, (*pptsValue) ? *pptsValue : TEXT("NULL"), ptsBuffer); free( *pptsKey ); *pptsKey = ptsBuffer; } // Replace the entire value with the new value. if (phnRule->dwAction & rename_value_fa) { DWORD dwLen = _tcslen( phnRule->ptsNewValue ) + 1; TCHAR *ptsBuffer = (TCHAR *) malloc( dwLen*sizeof(TCHAR) ); LOG_ASSERT_EXPR( ptsBuffer != NULL, IDS_NOT_ENOUGH_MEMORY, dwResult, ERROR_NOT_ENOUGH_MEMORY ); _tcscpy( ptsBuffer, phnRule->ptsNewValue ); if (DebugOutput || VerboseReg) Win32Printf(LogFile, "Applying rename_value rule to %s\\%s [%s], " "result %s\r\n", *pptsRoot, *pptsKey, (*pptsValue) ? *pptsValue : TEXT("NULL"), ptsBuffer); free( *pptsValue ); *pptsValue = ptsBuffer; } // Ask what the new path should be. if ((phnRule->dwAction & file_fa) && *pptsValue != NULL) { //Nothing to do here, we'll do this in Filter } if (!(SourceVersion & 0x80000000)) *pfForce = TRUE; cleanup: return dwResult; } /*************************************************************************** Filter Look for a rule for each component of the path. If found, apply it. ***************************************************************************/ DWORD Filter( TCHAR **pptsRoot, TCHAR **pptsKey, TCHAR **pptsValue, DWORD *pdwType, BYTE **ppbData, DWORD *pdwDataLen, BOOL *pfForce ) { DWORD dwKeyLen = _tcslen( *pptsKey ) + 1; TCHAR *ptsKeyPath = (TCHAR *) _alloca( dwKeyLen*sizeof(TCHAR) ); TCHAR *ptsFrom; TCHAR *ptsTo; TCHAR *ptsEnd; HASH_NODE *phnRule = NULL; DWORD dwResult = ERROR_SUCCESS; BOOL fSuppress = FALSE; BOOL fFileRuleFound = FALSE; //Make copies of all the initial keys TCHAR *ptsRootBuf = (TCHAR *) _alloca((_tcslen(*pptsRoot) + 1) * sizeof(TCHAR)); TCHAR *ptsKeyBuf = (TCHAR *) _alloca( dwKeyLen * sizeof(TCHAR) ); TCHAR *ptsValBuf = NULL; if (*pptsValue) { ptsValBuf = (TCHAR *) _alloca((_tcslen(*pptsValue) + 1) * sizeof(TCHAR)); _tcscpy(ptsValBuf, *pptsValue); } _tcscpy(ptsRootBuf, *pptsRoot); _tcscpy(ptsKeyBuf, *pptsKey); ptsFrom = ptsKeyBuf; phnRule = NULL; // Loop over each part of the key path. ptsTo = ptsKeyPath; while (ptsFrom[0] != 0) { // Copy the next segment from pptsKey to ptsKeyPath. ptsEnd = _tcschr( &ptsFrom[1], L'\\' ); if (ptsEnd == NULL) ptsEnd = ptsKeyBuf+dwKeyLen-1; _tcsncpy( ptsTo, ptsFrom, ptsEnd-ptsFrom ); ptsTo[ptsEnd-ptsFrom] = 0; ptsTo += ptsEnd-ptsFrom; ptsFrom = ptsEnd; if ( *pptsValue != NULL ) { // First look up each piece with value attached phnRule = Lookup( ptsRootBuf, ptsKeyPath, ptsValBuf ); // Apply only if recursive or at the end of the key if (phnRule != NULL && ((phnRule->dwAction & recursive_fa) || (ptsFrom[0]==0))) { dwResult = ApplyRule(phnRule, ptsFrom, pptsRoot, pptsKey, pptsValue, pdwType, ppbData, pdwDataLen, pfForce); if (dwResult) goto cleanup; if (phnRule->dwAction & suppress_fa) { fSuppress = TRUE; } if (phnRule->dwAction & file_fa && (REG_SZ == *pdwType || REG_EXPAND_SZ == *pdwType || REG_MULTI_SZ == *pdwType)) { fSuppress = TRUE; fFileRuleFound = TRUE; } } } // Check with no value attached phnRule = Lookup( ptsRootBuf, ptsKeyPath, NULL ); // Apply only if recursive or at the end of the key if (phnRule != NULL && ((phnRule->dwAction & recursive_fa) || (ptsFrom[0]==0))) { dwResult = ApplyRule(phnRule, ptsFrom, pptsRoot, pptsKey, pptsValue, pdwType, ppbData, pdwDataLen, pfForce); if (dwResult) goto cleanup; if (phnRule->dwAction & suppress_fa) { fSuppress = TRUE; } if (phnRule->dwAction & file_fa && (REG_SZ == *pdwType || REG_EXPAND_SZ == *pdwType || REG_MULTI_SZ == *pdwType)) { fSuppress = TRUE; fFileRuleFound = TRUE; } } } if (fFileRuleFound) { //Add to the list of files to be fixed up later. CRegFileList *prfl = new CRegFileList(*pptsRoot, *pptsKey, *pptsValue, (TCHAR *)*ppbData, *pdwType); if (prfl == NULL) { Win32PrintfResource(LogFile, IDS_NOT_ENOUGH_MEMORY); dwResult = ERROR_NOT_ENOUGH_MEMORY; goto cleanup; } if (DebugOutput || VerboseReg) Win32Printf(LogFile, "Applying file_fa rule to %s\\%s [%s], " "data = %s\r\n", *pptsRoot, *pptsKey, (*pptsValue) ? *pptsValue : TEXT("NULL"), (TCHAR *)*ppbData); prfl->SetNext(g_prflStart); g_prflStart = prfl; } if (fSuppress) { free(*pptsKey); free(*pptsValue); *pptsRoot = NULL; *pptsKey = NULL; *pptsValue = NULL; } cleanup: if (Verbose && dwResult != ERROR_SUCCESS) printf( "Filter failed with 0x%x\r\n", dwResult ); return dwResult; } //--------------------------------------------------------------- DWORD LoadSectionRules( const TCHAR *ptsSection, DWORD dwFlags ) { INFCONTEXT ic; DWORD dwResult = ERROR_SUCCESS; BOOL fSuccess; HASH_NODE *phnRule; // Open the section. fSuccess = SetupFindFirstLine( InputInf, ptsSection, NULL, &ic ); // Read all the rules in the section. while (fSuccess) { // Parse the rule. dwResult = ParseRule( &ic, &phnRule ); FAIL_ON_ERROR( dwResult ); if (dwFlags == function_fa) // remove the rename flags { phnRule->dwAction = function_fa; } else { phnRule->dwAction |= dwFlags; } // Save the rule in the hash table. Insert( phnRule ); phnRule = NULL; // Advance to the next line. fSuccess = SetupFindNextLine( &ic, &ic ); } cleanup: return dwResult; } /*************************************************************************** InitializeHash Read the filtering rules from the specified INF file. Read the rules from the sections for forcing, suppressing, renaming, and functions. ***************************************************************************/ DWORD InitializeHash() { DWORD i; DWORD dwResult = ERROR_SUCCESS; INFCONTEXT ic; BOOL fSuccess; TCHAR *ptsBuffer; CStringList *pslAdd = NULL; CStringList *pslRen = NULL; CStringList *pslFile = NULL; CStringList *pslDel = NULL; CStringList *pslCurr; // Initialize the hash table. for (i = 0; i < NUM_HASH_BUCKETS; i++) { HashTable[i].phhNext = &HashTable[i]; HashTable[i].phhPrev = &HashTable[i]; } // Load rules from the filter sections. // Since we try to force by default, it is okay to load in the Win9x force rules // and apply them even if the source is NT. If they exist, we'll force overwriting, // but if not, no harm done. dwResult = LoadSectionRules( FORCE_SECTION, force_fa ); LOG_ASSERT( dwResult ); // We shouldn't write these keys regardless of the source OS dwResult = LoadSectionRules( SUPPRESS_SECTION, suppress_fa ); LOG_ASSERT( dwResult ); // This section describes keys that should be removed from the default hive before // migrating the settings. It is not specific to any source OS. dwResult = LoadSectionRules( DELETE_SECTION, delete_fa ); LOG_ASSERT( dwResult ); if (SourceVersion & 0x80000000) { dwResult = LoadSectionRules( RENAME_SECTION, 0 ); LOG_ASSERT( dwResult ); dwResult = LoadSectionRules( FILE_SECTION, file_fa ); LOG_ASSERT( dwResult ); dwResult = LoadSectionRules( FUNCTION_SECTION, function_fa ); LOG_ASSERT( dwResult ); } // Load from copied rules sections. dwResult = LoadSectionRules( EXTENSION_ADDREG_SECTION, force_fa ); LOG_ASSERT( dwResult ); dwResult = LoadSectionRules( EXTENSION_RENREG_SECTION, 0 ); LOG_ASSERT( dwResult ); dwResult = LoadSectionRules( EXTENSION_REGFILE_SECTION, file_fa ); LOG_ASSERT( dwResult ); dwResult = LoadSectionRules( EXTENSION_DELREG_SECTION, suppress_fa ); LOG_ASSERT( dwResult ); // Open the section list. fSuccess = SetupFindFirstLine( InputInf, EXTENSION_SECTION, NULL, &ic ); if (!fSuccess) return ERROR_SUCCESS; // Allocate the section name lists. pslAdd = new CStringList( 0 ); pslRen = new CStringList( 0 ); pslFile = new CStringList( 0 ); pslDel = new CStringList( 0 ); if (pslAdd == NULL || pslRen == NULL || pslFile == NULL || pslDel == NULL) { dwResult = ERROR_NOT_ENOUGH_MEMORY; LOG_ASSERT( dwResult ); } // Make lists of the names of sections of each type. do { // Parse the line. dwResult = ParseSectionList( &ic, &ptsBuffer, &pslCurr ); FAIL_ON_ERROR( dwResult ); // Save the value if its one of the ones we are looking for. if (ptsBuffer != NULL) { if (_tcsicmp( ptsBuffer, ADDREG_LABEL ) == 0) pslAdd->Add( pslCurr ); else if (_tcsicmp( ptsBuffer, RENREG_LABEL ) == 0) pslRen->Add( pslCurr ); else if (_tcsicmp( ptsBuffer, REGFILE_LABEL ) == 0) pslFile->Add( pslCurr ); else if (_tcsicmp( ptsBuffer, DELREG_LABEL ) == 0) pslDel->Add( pslCurr ); else if (!_tcsicmp( ptsBuffer, COPYFILES_LABEL ) && !_tcsicmp( ptsBuffer, DELFILES_LABEL )) LOG_ASSERT_EXPR( FALSE, IDS_INF_ERROR, dwResult, SPAPI_E_GENERAL_SYNTAX ); free( ptsBuffer ); } // Advance to the next line. fSuccess = SetupFindNextLine( &ic, &ic ); } while( fSuccess); // Process all the addreg sections. for (pslCurr = pslAdd->Next(); pslCurr != pslAdd; pslCurr = pslCurr->Next()) { dwResult = LoadSectionRules( pslCurr->String(), force_fa ); LOG_ASSERT( dwResult ); } // Process all the renreg sections. for (pslCurr = pslRen->Next(); pslCurr != pslRen; pslCurr = pslCurr->Next()) { dwResult = LoadSectionRules( pslCurr->String(), 0 ); LOG_ASSERT( dwResult ); } // Process all the regfile sections. for (pslCurr = pslFile->Next(); pslCurr != pslFile; pslCurr = pslCurr->Next()) { dwResult = LoadSectionRules( pslCurr->String(), file_fa ); LOG_ASSERT( dwResult ); } // Process all the delreg sections. for (pslCurr = pslDel->Next(); pslCurr != pslDel; pslCurr = pslCurr->Next()) { dwResult = LoadSectionRules( pslCurr->String(), suppress_fa ); LOG_ASSERT( dwResult ); } cleanup: if (pslAdd != NULL) delete pslAdd; if (pslRen != NULL) delete pslRen; if (pslFile != NULL) delete pslFile; if (pslDel != NULL) delete pslDel; return dwResult; } /*************************************************************************** ParseAssignment Parse the line into a variable name and a value name. Allow optional whitespace and quotes around the variable or value names. This function allocates buffers for the variable and value names which the caller must free. Return a NULL pointer for the variable name if the line cannot be parsed. Note: The caller is required to free the following variables even if this function fails. pptsVar pptsValue ***************************************************************************/ DWORD ParseAssignment( INFCONTEXT *pic, DWORD dwLen, TCHAR **pptsVar, TCHAR **pptsValue ) { BOOL fSuccess; DWORD dwResult = ERROR_SUCCESS; DWORD dwVarLen; DWORD dwValueLen; // Initialize out params *pptsVar = *pptsValue = NULL; // Query the two lengths we need fSuccess = SetupGetStringField( pic, 0, NULL, 0, &dwVarLen ); LOG_ASSERT_GLE( fSuccess, dwResult ); fSuccess = SetupGetStringField( pic, 1, NULL, 0, &dwValueLen ); LOG_ASSERT_GLE( fSuccess, dwResult ); // Allocate memory for both *pptsVar = (TCHAR *) malloc( dwVarLen * sizeof(TCHAR) ); *pptsValue = (TCHAR *) malloc( dwValueLen * sizeof(TCHAR) ); if( *pptsVar == NULL || *pptsValue == NULL ) { free(*pptsVar); free(*pptsValue); *pptsVar = *pptsValue = NULL; Win32PrintfResource( LogFile, IDS_NOT_ENOUGH_MEMORY ); return ERROR_NOT_ENOUGH_MEMORY; } // Read the variable name fSuccess = SetupGetStringField( pic, 0, *pptsVar, dwVarLen, NULL ); LOG_ASSERT_EXPR(fSuccess, IDS_GETSTRINGFIELD_ERROR, dwResult, SPAPI_E_SECTION_NAME_TOO_LONG); // Read the value name fSuccess = SetupGetStringField( pic, 1, *pptsValue, dwValueLen, NULL ); LOG_ASSERT_EXPR(fSuccess, IDS_GETSTRINGFIELD_ERROR, dwResult, SPAPI_E_SECTION_NAME_TOO_LONG); cleanup: return dwResult; } /*************************************************************************** ReadUser Read the user section of migration.inf and return the values for the name of the settings section, the user name, and the domain name. Note: The caller is required to free the following variables even if this function fails. pptsSettingsSection pptsDomainName pptsUsername ***************************************************************************/ DWORD ReadUser( TCHAR **pptsSettingsSection, TCHAR **pptsDomainName, TCHAR **pptsUsername ) { DWORD dwResult; BOOL fSuccess; INFCONTEXT ic; DWORD dwReqLen; TCHAR *var; TCHAR *value; TCHAR *user_section = NULL; // Find the section for users. fSuccess = SetupFindFirstLine( InputInf, USERS_SECTION, NULL, &ic ); if (fSuccess == FALSE) { dwResult = GetLastError(); if (Verbose) Win32Printf(LogFile, "ERROR: Could not find %s in Input INF: %d\r\n", USERS_SECTION, dwResult); LOG_ASSERT( dwResult ); } // Find the name of the section containing user info. do { // Find the length of the line. dwReqLen = 0; fSuccess = SetupGetLineText( &ic, NULL, NULL, NULL, NULL, 0, &dwReqLen ); if (dwReqLen == 0) LOG_ASSERT_GLE( fSuccess, dwResult ); // Parse the line. dwResult = ParseAssignment( &ic, dwReqLen, &var, &value ); FAIL_ON_ERROR( dwResult ); // Save the value if its one of the ones we are looking for. if (var != NULL) { if (_tcsicmp( var, TEXT("section") ) == 0) user_section = value; else free( value ); free( var ); } // Advance to the next line. fSuccess = SetupFindNextLine( &ic, &ic ); } while( fSuccess); // Find the section for the user. fSuccess = SetupFindFirstLine( InputInf, user_section, NULL, &ic ); LOG_ASSERT_GLE( fSuccess, dwResult ); // Read each line in the section. do { // Find the length of the line. dwReqLen = 0; fSuccess = SetupGetLineText( &ic, NULL, NULL, NULL, NULL, 0, &dwReqLen ); if (dwReqLen == 0) LOG_ASSERT_GLE( fSuccess, dwResult ); // Parse the line. dwResult = ParseAssignment( &ic, dwReqLen, &var, &value ); FAIL_ON_ERROR( dwResult ); // Save the value if its one of the ones we are looking for. if (var != NULL) { if (_tcsicmp( var, TEXT("user") ) == 0) *pptsUsername = value; else if (_tcsicmp( var, TEXT("domain") ) == 0) *pptsDomainName = value; else if (_tcsicmp( var, TEXT("section") ) == 0) *pptsSettingsSection = value; else free( value ); free( var ); } // Advance to the next line. fSuccess = SetupFindNextLine( &ic, &ic ); } while( fSuccess); // It is an error if the username, domainname, or settings section // isn't specified. if (*pptsUsername == NULL || *pptsDomainName == NULL || *pptsSettingsSection == NULL) { Win32PrintfResource( LogFile, IDS_INF_ERROR ); dwResult = SPAPI_E_GENERAL_SYNTAX; } cleanup: if (user_section != NULL) free( user_section ); return dwResult; } /*************************************************************************** ParseRegistry Parse a line describing a registry key or value. reg-root-string, [subkey], [value-name], [flags], [value] reg-root-string One of HKCR, HKCU, HKLM, HKU, HKR subkey String name of subkey, may be quoted. value-name String name of value, may be quoted. flags One of the following 0x0 REG_SZ 0x10000 REG_MULTI_SZ 0x20000 REG_EXPAND_SZ 0x1 REG_BINARY 0x10001 REG_DWORD 0x100001 REG_MULTI_SZ stored as binary because it contains embedded newlines. 0x200001 REG_EXPAND_SZ stored as binary because it contains embedded newlines. 0x400001 REG_SZ stored as binary because it contains embedded newlines. 0x800000 REG_NONE other custom registry type directly copied value Depends on flags REG_SZ String, may be quoted. REG_MULTI_SZ List of comma separated strings, each of which may be quoted. REG_EXPAND_SZ String, may be quoted. REG_BINARY List of comma separated bytes in hex. REG_DWORD Integer Note: The caller is required to free the following variables even if this function fails. pptsRootName key_name value_name data ***************************************************************************/ DWORD ParseRegistry( INFCONTEXT *pic, DWORD line_len, TCHAR **pptsRootName, TCHAR **key_name, TCHAR **value_name, DWORD *value_type, TCHAR **data, DWORD *data_len ) { DWORD len; DWORD temp; BYTE *bytes; DWORD size = line_len*sizeof(TCHAR); DWORD req_size; BOOL fSuccess; DWORD dwResult = ERROR_SUCCESS; // Allocate memory for all the parameters. *key_name = (TCHAR *) malloc( size ); *value_name = (TCHAR *) malloc( size ); *data = (TCHAR *) malloc( size ); *pptsRootName = (TCHAR *) malloc( size ); if (*key_name == NULL || *value_name == NULL || *data == NULL || *pptsRootName == NULL) { free( *key_name ); free( *value_name ); free( *data ); free( *pptsRootName ); *key_name = NULL; *value_name = NULL; *data = NULL; *pptsRootName = NULL; Win32PrintfResource( LogFile, IDS_NOT_ENOUGH_MEMORY ); return ERROR_NOT_ENOUGH_MEMORY; } // Get the reg-root-string. fSuccess = SetupGetStringField( pic, 1, *pptsRootName, line_len, &req_size ); LOG_ASSERT_EXPR( fSuccess, IDS_INF_ERROR, dwResult, SPAPI_E_GENERAL_SYNTAX ); // Verify that it is HKR or HKLM. fSuccess = (_tcsicmp( TEXT("HKR"), *pptsRootName ) == 0) || (_tcsicmp( TEXT("HKLM"), *pptsRootName ) == 0); LOG_ASSERT_EXPR( fSuccess, IDS_INF_ERROR, dwResult, SPAPI_E_GENERAL_SYNTAX ); // Get the subkey. fSuccess = SetupGetStringField( pic, 2, *key_name, line_len, &req_size ); LOG_ASSERT_EXPR( fSuccess, IDS_INF_ERROR, dwResult, SPAPI_E_GENERAL_SYNTAX ); // Get the value name. fSuccess = SetupGetStringField( pic, 3, *value_name, line_len, &req_size ); LOG_ASSERT_EXPR( fSuccess, IDS_INF_ERROR, dwResult, SPAPI_E_GENERAL_SYNTAX ); // Get the flags. _tcstol detects a leading 0x and converts from hex. fSuccess = SetupGetIntField( pic, 4, (int *) value_type ); // Read the data based on the data type. if (fSuccess) // value_type is valid { // Read a string. if (*value_type == 0) { fSuccess = SetupGetStringField( pic, 5, *data, line_len, &req_size ); LOG_ASSERT_EXPR( fSuccess, IDS_INF_ERROR, dwResult, SPAPI_E_GENERAL_SYNTAX ); *data_len = req_size*sizeof(TCHAR); *value_type = REG_SZ; } // Read an expand string. else if (*value_type == 0x20000) { fSuccess = SetupGetStringField( pic, 5, *data, line_len, &req_size ); LOG_ASSERT_EXPR( fSuccess, IDS_INF_ERROR, dwResult, SPAPI_E_GENERAL_SYNTAX ); *data_len = req_size*sizeof(TCHAR); *value_type = REG_EXPAND_SZ; } // Read a multi string. else if (*value_type == 0x10000) { fSuccess = SetupGetMultiSzField( pic, 5, *data, line_len, &req_size ); LOG_ASSERT_EXPR( fSuccess, IDS_INF_ERROR, dwResult, SPAPI_E_GENERAL_SYNTAX ); *data_len = req_size*sizeof(TCHAR); *value_type = REG_MULTI_SZ; } // Read a dword. else if (*value_type == 0x10001) { fSuccess = SetupGetIntField( pic, 5, (int *) *data ); LOG_ASSERT_EXPR( fSuccess, IDS_INF_ERROR, dwResult, SPAPI_E_GENERAL_SYNTAX ); *data_len = sizeof(DWORD); *value_type = REG_DWORD; } // Read a binary. else { fSuccess = SetupGetBinaryField( pic, 5, (BYTE *) *data, size, &req_size ); LOG_ASSERT_EXPR( fSuccess, IDS_INF_ERROR, dwResult, SPAPI_E_GENERAL_SYNTAX ); *data_len = req_size; if (*value_type == 1) *value_type = REG_BINARY; else if (*value_type == 0x100001) *value_type = REG_MULTI_SZ; else if (*value_type == 0x200001) *value_type = REG_EXPAND_SZ; else if (*value_type == 0x400001) *value_type = REG_SZ; else if (*value_type == 0x800000) *value_type = REG_NONE; } } else { *value_type = REG_NONE; *data_len = 0; *data = NULL; } cleanup: return dwResult; } //--------------------------------------------------------------- DWORD CopyInf( const TCHAR *ptsSettingsSection ) { DWORD dwResult; BOOL fSuccess; INFCONTEXT ic; DWORD line_len = 0; DWORD dwReqLen; TCHAR *ptsKeyName = NULL; TCHAR *ptsValueName = NULL; TCHAR *ptsRootName = NULL; DWORD dwValueType; BYTE *data = NULL; DWORD dwDataLen; HKEY hKey = NULL; BOOL fForce; BOOL fExist; HKEY hRootKey; if (Verbose) { Win32Printf(LogFile, "Processing Section [%s]\r\n", ptsSettingsSection); } // Find the section. fSuccess = SetupFindFirstLine( InputInf, ptsSettingsSection, NULL, &ic ); if (!fSuccess) return ERROR_SUCCESS; // Process each line in the section. do { // Determine the line length. fForce = FALSE; fSuccess = SetupGetLineText( &ic, NULL, NULL, NULL, NULL, 0, &dwReqLen ); if (dwReqLen == 0) LOG_ASSERT_GLE( fSuccess, dwResult ); // Parse the line. dwResult = ParseRegistry( &ic, dwReqLen, &ptsRootName, &ptsKeyName, &ptsValueName, &dwValueType, (TCHAR **) &data, &dwDataLen ); FAIL_ON_ERROR( dwResult ); if (ptsKeyName != NULL) { if ( VerboseReg ) { Win32Printf(LogFile, "Processing Key: "); WriteKey( LogFile, dwValueType, ptsRootName, ptsKeyName, ptsValueName, data, dwDataLen); } dwResult = Filter( &ptsRootName, &ptsKeyName, &ptsValueName, &dwValueType, &data, &dwDataLen, &fForce ); FAIL_ON_ERROR( dwResult ); // Create or open the key. if (ptsRootName != NULL) { if (_tcsicmp( TEXT("HKLM"), ptsRootName ) == 0) { if (UserPortion) { goto cleanup; } hRootKey = HKEY_LOCAL_MACHINE; } else { hRootKey = CurrentUser; } dwResult = RegCreateKeyEx( hRootKey, ptsKeyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL ); #ifndef SPECIFIC_USER if (dwResult == ERROR_ACCESS_DENIED) { Win32PrintfResource( LogFile, IDS_REG_ACCESS, ptsRootName, ptsKeyName, NULL ); dwResult = ERROR_SUCCESS; } else #endif if (data != NULL) { LOG_ASSERT( dwResult ); // ptsValueName == NULL means key's unnamed // or default value if (!fForce) fExist = RegQueryValueEx( hKey, ptsValueName, NULL, NULL, NULL, NULL ) == ERROR_SUCCESS; // Set values that don't exist or are forced. if (fForce || !fExist) { if ( VerboseReg ) { Win32Printf(LogFile, "=> Writing Key: "); WriteKey( LogFile, dwValueType, ptsRootName, ptsKeyName, ptsValueName, data, dwDataLen); } dwResult = RegSetValueEx( hKey, ptsValueName, NULL, dwValueType, data, dwDataLen ); LOG_ASSERT( dwResult ); } } } // Free strings from the parser. free( ptsRootName ); free( ptsKeyName ); free( ptsValueName ); free( data ); RegCloseKey( hKey ); ptsRootName = NULL; hKey = NULL; ptsKeyName = NULL; ptsValueName = NULL; data = NULL; } // Skip to the next line. fSuccess = SetupFindNextLine( &ic, &ic ); } while(fSuccess); cleanup: // Close the key. if (hKey != NULL) RegCloseKey( hKey ); // Free strings from the parser. free( ptsRootName ); free( ptsKeyName ); free( ptsValueName ); free( data ); return dwResult; } /*************************************************************************** BuildHive This function creates a hive for the specified user by copying the default hive and adding all the registry keys in migration.inf according to the registry rules. The function returns the path to the hive. The caller is required to free the path to the hive even when this function fails. ***************************************************************************/ DWORD BuildHive( TCHAR *ptsSettingsSection, TCHAR **pptsHiveName ) { TCHAR tsDefaultUser[MAX_PATH]; DWORD dwDefaultUserLen = sizeof(tsDefaultUser); DWORD dwResult = ERROR_SUCCESS; DWORD dwLen; BOOL fSuccess; #ifdef SPECIFIC_USER // Find the location of the default user profile. fSuccess = GetDefaultUserProfileDirectory( tsDefaultUser, &dwDefaultUserLen ); LOG_ASSERT_GLE( fSuccess, dwResult ); if (dwDefaultUserLen + sizeof(HIVEFILE)+2 > MAX_PATH*sizeof(TCHAR) ) { Win32PrintfResource( LogFile, IDS_FAILED ); dwResult = ERROR_INTERNAL_ERROR; goto cleanup; } _tcscat( tsDefaultUser, HIVEFILE ); // Compute a path for the temporary hive. *pptsHiveName = (TCHAR *) malloc( MAX_PATH*sizeof(TCHAR) ); LOG_ASSERT_EXPR( *pptsHiveName != NULL, IDS_NOT_ENOUGH_MEMORY, dwResult, ERROR_NOT_ENOUGH_MEMORY ); dwLen = ExpandEnvironmentStrings( HIVEPATH, *pptsHiveName, MAX_PATH ); LOG_ASSERT_EXPR( dwLen != 0 && dwLen <= MAX_PATH, IDS_FAILED, dwResult, ERROR_INTERNAL_ERROR ); // To handle errors better, preemptively unload any old key in the // registry at the path this function uses. RegUnLoadKey( HKEY_USERS, BUILDKEY ); // Copy the default user hive to the temporary location. fSuccess = CopyFile( tsDefaultUser, *pptsHiveName, FALSE ); LOG_ASSERT_GLE( fSuccess, dwResult ); if (DebugOutput) Win32Printf(LogFile, "Loading the hive from %s\r\n", *pptsHiveName); // Load the hive. dwResult = RegLoadKey( HKEY_USERS, BUILDKEY, *pptsHiveName ); LOG_ASSERT( dwResult ); // Open the registry key. dwResult = RegOpenKeyEx( HKEY_USERS, BUILDKEY, 0, KEY_ALL_ACCESS, &CurrentUser ); LOG_ASSERT( dwResult ); #else dwResult = RegOpenKeyEx( HKEY_CURRENT_USER, NULL, 0, KEY_ALL_ACCESS, &CurrentUser ); LOG_ASSERT( dwResult ); #endif dwResult = DeleteInf (); // delete unwanted .DEFAULT values FAIL_ON_ERROR (dwResult); // Process the INF file. dwResult = CopyInf( ptsSettingsSection ); FAIL_ON_ERROR( dwResult ); cleanup: return dwResult; } //--------------------------------------------------------------- void CleanupUser() { // Close the key. if (CurrentUser != NULL) { RegCloseKey( CurrentUser ); CurrentUser = NULL; } // Unload the hive. RegUnLoadKey( HKEY_USERS, BUILDKEY ); } //--------------------------------------------------------------- DWORD CreateUserProfileFromName( TCHAR *ptsDomainName, TCHAR *ptsUsername, TCHAR *ptsHiveName ) { SID *pSid; DWORD dwSidLen = SID_GUESS; TCHAR *ptsFullName; DWORD dwDomainLen; DWORD dwUserLen; SID_NAME_USE sid_use; DWORD dwResult = ERROR_SUCCESS; BOOL fSuccess; #ifdef SPECIFIC_USER // Create the user profile when /u or (/f without /q flag) was used if ((FALSE == CopyUser) && ((FALSE == CopyFiles) || (TRUE == TestMode))) #endif return ERROR_SUCCESS; #ifdef SPECIFIC_USER //Close the registry keys and stuff, we'll get them back after we create //the profile. CleanupUser(); dwDomainLen = _tcslen( ptsDomainName ) + 1; dwUserLen = _tcslen( ptsUsername ) + 1; // Allocate space to hold the sid and construct the full domain\username. pSid = (SID *) _alloca( dwSidLen ); ptsFullName = (TCHAR *) _alloca( (dwDomainLen + dwUserLen + 2) * sizeof(TCHAR) ); _tcscpy( ptsFullName, ptsDomainName ); ptsFullName[dwDomainLen-1] = L'\\'; _tcscpy( &ptsFullName[dwDomainLen], ptsUsername ); // Get the SID for the specified user. fSuccess = LookupAccountName( NULL, ptsFullName, pSid, &dwSidLen, ptsDomainName, &dwDomainLen, &sid_use); if (!fSuccess) { // Try allocating a bigger buffer. if (dwSidLen > SID_GUESS) { pSid = (SID *) _alloca( dwSidLen ); fSuccess = LookupAccountName( NULL, ptsFullName, pSid, &dwSidLen, ptsDomainName, &dwDomainLen, &sid_use); } if (fSuccess == FALSE) { dwResult = GetLastError(); if (DebugOutput) { Win32Printf(LogFile, "Could not find account name for %s: %d\r\n", ptsFullName, dwResult); } } LOG_ASSERT( dwResult ); } // Allocate memory to hold the path to the user profile. UserPath = (TCHAR *) malloc( MAX_PATH*sizeof(TCHAR) ); UserPath[0]=0; LOG_ASSERT_EXPR( UserPath != NULL, IDS_NOT_ENOUGH_MEMORY, dwResult, ERROR_NOT_ENOUGH_MEMORY ); // Create the user profile directory. fSuccess = CreateUserProfile( pSid, ptsUsername, ptsHiveName, UserPath, MAX_PATH*sizeof(TCHAR) ); if (DebugOutput) Win32Printf(LogFile, "Creating Profile for %s in %s from %s\r\n", ptsUsername, UserPath, ptsHiveName); if (fSuccess == FALSE) { dwResult = GetLastError(); if (dwResult == ERROR_SHARING_VIOLATION) { Win32PrintfResource( LogFile, IDS_CANT_LOAD_CURRENT_USER ); goto cleanup; } LOG_ASSERT( dwResult ); } if (0 == UserPath[0]) { Win32PrintfResource( LogFile, IDS_USER_PROFILE_FAILED ); dwResult = ERROR_INTERNAL_ERROR; goto cleanup; } //Reopen the new hive TCHAR _tcsHivePath[MAX_PATH + 1]; if (_tcslen(UserPath) + _tcslen(HIVEFILE) > MAX_PATH) { if (DebugOutput) { Win32Printf(LogFile, "Error: hivepath too long %s%s\r\n", UserPath, HIVEFILE); } dwResult = ERROR_FILENAME_EXCED_RANGE; goto cleanup; } _tcscpy(_tcsHivePath, UserPath); _tcscat(_tcsHivePath, HIVEFILE); dwResult = RegLoadKey(HKEY_USERS, BUILDKEY, _tcsHivePath); if (DebugOutput) Win32Printf(LogFile, "Loading hive from %s\r\n", _tcsHivePath); if (dwResult) { LOG_ASSERT( dwResult ); } //Reopen the registry from the new location dwResult = RegOpenKeyEx(HKEY_USERS, BUILDKEY, 0, KEY_ALL_ACCESS, &CurrentUser); if (dwResult) { LOG_ASSERT(dwResult); } cleanup: return dwResult; #endif } //--------------------------------------------------------------- DWORD FixSpecial() { CRegFileList *prfl = g_prflStart; DWORD dwResult = ERROR_SUCCESS; while (prfl != NULL) { const TCHAR *ptsRoot, *ptsKey, *ptsVal, *ptsData; DWORD dwValueType; TCHAR *ptsLocation, *ptsFinalValue; TCHAR tsExpand[MAX_PATH + 1]; TCHAR tsTemp[MAX_PATH + 1]; prfl->GetData(&ptsRoot, &ptsKey, &ptsVal, &ptsData, &dwValueType); dwResult = WhereIsThisFile(ptsData, &ptsLocation); if (ERROR_NOT_FOUND == dwResult) { ptsLocation = (TCHAR *)ptsData; } else if (ERROR_SUCCESS != dwResult) { return dwResult; } //Expand any environment strings in the original data with //the values for the user we're loading for. If the final //paths match, we'll retain the version of the data with the //unexpanded environment variables in it. Otherwise, we take //the full path. if (_tcslen(ptsData) > MAX_PATH) { if (DebugOutput) { Win32Printf(LogFile, "Error: ptsData too long %s\r\n", ptsData); } return ERROR_FILENAME_EXCED_RANGE; } _tcscpy(tsExpand, ptsData); dwResult = ExpandEnvStringForUser(tsExpand, tsTemp, &ptsFinalValue); if (dwResult) return dwResult; if (_tcsicmp(ptsLocation, ptsFinalValue) == 0) { //They're the same, use the string with the environment //variables in it. ptsFinalValue = (TCHAR *)ptsData; } else { ptsFinalValue = ptsLocation; } if (ptsRoot != NULL) { HKEY hRootKey; HKEY hKey; if (_tcsicmp(TEXT("HKLM"), ptsRoot) == 0) hRootKey = HKEY_LOCAL_MACHINE; else hRootKey = CurrentUser; dwResult = RegCreateKeyEx(hRootKey, ptsKey, NULL, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL); LOG_ASSERT(dwResult); if ( VerboseReg ) { Win32Printf(LogFile, "=> Writing Key: "); WriteKey(LogFile, dwValueType, (TCHAR *)ptsRoot, (TCHAR *)ptsKey, (TCHAR *)ptsVal, (UCHAR *)ptsFinalValue, _tcslen(ptsFinalValue)+1); } dwResult = RegSetValueEx(hKey, ptsVal, NULL, dwValueType, (BYTE *)ptsFinalValue, (_tcslen(ptsFinalValue) + 1) * sizeof(TCHAR)); RegCloseKey(hKey); LOG_ASSERT(dwResult); } free(ptsLocation); // Next: CRegFileList *prflPrev; prflPrev = prfl; prfl = prfl->GetNext(); delete prflPrev; g_prflStart = prfl; } cleanup: return dwResult; } //--------------------------------------------------------------- DWORD LoadUser( TCHAR **pptsDomainName, TCHAR **pptsUsername, TCHAR **pptsHiveName ) { TCHAR *ptsSettingsSection = NULL; DWORD dwResult; // Initialize the hash table with the filter rules. dwResult = InitializeHash( ); FAIL_ON_ERROR( dwResult ); // Fetch user info only if /u or (/f without /q) flag was used if ((FALSE == CopyUser) && ((FALSE == CopyFiles) || (TRUE == TestMode))) { // Open the registry key. dwResult = RegOpenKeyEx( HKEY_CURRENT_USER, NULL, 0, KEY_ALL_ACCESS, &CurrentUser ); LOG_ASSERT( dwResult ); return ERROR_SUCCESS; } // Read the user information from the inf file. dwResult = ReadUser( &ptsSettingsSection, pptsDomainName, pptsUsername ); FAIL_ON_ERROR( dwResult ); #ifdef SPECIFIC_USER // Enable some privileges. dwResult = EnableBackupPrivilege(); FAIL_ON_ERROR( dwResult ); #endif // If the user was on a Win9x machine, // apply all the settings to a new hive. dwResult = BuildHive( ptsSettingsSection, pptsHiveName ); FAIL_ON_ERROR( dwResult ); cleanup: if (ptsSettingsSection != NULL) free( ptsSettingsSection ); return dwResult; } //--------------------------------------------------------------- DWORD ProcessExtensions() { // Apply registry keys in the copied state section. return CopyInf( EXTENSION_STATE_SECTION ); } //***************************************************************** // // Synopsis: Build a file list string out of a CStringList. // // History: 11/14/1999 Created by WeiruC. // // Return Value: Win32 error code. // //***************************************************************** DWORD BuildFileListString(CStringList* fileList, TCHAR** tcsFileList) { DWORD cFileListBuffer = 10240; // length of file list string buffer DWORD cFileListString = 0; // length of file list string DWORD rv = ERROR_SUCCESS; // return value TCHAR* tcsTargetFileName = NULL; TCHAR* tmpStringBuffer; CStringList* cur; *tcsFileList = new TCHAR[cFileListBuffer]; **tcsFileList = TEXT('\0'); if(fileList == NULL || (fileList->String())[0] == TEXT('\0')) { return rv; } cur = fileList->Next(); // // For every file in the source file list, call Phil's code to figure out // where that file is migrated to, and then add it to the target file list // string. // do { rv = WhereIsThisFile(cur->String(), &tcsTargetFileName); if(rv == ERROR_SUCCESS) { if(cFileListBuffer - cFileListString <= _tcslen(tcsTargetFileName)) { // // String buffer is not big enough. Double it. // tmpStringBuffer = *tcsFileList; *tcsFileList = new TCHAR[cFileListBuffer *= 2]; _tcscpy(*tcsFileList, tmpStringBuffer); delete []tmpStringBuffer; } // // Add the new file name to the new file list. // _tcscat(*tcsFileList, tcsTargetFileName); _tcscat(*tcsFileList, TEXT(" ")); cFileListString += _tcslen(tcsTargetFileName) + 1; } if(tcsTargetFileName != NULL) { free(tcsTargetFileName); tcsTargetFileName = NULL; } if(cur == fileList) { break; } // // Go to the next file. // cur = cur->Next(); } while(TRUE); if(tcsTargetFileName != NULL) { free(tcsTargetFileName); } return rv; } //***************************************************************** // // Synopsis: Run an executable in a child process. // // History: 11/14/1999 Created by WeiruC. // // Return Value: Win32 error code. // //***************************************************************** DWORD RunCommandInChildProcess(CStringList* command, CStringList* fileList) { SECURITY_ATTRIBUTES sa; // allow handles to be inherited DWORD rv = ERROR_SUCCESS; // return value STARTUPINFO si; PROCESS_INFORMATION pi; TCHAR* tcsFileList = NULL; TCHAR* cur; CStringList* tmp; // used when growing the string TCHAR fileName[MAX_PATH + 1]; TCHAR* commandLine = NULL; // command line DWORD commandLineLen = 0; // command line length DWORD cFileList = 10240; // string length of tcsFileList ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); // // Build the file list string. We ignore error here. If a file is not picked // up, we'll still pass it to the command. We'll let the user's executable // handle the error. // BuildFileListString(fileList, &tcsFileList); // // Initialize the command line. We can either do two loops to count how big // a string we need for the command line, or do one loops and just set a // max limit on how long the command line is allowed. We probably won't // have that many commands or arguments anyway. // commandLineLen += _tcslen(command->String()) + 3; // '"' + '"' + ' ' commandLineLen += _tcslen(tcsFileList) + 1; // ' ' for(tmp = command->Next(); tmp != command; tmp = tmp->Next()) { commandLineLen += _tcslen(tmp->String()) + 3; // '"' + '"' + ' ' } commandLine = new TCHAR[commandLineLen + _tcslen(tcsFileList) + 1]; commandLine[0] = TEXT('\0'); MakeCommandLine(command, command->Next(), commandLine); _tcscat(commandLine, tcsFileList); if(!CreateProcess(NULL, commandLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) { rv = GetLastError(); goto cleanup; } cleanup: if(tcsFileList != NULL) { delete []tcsFileList; } if(commandLine != NULL) { delete []commandLine; } return rv; } //***************************************************************** // // Synopsis: Process the [Run These Commands] extension section in an inf // file. // // History: 11/14/1999 Created by WeiruC. // // Return Value: Win32 error code. // //***************************************************************** DWORD ProcessExecExtensions() { DWORD rv = ERROR_SUCCESS; // return value BOOL success = TRUE; // value returned by setup functions INFCONTEXT context; // used by setup inf functions INFCONTEXT contextOutput; // Run These Commands Output section TCHAR* label = NULL; // label in inf file TCHAR* labelOutput = NULL; // label in inf file CStringList* command = NULL; // command CStringList* fileList = NULL; // file list from Scanstate if(InputInf == INVALID_HANDLE_VALUE) { return ERROR_SUCCESS; } // // Find the section in the inf file. If it doesn't exist, do nothing and // return ERROR_SUCCESS. // if(!SetupFindFirstLine(InputInf, EXECUTABLE_EXT_SECTION, NULL, &context)) { return ERROR_SUCCESS; } // // Process each line in the section: // Find matching file list from Scanstate // run the command // do { // // Parse the line. // rv = ParseSectionList(&context, &label, &command); FAIL_ON_ERROR(rv); if((command->String())[0] != TEXT('\0')) { // // Find matching output from Scanstate. // if(SetupFindFirstLine(InputInf, EXECUTABLE_EXTOUT_SECTION, label, &contextOutput)) { // // Parse the line. // rv = ParseSectionList(&contextOutput, &labelOutput, &fileList); FAIL_ON_ERROR(rv); } // // Create a child process to run the command. Ignore error and // continue to run the next command. // RunCommandInChildProcess(command, fileList); } // // Clean up and reinitialize. // if(label) { free(label); label = NULL; } if(labelOutput) { free(labelOutput); labelOutput = NULL; } if(command) { delete command; command = NULL; } if(fileList) { delete fileList; fileList = NULL; } } while(SetupFindNextLine(&context, &context)); cleanup: if(label) { free(label); } if(labelOutput) { free(labelOutput); labelOutput = NULL; } if(command) { delete command; } if(fileList) { delete fileList; fileList = NULL; } return rv; }