From 5117a3b4a8de29b00e27fefc8de0502cf6c4256a Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Wed, 13 Jul 2022 18:31:11 +0100 Subject: [PATCH] [wue] fix MSA bypass not being applied unless SB/TPM or RAM/Disk bypass is also selected * In a manner that defies logic, Microsoft designed Windows setup to parse Autounattend.xml for windowsPE tasks in the PE environment, but only carry out the copying of that file to %WINDIR%\Panther for subsequent processing with the other passes *IF* there exist an actual windowsPE section. * In short, when using the Autounattend.xml method, Microsoft have made all passes there dependent on the existence of a windowsPE pass, regardless of whether that pass has any use or not. * Working around this would be fine and all (just add an empty windowsPE pass so that the later passes get executed) if the absence of a windowsPE pass didn't also determine whether the user will be presented with the default Windows setup screens that include the "Repair your computer" option or a completely different set of screens (c.f. #1971). * This means that, to keep users happy, we need to add yet another method to carry out tasks that should have remained the realm of boot.wim's Autounattend.xml, and instead create a \sources\$OEM$\$$\Panther\unattend.xml when there are no windowsPE tasks (on account that setup copies anything found under \sources\$OEM$\$$\ to %WINDIR%\). Only through this can we have the specialize and oobeSystem tasks actually carried out (for bypassing MSA requirements of skipping the data collection screens) while keeping the original Windows Setup look and feel. * Closes #1981 --- src/format.c | 75 +++++++++++++++++++++++++++++++++++++++------------- src/rufus.c | 2 +- src/rufus.h | 13 ++++----- src/rufus.rc | 10 +++---- 4 files changed, 70 insertions(+), 30 deletions(-) diff --git a/src/format.c b/src/format.c index d996b2d0..3268c49f 100644 --- a/src/format.c +++ b/src/format.c @@ -1498,8 +1498,9 @@ static BOOL SetupWinToGo(DWORD DriveIndex, const char* drive_name, BOOL use_esp) /* * Add unattend.xml to 'sources\boot.wim' (install) or 'Windows\Panther\' (Windows To Go) + * NB: Work with a copy of unattend_xml_selection as a paremeter since we will modify it. */ -BOOL ApplyWindowsCustomization(char drive_letter, BOOL windows_to_go) +BOOL ApplyWindowsCustomization(char drive_letter, int unattend_selection) { BOOL r = FALSE, is_hive_mounted = FALSE; int i; @@ -1515,7 +1516,7 @@ BOOL ApplyWindowsCustomization(char drive_letter, BOOL windows_to_go) assert(unattend_xml_path != NULL); uprintf("Applying Windows customization:"); - if (windows_to_go) { + if (unattend_selection & UNATTEND_WINDOWS_TO_GO) { static_sprintf(path, "%c:\\Windows\\Panther", drive_letter); if (!CreateDirectoryA(path, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) { uprintf("Could not create '%s' : %s", path, WindowsErrorString()); @@ -1529,7 +1530,7 @@ BOOL ApplyWindowsCustomization(char drive_letter, BOOL windows_to_go) uprintf("Added '%s'", path); } else { boot_wim_path[0] = drive_letter; - if (unattend_xml_selection & UNATTEND_WINPE_SETUP_MASK) { + if (unattend_selection & UNATTEND_WINPE_SETUP_MASK) { // Create a backup of sources\appraiserres.dll and then create an empty file to // allow in-place upgrades without TPM/SB. Note that we need to create an empty, // appraiserres.dll otherwise setup.exe extracts its own. @@ -1544,12 +1545,16 @@ BOOL ApplyWindowsCustomization(char drive_letter, BOOL windows_to_go) } UpdateProgressWithInfoForce(OP_PATCH, MSG_325, 0, PATCH_PROGRESS_TOTAL); - uprintf("Mounting '%s'...", boot_wim_path); - mount_path = WimMountImage(boot_wim_path, wim_index); - if (mount_path == NULL) - goto out; + // We only need to mount boot.wim if we have windowsPE data to deal with. If + // not, we can just copy our unattend.xml in \sources\$OEM$\$$\Panther\. + if (unattend_selection & UNATTEND_WINPE_SETUP_MASK) { + uprintf("Mounting '%s'...", boot_wim_path); + mount_path = WimMountImage(boot_wim_path, wim_index); + if (mount_path == NULL) + goto out; + } - if (unattend_xml_selection & UNATTEND_WINPE_SETUP_MASK) { + if (unattend_selection & (UNATTEND_SECUREBOOT_TPM_MASK | UNATTEND_MINRAM_MINDISK_MASK)) { // Try to create the registry keys directly, and fallback to using unattend // if that fails (which the Windows Store version is expected to do). static_sprintf(path, "%s\\Windows\\System32\\config\\SYSTEM", mount_path); @@ -1577,7 +1582,7 @@ BOOL ApplyWindowsCustomization(char drive_letter, BOOL windows_to_go) } for (i = 0; i < ARRAYSIZE(bypass_name); i++) { - if (!(unattend_xml_selection & (1 << (i / 2)))) + if (!(unattend_selection & (1 << (i / 2)))) continue; status = RegSetValueExA(hSubKey, bypass_name[i], 0, REG_DWORD, (LPBYTE)&dwVal, sizeof(DWORD)); if (status != ERROR_SUCCESS) { @@ -1590,18 +1595,52 @@ BOOL ApplyWindowsCustomization(char drive_letter, BOOL windows_to_go) } // We were successfull in creating the keys so disable the windowsPE section from unattend.xml // We do this by replacing '' with '' - if (replace_in_token_data(unattend_xml_path, " entries from windowsPE (and only windowsPE). + assert(FALSE); + } UpdateProgressWithInfoForce(OP_PATCH, MSG_325, 102, PATCH_PROGRESS_TOTAL); } copy_unattend: - static_sprintf(path, "%s\\Autounattend.xml", mount_path); - if (!CopyFileU(unattend_xml_path, path, TRUE)) { - uprintf("Could not create boot.wim 'Autounattend.xml': %s", WindowsErrorString()); - goto out; + if (unattend_selection & UNATTEND_WINPE_SETUP_MASK) { + // If we have a windowsPE section, copy the answer files to the root of boot.wim as + // Autounattend.xml. This also results in that file being automatically copied over + // to %WINDIR%\Panther\unattend.xml for later passes processing. + assert(mount_path != NULL); + static_sprintf(path, "%s\\Autounattend.xml", mount_path); + if (!CopyFileU(unattend_xml_path, path, TRUE)) { + uprintf("Could not create boot.wim 'Autounattend.xml': %s", WindowsErrorString()); + goto out; + } + uprintf("Added 'Autounattend.xml' to '%s'", boot_wim_path); + } else { + // If there is no windowsPE section in our unattend, then copying it as Autounattend.xml on + // the root of boot.wim will not work as Windows Setup does *NOT* carry Autounattend.xml into + // %WINDIR%\Panther\unattend.xml then (See: https://github.com/pbatard/rufus/issues/1981). + // So instead, copy it to \sources\$OEM$\$$\Panther\unattend.xml on the media, as the content + // of \sources\$OEM$\$$\* will get copied into %WINDIR%\ during the file copy phase. + static_sprintf(path, "%c:\\sources\\$OEM$\\$$\\Panther", drive_letter); + i = SHCreateDirectoryExA(NULL, path, NULL); + if (i != ERROR_SUCCESS) { + SetLastError(i); + uprintf("Error: Could not create directory '%s': %s", path, WindowsErrorString()); + goto out; + } + static_sprintf(path, "%c:\\sources\\$OEM$\\$$\\Panther\\unattend.xml", drive_letter); + if (!CopyFileU(unattend_xml_path, path, TRUE)) { + uprintf("Could not create '%s': %s", path, WindowsErrorString()); + goto out; + } + uprintf("Created '%s'", path); } - uprintf("Added 'Autounattend.xml' to '%s'", boot_wim_path); UpdateProgressWithInfoForce(OP_PATCH, MSG_325, 103, PATCH_PROGRESS_TOTAL); } r = TRUE; @@ -2413,7 +2452,7 @@ DWORD WINAPI FormatThread(void* param) goto out; } if (unattend_xml_path != NULL) { - if (!ApplyWindowsCustomization(drive_name[0], TRUE)) + if (!ApplyWindowsCustomization(drive_name[0], unattend_xml_selection | UNATTEND_WINDOWS_TO_GO)) FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_CANT_PATCH); } } else { @@ -2455,7 +2494,7 @@ DWORD WINAPI FormatThread(void* param) FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_PATCH); } if (unattend_xml_path != NULL) { - if (!ApplyWindowsCustomization(drive_name[0], FALSE)) + if (!ApplyWindowsCustomization(drive_name[0], unattend_xml_selection)) FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_CANT_PATCH); } } diff --git a/src/rufus.c b/src/rufus.c index 1b477627..83841694 100755 --- a/src/rufus.c +++ b/src/rufus.c @@ -1283,7 +1283,7 @@ static char* CreateUnattendXml(int arch, int mask) // WinPE will complain if we don't provide a product key. *Any* product key. This is soooo idiotic... fprintf(fd, " \n"); fprintf(fd, " \n"); - fprintf(fd, " xxxxx-xxxxx-xxxxx-xxxxx-xxxxx\n"); + fprintf(fd, " \n"); fprintf(fd, " \n"); fprintf(fd, " \n"); fprintf(fd, " \n"); diff --git a/src/rufus.h b/src/rufus.h index 0a5f1c42..f2136061 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -499,12 +499,13 @@ enum ArchType { }; // Windows User Experience (unattend.xml) options -#define UNATTEND_SECUREBOOT_TPM_MASK 0x01 -#define UNATTEND_MINRAM_MINDISK_MASK 0x02 -#define UNATTEND_NO_ONLINE_ACCOUNT_MASK 0x04 -#define UNATTEND_NO_DATA_COLLECTION_MASK 0x08 -#define UNATTEND_OFFLINE_INTERNAL_DRIVES 0x10 -#define UNATTEND_DEFAULT_MASK 0x1F +#define UNATTEND_SECUREBOOT_TPM_MASK 0x00001 +#define UNATTEND_MINRAM_MINDISK_MASK 0x00002 +#define UNATTEND_NO_ONLINE_ACCOUNT_MASK 0x00004 +#define UNATTEND_NO_DATA_COLLECTION_MASK 0x00008 +#define UNATTEND_OFFLINE_INTERNAL_DRIVES 0x00010 +#define UNATTEND_DEFAULT_MASK 0x0001F +#define UNATTEND_WINDOWS_TO_GO 0x10000 // Special flag for Windows To Go #define UNATTEND_WINPE_SETUP_MASK (UNATTEND_SECUREBOOT_TPM_MASK | UNATTEND_MINRAM_MINDISK_MASK) #define UNATTEND_SPECIALIZE_DEPLOYMENT_MASK (UNATTEND_NO_ONLINE_ACCOUNT_MASK) diff --git a/src/rufus.rc b/src/rufus.rc index 1ad239cc..5a3d1dd0 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 232, 326 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 3.20.1918" +CAPTION "Rufus 3.20.1919" FONT 9, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP @@ -395,8 +395,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 3,20,1918,0 - PRODUCTVERSION 3,20,1918,0 + FILEVERSION 3,20,1919,0 + PRODUCTVERSION 3,20,1919,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -414,13 +414,13 @@ BEGIN VALUE "Comments", "https://rufus.ie" VALUE "CompanyName", "Akeo Consulting" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "3.20.1918" + VALUE "FileVersion", "3.20.1919" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", "© 2011-2022 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html" VALUE "OriginalFilename", "rufus-3.20.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "3.20.1918" + VALUE "ProductVersion", "3.20.1919" END END BLOCK "VarFileInfo"