/*++ Copyright (c) 1995 Microsoft Corporation Module Name: registry.c Abstract: Routines for manupilating the configuration registry. Entry points: SaveHive SetEnvironmentVariableInRegistry Author: Ted Miller (tedm) 5-Apr-1995 Revision History: --*/ #include "setupp.h" #pragma hdrstop #ifdef _WIN64 #include #endif // // Names of frequently used keys, values. // PCWSTR ControlKeyName = L"SYSTEM\\CurrentControlSet\\Control"; PCWSTR SessionManagerKeyName = L"SYSTEM\\CurrentControlSet\\Control\\Session Manager"; PCWSTR EnvironmentKeyName = L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment"; PCWSTR WinntSoftwareKeyName = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"; PCWSTR MemoryManagementKeyName = L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management"; PCWSTR WindowsCurrentVersionKeyName = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion"; PCWSTR IEProductVersionKeyName = L"Software\\Microsoft\\Internet Explorer\\Registration"; PCWSTR szBootExecute = L"BootExecute"; PCWSTR szRegisteredProcessors = L"RegisteredProcessors"; PCWSTR szLicensedProcessors = L"LicensedProcessors"; PCWSTR szRegisteredOwner = L"RegisteredOwner"; PCWSTR szRegisteredOrganization = L"RegisteredOrganization"; PCWSTR szCurrentProductId = L"CurrentProductId"; // // Logging constants used only in this module. // PCWSTR szRegSaveKey = L"RegSaveKey"; // // Number of processors to enable in server case. // #define SERVER_PROCESSOR_LICENSE (2) // // Table telling us the info needed in order to save and // replace the system hives at the end of setup. // struct { // // Key and subkey that is at the root of the hive. // HKEY RootKey; PCWSTR Subkey; // // Name active hive has in the config directory. // PCWSTR Hive; // // Name to use for new hive file, that will be the hive // at next boot. // PCWSTR NewHive; // // Name to use for current hive file, that will be deleted // on next boot. // PCWSTR DeleteHive; } HiveTable[3] = { // // System hive. // { HKEY_LOCAL_MACHINE, L"SYSTEM" , L"SYSTEM" , L"SYS$$$$$.$$$", L"SYS$$$$$.DEL" }, // // Software hive // { HKEY_LOCAL_MACHINE, L"SOFTWARE", L"SOFTWARE", L"SOF$$$$$.$$$", L"SOF$$$$$.DEL" }, // // Default user hive // { HKEY_USERS , L".DEFAULT", L"DEFAULT" , L"DEF$$$$$.$$$", L"DEF$$$$$.DEL" } }; BOOL SaveHive( IN HKEY RootKey, IN PCWSTR Subkey, IN PCWSTR Filename, IN DWORD Format ) /*++ Routine Description: Save a hive into a disk file. Arguments: RootKey - supplies root key for hive to be saved, ie, HKEY_LOCAL_MACHINE or HKEY_USERS Subkey - supplies name of subkey for hive to be saved, such as SYSTEM, SOFTWARE, or .DEFAULT. Filename - supplies the name of the file to be created. If it exists it is overwritten. Return Value: Boolean value indicating outcome. --*/ { LONG rc; HKEY hkey; BOOL b; b = FALSE; // // Open the key. // rc = RegOpenKeyEx(RootKey,Subkey,0,KEY_READ,&hkey); if(rc != NO_ERROR) { SetuplogError( LogSevError, SETUPLOG_USE_MESSAGEID, MSG_LOG_SAVEHIVE_FAIL, Subkey, Filename, NULL, SETUPLOG_USE_MESSAGEID, MSG_LOG_X_RETURNED_WINERR, szRegOpenKeyEx, rc, NULL,NULL); goto err1; } // // Delete the file if it's there. // if(FileExists(Filename,NULL)) { SetFileAttributes(Filename,FILE_ATTRIBUTE_NORMAL); DeleteFile(Filename); } // // Enable backup privilege. Ignore any error. // pSetupEnablePrivilege(SE_BACKUP_NAME,TRUE); // // Do the save. // rc = RegSaveKeyEx(hkey,Filename,NULL,Format); if(rc != NO_ERROR) { SetuplogError( LogSevError, SETUPLOG_USE_MESSAGEID, MSG_LOG_SAVEHIVE_FAIL, Subkey, Filename, NULL, SETUPLOG_USE_MESSAGEID, MSG_LOG_X_RETURNED_WINERR, szRegSaveKey, rc, NULL,NULL); goto err2; } b = TRUE; err2: RegCloseKey(hkey); err1: return(b); } BOOL SetEnvironmentVariableInRegistry( IN PCWSTR Name, IN PCWSTR Value, IN BOOL SystemWide ) { HKEY hKey,hRootKey; PCWSTR Subkey; DWORD dwDisp; LONG rc; BOOL b; b = FALSE; // // Check if the caller wants to modify a system environment variable // or a user environment variable. Accordingly find out the right // place in the registry to look. // if(SystemWide) { hRootKey = HKEY_LOCAL_MACHINE; Subkey = EnvironmentKeyName; } else { hRootKey = HKEY_CURRENT_USER; Subkey = L"Environment"; } // // Open the environment variable key. // rc = RegCreateKeyEx(hRootKey,Subkey,0,NULL,REG_OPTION_NON_VOLATILE, KEY_WRITE,NULL,&hKey,&dwDisp); if(rc != NO_ERROR) { SetuplogError( LogSevWarning, SETUPLOG_USE_MESSAGEID, MSG_LOG_SETENV_FAIL, Name, NULL, SETUPLOG_USE_MESSAGEID, MSG_LOG_X_PARAM_RETURNED_WINERR, szRegOpenKeyEx, rc, Subkey, NULL,NULL); goto err0; } // // Write the value given. // rc = RegSetValueEx( hKey, Name, 0, REG_EXPAND_SZ, (PBYTE)Value, (lstrlen(Value)+1)*sizeof(WCHAR) ); if(rc != NO_ERROR) { SetuplogError( LogSevWarning, SETUPLOG_USE_MESSAGEID, MSG_LOG_SETENV_FAIL, Name, NULL, SETUPLOG_USE_MESSAGEID, MSG_LOG_X_PARAM_RETURNED_WINERR, szRegSetValueEx, rc, Subkey, NULL,NULL); goto err1; } // // Send a WM_WININICHANGE message so that progman picks up the new // variable // SendMessageTimeout( (HWND)-1, WM_WININICHANGE, 0L, (LPARAM)"Environment", SMTO_ABORTIFHUNG, 1000, NULL ); b = TRUE; err1: RegCloseKey(hKey); err0: return(b); } #ifdef _WIN64 typedef struct _SUBST_STRING { BOOL ExpandEnvironmentVars; PTSTR InputString; PTSTR ExclusionString; PTSTR OutputString; PTSTR SourceInputString; PTSTR SourceExclusionString; PTSTR SourceOutputString; } SUBST_STRING,*PSUBST_STRING; // // note that WOW64 does file system redirection of system32, but it does NOT do // redirection of program files, etc. So we must substitute in the 32 bit // environment variables in those cases where WOW64 does not do it for us // automatically // SUBST_STRING StringArray[] = { // // order of these 2 is important! // { FALSE, NULL, NULL, NULL, TEXT("%CommonProgramFiles%"), TEXT("%CommonProgramFiles(x86)%"), TEXT("%CommonProgramFiles(x86)%") }, { FALSE, NULL, NULL, NULL, TEXT("%ProgramFiles%"), TEXT("%ProgramFiles(x86)%"), TEXT("%ProgramFiles(x86)%") }, { TRUE, NULL, NULL, NULL, TEXT("%CommonProgramFiles%"), TEXT("%CommonProgramFiles(x86)%"), TEXT("%CommonProgramFiles(x86)%") }, { TRUE, NULL, NULL, NULL, TEXT("%ProgramFiles%"), TEXT("%ProgramFiles(x86)%"), TEXT("%ProgramFiles(x86)%") } } ; BOOL pDoWow64SubstitutionHelper( IN OUT PTSTR String ) /*++ Routine Description: This routine filters and outputs the input line. It looks for a string pattern that matches one of a known list of strings, and replaces the known string with a substitution string. Arguments: String - input string to be searched. We edit this string in-place if we find a match. Return Value: Boolean indicating outcome. --*/ { WCHAR ScratchBuffer[MAX_PATH]; DWORD i; PTSTR p,q; TCHAR c; for (i = 0; i< sizeof(StringArray)/sizeof(SUBST_STRING); i++) { if (!StrStrI(String,StringArray[i].ExclusionString) && (p = StrStrI(String,StringArray[i].InputString))) { // // if we found a hit, then find the end of the string // and concatenate that to our source string, which gives // the resultant string with substitutions. // q = p + wcslen(StringArray[i].InputString); c = *p; *p = TEXT('\0'); wcscpy(ScratchBuffer,String); *p = c; wcscat(ScratchBuffer,StringArray[i].OutputString); wcscat(ScratchBuffer,q); wcscpy(String,ScratchBuffer); // // recursively call in case there are more strings. // pDoWow64SubstitutionHelper(String); break; } } return(TRUE); } BOOL pDoWow64Substitution( IN PCWSTR InputString, OUT PWSTR OutputString ) { DWORD i; WCHAR Buffer[MAX_PATH]; BOOL RetVal; // // set up our global array of substitution strings // for (i = 0; i 0) && (Path[PlatformOffset-1] == L'\\') && !lstrcmpi(Path+PlatformOffset,PlatformName)) { Path[PlatformOffset-1] = 0; SoftwareKeyItems[0].Size -= (PlatformNameLength+1)*sizeof(WCHAR); SoftwareKeyItems[1].Size -= (PlatformNameLength+1)*sizeof(WCHAR); } // // Add "real" path to MRU list and update setupapi.dll/Win95 // SourcePath value. // if(!SetupAddToSourceList(SRCLIST_SYSTEM,Path)) { b = FALSE; } if(SetGroupOfValues(HKEY_LOCAL_MACHINE,REGSTR_PATH_SETUP REGSTR_KEY_SETUP,SoftwareKeyItems,2) != NO_ERROR) { b = FALSE; } } } return(b); } BOOL StoreNameOrgInRegistry( PWSTR NameOrgName, PWSTR NameOrgOrg ) { DWORD d; REGVALITEM SoftwareKeyItems[2]; MYASSERT(!Upgrade); SoftwareKeyItems[0].Name = szRegisteredOwner; SoftwareKeyItems[0].Data = NameOrgName; SoftwareKeyItems[0].Size = (lstrlen(NameOrgName)+1)*sizeof(WCHAR); SoftwareKeyItems[0].Type = REG_SZ; SoftwareKeyItems[1].Name = szRegisteredOrganization; SoftwareKeyItems[1].Data = NameOrgOrg; SoftwareKeyItems[1].Size = (lstrlen(NameOrgOrg)+1)*sizeof(WCHAR); SoftwareKeyItems[1].Type = REG_SZ; d = SetGroupOfValues(HKEY_LOCAL_MACHINE,WinntSoftwareKeyName,SoftwareKeyItems,2); return(d == NO_ERROR); } BOOL SetUpEvaluationSKUStuff( VOID ) { FILETIME FileTime; DWORD EvalValues[3]; DWORD d; REGVALITEM Value; HKEY hkey; ULONGLONG SKUData; DWORD DataType; DWORD DataSize; time_t RawLinkTime; SYSTEMTIME SystemTime; struct tm *LinkTime; int delta; PIMAGE_NT_HEADERS NtHeaders; // // Fetch the evaulation time in minutes from the registry. // An evaluation time of 0 means indefinite. // This value was passed in from text mode in a special way // (ie, not via the text file that contains our params, // since that's not secure enough). // EvalValues[1] = 0; d = RegOpenKeyEx(HKEY_LOCAL_MACHINE,L"System\\Setup",0,KEY_READ,&hkey); if(d == NO_ERROR) { DataSize = sizeof(ULONGLONG); d = RegQueryValueEx(hkey,L"SystemPrefix",NULL,&DataType,(PBYTE)&SKUData,&DataSize); if(d == NO_ERROR) { // // Do not change this line without changing SpSaveSKUStuff() in // text setup (spconfig.c). // EvalValues[1] = (DWORD)(SKUData >> 13); } RegCloseKey(hkey); } // // Verify that the clock seems right in the eval unit case. // This helps protect against prople discovering that their // clock is wrong later and changing it, which expires their // eval unit. // if(EvalValues[1]) { // // Get the link time of our dll and convert to // a form where we have the year separated out. // try { if( NtHeaders = RtlImageNtHeader(MyModuleHandle) ) { RawLinkTime = NtHeaders->FileHeader.TimeDateStamp; } else { RawLinkTime = 0; } RawLinkTime = RtlImageNtHeader(MyModuleHandle)->FileHeader.TimeDateStamp; } except(EXCEPTION_EXECUTE_HANDLER) { RawLinkTime = 0; } if(RawLinkTime && (LinkTime = gmtime(&RawLinkTime))) { GetLocalTime(&SystemTime); delta = (SystemTime.wYear - 1900) - LinkTime->tm_year; // // If the year of the current time is more than one year less then // the year the dll was linked, or more than three years more, // assume the user's clock is out of whack. // if((delta < -1) || (delta > 3)) { extern PCWSTR DateTimeCpl; MessageBoxFromMessage( MainWindowHandle, MSG_EVAL_UNIT_CLOCK_SEEMS_WRONG, NULL, IDS_WINNT_SETUP, MB_OK | MB_ICONWARNING ); InvokeControlPanelApplet(DateTimeCpl,L"",0,L""); } } } // // Get current date/time and put into array in format // expected by the system code that reads it. // GetSystemTimeAsFileTime(&FileTime); EvalValues[0] = FileTime.dwLowDateTime; EvalValues[2] = FileTime.dwHighDateTime; // // Write value into registry. // Value.Name = L"PriorityQuantumMatrix"; Value.Data = EvalValues; Value.Size = sizeof(EvalValues); Value.Type = REG_BINARY; d = SetGroupOfValues( HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Executive", &Value, 1 ); return(d == NO_ERROR); } BOOL ReadAndParseProcessorLicenseInfo( PDWORD LicensedProcessors, PLARGE_INTEGER pSKUData ) { DWORD d; REGVALITEM Value; HKEY hkey; LARGE_INTEGER SKUData; DWORD DataType; DWORD DataSize; DWORD NumberOfProcessors; // // Fetch the SKU Data from the registry // d = RegOpenKeyEx(HKEY_LOCAL_MACHINE,L"System\\Setup",0,KEY_READ,&hkey); if(d == NO_ERROR) { DataSize = sizeof(ULONGLONG); d = RegQueryValueEx(hkey,L"SystemPrefix",NULL,&DataType,(PBYTE)&SKUData,&DataSize); if(d == NO_ERROR) { // // The SKU Data contains several pieces of information. // // The registered processor related pieces are // // Bits 5 - 9 : The maximum number of processors that the system is licensed // to use. The value stored is actually ~(MaxProcessors-1) // // // Compute Licensed Processors // NumberOfProcessors = SKUData.LowPart; NumberOfProcessors = NumberOfProcessors >> 5; NumberOfProcessors = ~NumberOfProcessors; NumberOfProcessors = NumberOfProcessors & 0x0000001f; NumberOfProcessors++; *LicensedProcessors = NumberOfProcessors; } RegCloseKey(hkey); } *pSKUData = SKUData; return(d == NO_ERROR); } BOOL IsStandardServerSKU( PBOOL pIsServer ) { BOOL fReturnValue = (BOOL) FALSE; OSVERSIONINFOEX VersionInfo; BOOL IsServer = FALSE; // // get the current SKU. // VersionInfo.dwOSVersionInfoSize = sizeof(VersionInfo); if (GetVersionEx((OSVERSIONINFO *)&VersionInfo)) { fReturnValue = TRUE; // // is it some sort of server SKU? // if (VersionInfo.wProductType != VER_NT_WORKSTATION) { // // standard server or a server variant? // if ((VersionInfo.wSuiteMask & (VER_SUITE_ENTERPRISE | VER_SUITE_DATACENTER)) == 0) { // // it's standard server // IsServer = TRUE; } } *pIsServer = IsServer; } return(fReturnValue); } BOOL SetEnabledProcessorCount( VOID ) { DWORD d; REGVALITEM RegistryItem; HKEY hkey; DWORD Size; DWORD Type; DWORD OriginalLicensedProcessors; DWORD LicensedProcessors; LARGE_INTEGER SKUData; BOOL IsServer = FALSE; if ( !ReadAndParseProcessorLicenseInfo(&OriginalLicensedProcessors,&SKUData) ) { return FALSE; } LicensedProcessors = OriginalLicensedProcessors; if(Upgrade) { // // During an upgrade, do not let the user go backwards. // (except for standard server SKU) // if (!IsStandardServerSKU(&IsServer) || IsServer == FALSE) { if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,SessionManagerKeyName,0,KEY_QUERY_VALUE,&hkey) == NO_ERROR) { Size = sizeof(d); if((RegQueryValueEx(hkey,szLicensedProcessors,NULL,&Type,(LPBYTE)&d,&Size) == NO_ERROR) && (Type == REG_DWORD) && (d >= LicensedProcessors)) { LicensedProcessors = d; } RegCloseKey(hkey); } } } d = LicensedProcessors; RegistryItem.Data = &d; RegistryItem.Size = sizeof(DWORD); RegistryItem.Type = REG_DWORD; RegistryItem.Name = szRegisteredProcessors; d = SetGroupOfValues(HKEY_LOCAL_MACHINE,SessionManagerKeyName,&RegistryItem,1); if ( d == NO_ERROR ) { RegistryItem.Data = &LicensedProcessors; RegistryItem.Size = sizeof(DWORD); RegistryItem.Type = REG_DWORD; RegistryItem.Name = szLicensedProcessors; d = SetGroupOfValues(HKEY_LOCAL_MACHINE,SessionManagerKeyName,&RegistryItem,1); } if ( d == NO_ERROR && LicensedProcessors >= OriginalLicensedProcessors) { // // need to update SKUData to reflect the fact the we are running with // a licensed processor count that is different from what is programmed // in the hives. // // // Convert Licensed Processors to Registry Format // LicensedProcessors--; LicensedProcessors = ~LicensedProcessors; LicensedProcessors = LicensedProcessors << 5; LicensedProcessors &= 0x000003e0; // // Store NumberOfProcessors into the registry // SKUData.LowPart &= ~0x000003e0; SKUData.LowPart |= LicensedProcessors; RegistryItem.Data = &SKUData; RegistryItem.Size = sizeof(SKUData); RegistryItem.Type = REG_BINARY; RegistryItem.Name = L"SystemPrefix"; d = SetGroupOfValues(HKEY_LOCAL_MACHINE,L"SYSTEM\\Setup",&RegistryItem,1); } return(d == NO_ERROR); } #ifdef PRERELEASE UINT ValidateGroupOfValues( IN HKEY RootKey, IN PCWSTR SubkeyName, IN PREGVALITEM ValueList, IN UINT ValueCount ) { UINT i; LONG rc; HKEY hkey; UINT RememberedRc; // // Open the key first. // rc = RegOpenKeyEx( RootKey, SubkeyName, 0, KEY_READ, &hkey ); if(rc != NO_ERROR) { SetupDebugPrint2(L"RegOpenKeyEx failed on key:%s errorcode: %d\n", SubkeyName, rc); return(FALSE); } RememberedRc = NO_ERROR; // // Query all values in the given list. // for(i=0; i Reset the source path to the CDROM. // // // // Pickup the answer file. // GetSystemDirectory(AnswerFile,MAX_PATH); pSetupConcatenatePaths(AnswerFile,WINNT_GUI_FILE,MAX_PATH,NULL); // // Assume we need to fixup the sourcepath. // FixupSourcePath = TRUE; // // Go retrieve this key from the unattend file. // if( GetPrivateProfileString( pwUnattended, TEXT("ResetSourcePath"), pwNull, Answer, AnswerBufLen, AnswerFile ) ) { // // We got an answer. See what he wants us to do. // if( !wcscmp( L"*", Answer ) ) { // // He gave us a "*", so don't change anything. // FixupSourcePath = FALSE; } else { // // We'll be using the contents of Answer for the // new source path. // FixupSourcePath = TRUE; } } else { // // Reset the source path to the first CDROM. // Assume conservatively that we don't have a CDROM, and // in that case, we won't be resetting the source path. // FixupSourcePath = FALSE; // // Don't change the sourcepath if the directory specified in // the key exists. // rc = (DWORD)RegOpenKeyEx( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Setup", 0, KEY_SET_VALUE | KEY_QUERY_VALUE, &hKeySetup ); if( rc == NO_ERROR ) { TCHAR CurrentSourcePath[MAX_PATH] = L""; DWORD Size = sizeof(CurrentSourcePath); DWORD dwAttr; UINT OldMode; // // Avoid system popups. // OldMode = SetErrorMode(SEM_FAILCRITICALERRORS); // // Read the current value. // rc = RegQueryValueEx( hKeySetup, TEXT("SourcePath"), 0, 0, (LPBYTE)CurrentSourcePath, &Size); // Set up the ARCH_DIR based on the current binary architecture // #ifdef _X86_ #define ARCH_DIR L"i386" #else #define ARCH_DIR L"ia64" #endif // // If the current directory (with arch) exists and it is on a fixed disk and it // is not a root directory then don't change it, otherwise change it. // if ( !((rc == NO_ERROR) && (CurrentSourcePath[0]) && (CurrentSourcePath[1] == L':') && (MyGetDriveType(CurrentSourcePath[0]) == DRIVE_FIXED) && (pSetupConcatenatePaths(CurrentSourcePath, ARCH_DIR, MAX_PATH, NULL)) && ((dwAttr = GetFileAttributes(CurrentSourcePath)) != 0xFFFFFFFF) && (dwAttr & FILE_ATTRIBUTE_DIRECTORY) ) ) { Type = DRIVE_CDROM; wcscpy( Answer, L"A:\\" ); for( c = L'A'; c <= L'Z'; c++ ) { if( MyGetDriveType(c) == DRIVE_CDROM ) { // // Got it. Remember the drive letter for // the CDROM and break. // Answer[0] = c; FixupSourcePath = TRUE; break; } } } SetErrorMode(OldMode); RegCloseKey( hKeySetup ); } } if( FixupSourcePath ) { // // If we get here, then Answer contains the new source path. // rc = (DWORD)RegOpenKeyEx( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Setup", 0, KEY_SET_VALUE | KEY_QUERY_VALUE, &hKeySetup ); if( rc == NO_ERROR ) { // // Set the value. Ignore the return. // RegSetValueEx( hKeySetup, TEXT("SourcePath" ), 0, REG_SZ, (LPBYTE)Answer, (lstrlen(Answer)+1) * sizeof(WCHAR) ); RegSetValueEx( hKeySetup, TEXT("ServicePackSourcePath" ), 0, REG_SZ, (LPBYTE)Answer, (lstrlen(Answer)+1) * sizeof(WCHAR) ); // // Now we need to determine if the drive we're setting him to // is a CDROM. // if( (Answer[1] == L':') && (MyGetDriveType(Answer[0]) == DRIVE_CDROM) ) { rc = 1; RegSetValueEx( hKeySetup, TEXT("CDInstall" ), 0, REG_DWORD, (CONST BYTE *)&rc, sizeof(DWORD)); } RegCloseKey( hKeySetup ); } } } // // See if we need to disable the Admin account. Only do this if // the user asked us to *and* the machine has been joined to a // domain. // GetSystemDirectory(AnswerFile,MAX_PATH); pSetupConcatenatePaths(AnswerFile,WINNT_GUI_FILE,MAX_PATH,NULL); if( GetPrivateProfileString( pwData, TEXT("DisableAdminAccountOnDomainJoin"), pwNull, Answer, AnswerBufLen, AnswerFile ) ) { if( wcscmp( L"", Answer ) ) { PWSTR SpecifiedDomain = NULL; NETSETUP_JOIN_STATUS JoinStatus; // // See if we're in a domain. // rc = NetGetJoinInformation( NULL, &SpecifiedDomain, &JoinStatus ); if( SpecifiedDomain ) { NetApiBufferFree( SpecifiedDomain ); } if( (rc == NO_ERROR) && (JoinStatus == NetSetupDomainName) ) { // // Yes. Go disable the Admin account. // DisableLocalAdminAccount(); } } } // // Remove sprestrt.exe from the session manager execute list. // rc = pSetupQueryMultiSzValueToArray( HKEY_LOCAL_MACHINE, SessionManagerKeyName, szBootExecute, &MultiSz, &Count, TRUE ); if(rc == NO_ERROR) { Found = FALSE; for(i=0; i, default to 0x32 // SFCShowProgress = <0|1>, default to 0 // SFCDllCacheDir = , default to "%systemroot%\system32\dllcache" // // // SFCQuota // if( GetPrivateProfileString( TEXT("SystemFileProtection"), TEXT("SFCQuota"), pwNull, Answer, AnswerBufLen, AnswerFile ) ) { if( lstrcmp( pwNull, Answer ) ) { // // We got an answer. If it's valid, then set it. // d = wcstoul(Answer,NULL,16); RegSetValueEx( hKey, TEXT("SFCQuota"), 0, REG_DWORD, (CONST BYTE *)&d, sizeof(DWORD) ); } } // // SFCShowProgress // if( GetPrivateProfileString( TEXT("SystemFileProtection"), TEXT("SFCShowProgress"), pwNull, Answer, AnswerBufLen, AnswerFile ) ) { if( lstrcmp( pwNull, Answer ) ) { // // We got an answer. If it's valid, then set it. // d = wcstoul(Answer,NULL,10); if( d <= 1 ) { RegSetValueEx( hKey, TEXT("SFCShowProgress"), 0, REG_DWORD, (CONST BYTE *)&d, sizeof(DWORD) ); } } } // // SFCDllCacheDir // if( GetPrivateProfileString( TEXT("SystemFileProtection"), TEXT("SFCDllCacheDir"), pwNull, Answer, AnswerBufLen, AnswerFile ) ) { if( lstrcmp( pwNull, Answer ) ) { // // We got an answer. If it's valid, then set it. // RegSetValueEx( hKey, TEXT("SFCDllCacheDir"), 0, REG_EXPAND_SZ, (CONST BYTE *)Answer, (lstrlen(Answer)+1)*sizeof(WCHAR) ); } } RegCloseKey( hKey ); } DWORD QueryValueInHKLM ( IN PWCH KeyName OPTIONAL, IN PWCH ValueName, OUT PDWORD ValueType, OUT PVOID *ValueData, OUT PDWORD ValueDataLength ) /*++ Routine Description: Queries the data for a value in HKLM. Arguments: KeyName - pointer to name of the key containing the value. ValueName - pointer to name of the value. ValueType - returns the type of the value data. ValueData - returns a pointer to value data. This buffer must be freed by the caller using MyFree. ValueDataLength - length in bytes of ValueData. Return Value: DWORD - Win32 status of the operation. --*/ { HKEY hkey; DWORD disposition; DWORD error; // // Open the parent key. // if ( (KeyName == NULL) || (wcslen(KeyName) == 0) ) { hkey = HKEY_LOCAL_MACHINE; } else { error = RegCreateKeyEx( HKEY_LOCAL_MACHINE, KeyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ, NULL, &hkey, &disposition ); if ( error != ERROR_SUCCESS ) { return error; } } // // Query the value to get the length of its data. // *ValueDataLength = 0; *ValueData = NULL; error = RegQueryValueEx( hkey, ValueName, NULL, ValueType, NULL, ValueDataLength ); // // Allocate a buffer to hold the value data. // if ( error == NO_ERROR ) { *ValueData = MyMalloc( *ValueDataLength ); if ( *ValueData == NULL ) { error = ERROR_NOT_ENOUGH_MEMORY; } } // // Query the value again, this time retrieving the data. // if ( error == NO_ERROR ) { error = RegQueryValueEx( hkey, ValueName, NULL, ValueType, *ValueData, ValueDataLength ); if ( error != NO_ERROR ) { MyFree( *ValueData ); } } // // Close the parent key. // if ( hkey != HKEY_CURRENT_USER ) { RegCloseKey( hkey ); } return error; } DWORD MyCopyKeyRecursive( IN HKEY DestRootKey, IN HKEY SourceRootKey ) /*++ Routine Description: This function will duplicate one key (and all its subkeys) to another key. Arguments: DestRootKey - Root of the destination registry key. SourceRootKey - Root of the source registry key. Return Value: ReturnCode --*/ { PWCH SubKeyName; DWORD SubKeyNameLength; PVOID DataBuffer; DWORD DataLength; DWORD maxValueDataLength; DWORD maxValueNameLength; DWORD maxKeyNameLength; ULONG Index; DWORD rc = NO_ERROR; FILETIME ftLastWriteTime; HKEY hSubDestKey, hSubSourceKey; DWORD dwDisp; DWORD Type; // // Query information about the key that we'll be inspecting. // rc = RegQueryInfoKey( SourceRootKey, NULL, NULL, NULL, NULL, &maxKeyNameLength, NULL, NULL, &maxValueNameLength, &maxValueDataLength, NULL, NULL ); if( rc != NO_ERROR ) { SetupDebugPrint1( L"Setup: MyCopyKeyRecursive - RegQueryInfoKey failed (%d)", rc ); return rc; } // // Enumerate all keys in the source and recursively create // them in the destination. // for( Index = 0; ; Index++ ) { // // Allocate a buffer large enough to hold the longest // key name. // SubKeyName = NULL; SubKeyName = MyMalloc( (maxKeyNameLength+2) * sizeof(WCHAR) ); SubKeyNameLength = (maxKeyNameLength+2); if( !SubKeyName ) { return ERROR_NOT_ENOUGH_MEMORY; } rc = RegEnumKeyEx( SourceRootKey, Index, SubKeyName, &SubKeyNameLength, NULL, NULL, NULL, &ftLastWriteTime ); // // Did we error? // if( rc != ERROR_SUCCESS ) { // // Are we done? // if( rc == ERROR_NO_MORE_ITEMS ) { rc = ERROR_SUCCESS; } else { SetupDebugPrint1( L"Setup: MyCopyKeyRecursive - RegEnumKeyEx failed (%d)", rc ); } break; } hSubDestKey = NULL; hSubSourceKey = NULL; // // Create the key in the destination, and call // ourselves again. // rc = RegCreateKeyEx( DestRootKey, SubKeyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hSubDestKey, &dwDisp ); if( rc == ERROR_SUCCESS ) { rc = RegOpenKeyEx( SourceRootKey, SubKeyName, 0, KEY_READ, &hSubSourceKey ); } else { SetupDebugPrint2( L"Setup: MyCopyKeyRecursive - RegCreateKeyEx failed to create %ws (%d)", SubKeyName, rc ); } if( rc == ERROR_SUCCESS ) { rc = MyCopyKeyRecursive( hSubDestKey, hSubSourceKey ); } else { SetupDebugPrint2( L"Setup: MyCopyKeyRecursive - RegOpenKeyEx failed to open %ws (%d)", SubKeyName, rc ); } // // Clean up and do the loop again. // if( hSubDestKey ) { RegCloseKey( hSubDestKey ); hSubDestKey = NULL; } if( hSubSourceKey ) { RegCloseKey( hSubSourceKey ); hSubSourceKey = NULL; } if( SubKeyName ) { MyFree( SubKeyName ); SubKeyName = NULL; } } // // Enumerate all the value keys in the source and copy them all // into the destination key. // for( Index = 0; ; Index++ ) { // // Allocate a buffers large enough to hold the longest // name and data // SubKeyName = NULL; SubKeyName = MyMalloc( (maxValueNameLength+2) * sizeof(WCHAR) ); SubKeyNameLength = (maxValueNameLength+2); if( !SubKeyName ) { return ERROR_NOT_ENOUGH_MEMORY; } DataBuffer = NULL; DataBuffer = MyMalloc( maxValueDataLength+2 ); DataLength = maxValueDataLength+2; if( !DataBuffer ) { return ERROR_NOT_ENOUGH_MEMORY; } rc = RegEnumValue( SourceRootKey, Index, SubKeyName, &SubKeyNameLength, NULL, &Type, DataBuffer, &DataLength ); // // Did we error? // if( rc != ERROR_SUCCESS ) { // // Are we done? // if( rc == ERROR_NO_MORE_ITEMS ) { rc = ERROR_SUCCESS; } else { SetupDebugPrint1( L"Setup: MyCopyKeyRecursive - RegEnumValue failed (%d)", rc ); } break; } hSubDestKey = NULL; hSubSourceKey = NULL; // // Create the value key in the destination. // rc = RegSetValueEx( DestRootKey, SubKeyName, 0, Type, DataBuffer, DataLength ); if( rc != ERROR_SUCCESS ) { SetupDebugPrint2( L"Setup: MyCopyKeyRecursive - RegSetValueEx failed to set %ws (%d)", SubKeyName, rc ); } // // Clean up and do the loop again. // if( SubKeyName ) { MyFree( SubKeyName ); SubKeyName = NULL; } if( DataBuffer ) { MyFree( DataBuffer ); DataBuffer = NULL; } } return rc; } DWORD MyCopyKey ( IN HKEY DestRootKey, IN PCWSTR DestKeyName, IN HKEY SourceRootKey, IN PCWSTR SourceKeyName ) /*++ Routine Description: This function will duplicate one key (and all its subkeys) to another key. Note that we're not just going to lay the new key ontop of the destination. We're going to actually replace the destination with the source. Arguments: DestRootKey - Root of the destination registry key. DestKeyName - Name of teh source registry key. SourceRootKey - Root of the source registry key. SourceKeyName - Name of teh source registry key. Return Value: ReturnCode --*/ { UINT i; HKEY hDestKey = NULL, hSourceKey = NULL; DWORD ActionTaken; UINT RememberedRc; DWORD rc = NO_ERROR; // // Don't accept any NULL parameters. // if( (SourceRootKey == NULL ) || (SourceKeyName == NULL ) || (DestRootKey == NULL ) || (DestKeyName == NULL ) ) { return ERROR_INVALID_PARAMETER; } // // Open our source key. // rc = RegOpenKeyEx( SourceRootKey, SourceKeyName, 0, KEY_ENUMERATE_SUB_KEYS | KEY_READ, &hSourceKey ); if( rc != NO_ERROR ) { SetupDebugPrint2( L"Setup: MyCopyKey - Failed to open %ws (%d)", SourceKeyName, rc ); return rc; } // // Remove the destination key. // if( rc == NO_ERROR ) { pSetupRegistryDelnode( DestRootKey, DestKeyName ); } // // Now copy over the source key into the destination key. // // // Open/create the key first. // if( rc == NO_ERROR ) { rc = RegCreateKeyEx( DestRootKey, DestKeyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hDestKey, &ActionTaken ); if( rc != NO_ERROR ) { SetupDebugPrint2( L"Setup: MyCopyKey - Failed to create %ws (%d)", DestKeyName, rc ); } } // // We've got handles to both keys, now we're ready to call // our worker. // if( rc == NO_ERROR ) { rc = MyCopyKeyRecursive( hDestKey, hSourceKey ); if( rc != NO_ERROR ) { SetupDebugPrint1( L"Setup: MyCopyKey - MyCopyKeyRecursive failed (%d)", rc ); } } // // Clean up and exit. // if( hSourceKey ) { RegCloseKey( hSourceKey ); } if( hDestKey ) { RegCloseKey( hDestKey ); } return rc; } DWORD FixupUserHives( VOID ) /*++ Routine Description: This function will take some of the changes we've made to the default hive and copy them into the various user hives. Arguments: NONE Return Value: ReturnCode --*/ { DWORD rc = ERROR_SUCCESS; WCHAR ProfilesDir[MAX_PATH*2]; WCHAR HiveName[MAX_PATH*2]; WCHAR ValueBuffer[MAX_PATH*2]; DWORD dwSize; HANDLE FindHandle; WIN32_FIND_DATA FileData; DWORD Type, DataSize; HKEY TmpKey1, TmpKey2; pSetupEnablePrivilege(SE_RESTORE_NAME,TRUE); // // Take care of every profile we find. // dwSize = (MAX_PATH * 2); if( GetProfilesDirectory( ProfilesDir, &dwSize ) ) { pSetupConcatenatePaths( ProfilesDir, L"\\*", (MAX_PATH*2), NULL ); FindHandle = FindFirstFile( ProfilesDir, &FileData ); if( FindHandle != INVALID_HANDLE_VALUE ) { do { // // We got something, but remember that we only want directories. // if( (FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (wcscmp(FileData.cFileName,L".")) && (wcscmp(FileData.cFileName,L"..")) ) { // // He's a directory and he's not parent or current. // Generate a path to his hive. // dwSize = (MAX_PATH * 2); GetProfilesDirectory( HiveName, &dwSize ); pSetupConcatenatePaths( HiveName, FileData.cFileName, (MAX_PATH*2), NULL ); pSetupConcatenatePaths( HiveName, L"\\NTUSER.DAT", (MAX_PATH*2), NULL ); rc = RegLoadKey( HKEY_LOCAL_MACHINE, L"MiniSetupTemp", HiveName ); if( rc == ERROR_SUCCESS ) { // // Take care of the 'International' key // rc = MyCopyKey( HKEY_LOCAL_MACHINE, L"MiniSetupTemp\\Control Panel\\International", HKEY_CURRENT_USER, L"Control Panel\\International" ); if( rc != ERROR_SUCCESS ) { SetupDebugPrint2( L"Setup: FixupUserHive - Failed to update Control Panel\\International in %ws (%d)", HiveName, rc ); } // // Take care of the 'Keyboard Layout' key // rc = MyCopyKey( HKEY_LOCAL_MACHINE, L"MiniSetupTemp\\Keyboard Layout", HKEY_CURRENT_USER, L"Keyboard Layout" ); if( rc != ERROR_SUCCESS ) { SetupDebugPrint2( L"Setup: FixupUserHive - Failed to update Keyboard Layout in %ws (%d)", HiveName, rc ); } // // Take care of the 'Input Method' key // rc = MyCopyKey( HKEY_LOCAL_MACHINE, L"MiniSetupTemp\\Control Panel\\Input Method", HKEY_CURRENT_USER, L"Control Panel\\Input Method" ); if( rc != ERROR_SUCCESS ) { SetupDebugPrint2( L"Setup: FixupUserHive - Failed to update Input Method in %ws (%d)", HiveName, rc ); } // // If the user has modified the internationalization settings // in intl.cpl, then there's likely a 'Run' key. We need to migrate that // too. We need to be careful here though. The established users may already // have value keys set under here. We only need to set *our* single value // key under here. That value is called 'internat.exe'. If it's there, we // need to prop it out to the hives we're modifying. // rc = RegOpenKeyEx( HKEY_CURRENT_USER, REGSTR_PATH_RUN, 0, KEY_READ, &TmpKey1 ); if( rc != ERROR_SUCCESS ) { SetupDebugPrint1( L"Setup: FixupUserHive - Failed to open Run key (%d)", rc ); } else { DataSize = sizeof(ValueBuffer); rc = RegQueryValueEx( TmpKey1, L"internat.exe", NULL, &Type, (PBYTE)ValueBuffer, &DataSize ); RegCloseKey( TmpKey1 ); if( rc == ERROR_SUCCESS ) { // // It's there. Prop it into the existing hives too. // We can't just use RegSetValueEx though because that API // may tell us we succeeded, when in fact if the key doesn't // exist, we won't set it. To fix that, first create the // key. // rc = RegCreateKeyEx ( HKEY_LOCAL_MACHINE, TEXT("MiniSetupTemp\\Software\\Microsoft\\Windows\\CurrentVersion\\Run"), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &TmpKey1, &DataSize); if( rc == ERROR_SUCCESS ) { wcscpy( ValueBuffer, L"internat.exe" ); rc = RegSetValueEx( TmpKey1, L"Internat.exe", 0, REG_SZ, (LPBYTE)ValueBuffer, (lstrlen(ValueBuffer)+1)*sizeof(WCHAR) ); RegCloseKey( TmpKey1 ); if( rc != ERROR_SUCCESS ) { SetupDebugPrint2( L"Setup: FixupUserHive - Failed to set internat.exe key in hive %ws (%d)", HiveName, rc ); } } else { SetupDebugPrint1( L"Setup: FixupUserHive - Failed to create MiniSetupTemp\\Software\\Microsoft\\Windows\\CurrentVersion\\Run key (%d)", rc ); } } } rc = RegUnLoadKey( HKEY_LOCAL_MACHINE, L"MiniSetupTemp" ); if( rc != ERROR_SUCCESS ) { SetupDebugPrint2( L"Setup: FixupUserHive - Failed to unload %ws (%d)", HiveName, rc ); } } else { SetupDebugPrint2( L"Setup: FixupUserHive - Failed to load %ws (%d)", HiveName, rc ); } } } while( FindNextFile( FindHandle, &FileData ) ); } } else { SetupDebugPrint( L"Setup: FixupUserHive - Failed to get Profiles path." ); } return rc; } void LogPidValues() { LONG rc; HKEY hkey = NULL; WCHAR RegProductId[MAX_PRODUCT_ID+1]; BYTE RegDigitalProductId[DIGITALPIDMAXLEN]; DWORD Size; DWORD Type; #ifdef PRERELEASE ValidateProductIDInReg(); #endif rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,WinntSoftwareKeyName,0,KEY_READ,&hkey); if (rc == ERROR_SUCCESS) { *RegProductId = L'\0'; Size = sizeof(RegProductId); rc = RegQueryValueEx(hkey,L"ProductId",NULL,&Type,(PBYTE)RegProductId,&Size); if (rc == ERROR_SUCCESS) { if (*RegProductId == L'\0') { SetupDebugPrint(L"LogPidValues: ProductId20FromProductId30 is empty\n"); } else { SetupDebugPrint(L"LogPidValues: ProductId20FromProductId30 is NOT empty\n"); } } else { SetupDebugPrint1(L"LogPidValues: RegQueryValueEx on ProductId failed. Error code:%d\n",rc); } *RegDigitalProductId = 0; Size = sizeof(RegDigitalProductId); rc = RegQueryValueEx(hkey,L"DigitalProductId",NULL,&Type,(PBYTE)RegDigitalProductId,&Size); if (rc == ERROR_SUCCESS) { if (*RegDigitalProductId == 0) { SetupDebugPrint(L"LogPidValues: DigitalProductId is empty\n"); } else { SetupDebugPrint(L"LogPidValues: DigitalProductId is NOT empty\n"); } } else { SetupDebugPrint1(L"LogPidValues: RegQueryValueEx on DigitalProductId failed. Error code:%d\n",rc); } RegCloseKey(hkey); } else { SetupDebugPrint1(L"LogPidValues: RegOpenKeyEx on %1 failed\n",WindowsCurrentVersionKeyName); } }