Bug 1436475 Part 3 - Port our customizations forward to the new 7-zip code. r?agashlin draft
authorMatt Howell <mhowell@mozilla.com>
Mon, 12 Feb 2018 14:46:37 -0800
changeset 754613 7d4d68302f453a07261af022d9b5c6242a1bfa66
parent 754612 cd9f09b5547c7d49792c0b2fc370e7d46c5eeee5
child 754614 9955c19c3c72ac5673740d4c2159ef288470d510
push id98946
push usermhowell@mozilla.com
push dateTue, 13 Feb 2018 22:25:21 +0000
reviewersagashlin
bugs1436475
milestone60.0a1
Bug 1436475 Part 3 - Port our customizations forward to the new 7-zip code. r?agashlin MozReview-Commit-ID: 7QtV1XTSKch
other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsp
other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp
other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/resource.h
other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/resource.rc
other-licenses/7zstub/src/CPP/7zip/UI/FileManager/ProgressDialog.cpp
--- a/other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsp
+++ b/other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsp
@@ -49,17 +49,17 @@ RSC=rc.exe
 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
 # ADD BASE RSC /l 0x419 /d "NDEBUG"
 # ADD RSC /l 0x419 /d "NDEBUG"
 BSC32=bscmake.exe
 # ADD BASE BSC32 /nologo
 # ADD BSC32 /nologo
 LINK32=link.exe
 # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
-# ADD LINK32 comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zS.sfx" /opt:NOWIN98
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib delayimp.lib /nologo /subsystem:windows /machine:I386 /out:"Release\7zS.sfx" /opt:NOWIN98 /delayload:user32.dll /delayload:shell32.dll /delayload:oleaut32.dll
 # SUBTRACT LINK32 /pdb:none
 
 !ELSEIF  "$(CFG)" == "SFXSetup - Win32 Debug"
 
 # PROP BASE Use_MFC 0
 # PROP BASE Use_Debug_Libraries 1
 # PROP BASE Output_Dir "Debug"
 # PROP BASE Intermediate_Dir "Debug"
@@ -76,17 +76,17 @@ LINK32=link.exe
 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
 # ADD BASE RSC /l 0x419 /d "_DEBUG"
 # ADD RSC /l 0x419 /d "_DEBUG"
 BSC32=bscmake.exe
 # ADD BASE BSC32 /nologo
 # ADD BSC32 /nologo
 LINK32=link.exe
 # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib /nologo /subsystem:windows /debug /machine:I386 /out:"C:\UTIL\7zSfxS.exe" /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib delayimp.lib /nologo /subsystem:windows /debug /machine:I386 /out:"Debug\7zSfxS.exe" /pdbtype:sept /delayload:user32.dll /delayload:shell32.dll /delayload:oleaut32.dll
 
 !ELSEIF  "$(CFG)" == "SFXSetup - Win32 ReleaseD"
 
 # PROP BASE Use_MFC 0
 # PROP BASE Use_Debug_Libraries 0
 # PROP BASE Output_Dir "ReleaseD"
 # PROP BASE Intermediate_Dir "ReleaseD"
 # PROP BASE Ignore_Export_Lib 0
@@ -102,19 +102,19 @@ LINK32=link.exe
 # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
 # ADD BASE RSC /l 0x419 /d "NDEBUG"
 # ADD RSC /l 0x419 /d "NDEBUG"
 BSC32=bscmake.exe
 # ADD BASE BSC32 /nologo
 # ADD BSC32 /nologo
 LINK32=link.exe
-# ADD BASE LINK32 comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\UTIL\7zWinSR.exe"
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\UTIL\7zWinSR.exe"
 # SUBTRACT BASE LINK32 /debug /nodefaultlib
-# ADD LINK32 comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zSD.sfx" /opt:NOWIN98
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib delayimp.lib /nologo /subsystem:windows /machine:I386 /out:"ReleaseD\7zSD.sfx" /opt:NOWIN98 /delayload:user32.dll /delayload:shell32.dll /delayload:oleaut32.dll
 # SUBTRACT LINK32 /pdb:none
 
 !ENDIF 
 
 # Begin Target
 
 # Name "SFXSetup - Win32 Release"
 # Name "SFXSetup - Win32 Debug"
--- a/other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp
+++ b/other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp
@@ -120,31 +120,226 @@ static void ShowErrorMessageSpec(const U
   if (pos >= 0)
   {
     message.Delete(pos, 2);
     message.Insert(pos, name);
   }
   ShowErrorMessage(NULL, message);
 }
 
+/* BEGIN Mozilla customizations */
+
+static char const *
+FindStrInBuf(char const * buf, size_t bufLen, char const * str)
+{
+  size_t index = 0;
+  while (index < bufLen) {
+    char const * result = strstr(buf + index, str);
+    if (result) {
+      return result;
+    }
+    while ((buf[index] != '\0') && (index < bufLen)) {
+      index++;
+    }
+    index++;
+  }
+  return NULL;
+}
+
+static bool
+ReadPostSigningDataFromView(char const * view, DWORD size, AString& data)
+{
+  // Find the offset and length of the certificate table,
+  // so we know the valid range to look for the token.
+  if (size < (0x3c + sizeof(UInt32))) {
+    return false;
+  }
+  UInt32 PEHeaderOffset = *(UInt32*)(view + 0x3c);
+  UInt32 optionalHeaderOffset = PEHeaderOffset + 24;
+  UInt32 certDirEntryOffset = 0;
+  if (size < (optionalHeaderOffset + sizeof(UInt16))) {
+    return false;
+  }
+  UInt16 magic = *(UInt16*)(view + optionalHeaderOffset);
+  if (magic == 0x010b) {
+    // 32-bit executable
+    certDirEntryOffset = optionalHeaderOffset + 128;
+  } else if (magic == 0x020b) {
+    // 64-bit executable; certain header fields are wider
+    certDirEntryOffset = optionalHeaderOffset + 144;
+  } else {
+    // Unknown executable
+    return false;
+  }
+  if (size < certDirEntryOffset + 8) {
+    return false;
+  }
+  UInt32 certTableOffset = *(UInt32*)(view + certDirEntryOffset);
+  UInt32 certTableLen = *(UInt32*)(view + certDirEntryOffset + sizeof(UInt32));
+  if (certTableOffset == 0 || certTableLen == 0 ||
+      size < (certTableOffset + certTableLen)) {
+    return false;
+  }
+
+  char const token[] = "__MOZCUSTOM__:";
+  // We're searching for a string inside a binary blob,
+  // so a normal strstr that bails on the first NUL won't work.
+  char const * tokenPos = FindStrInBuf(view + certTableOffset,
+                                       certTableLen, token);
+  if (tokenPos) {
+    size_t tokenLen = (sizeof(token) / sizeof(token[0])) - 1;
+    data = AString(tokenPos + tokenLen);
+    return true;
+  }
+  return false;
+}
+
+static bool
+ReadPostSigningData(UString exePath, AString& data)
+{
+  bool retval = false;
+  HANDLE exeFile = CreateFileW(exePath, GENERIC_READ, FILE_SHARE_READ, NULL,
+                               OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+  if (exeFile != INVALID_HANDLE_VALUE) {
+    HANDLE mapping = CreateFileMapping(exeFile, NULL, PAGE_READONLY, 0, 0, NULL);
+    if (mapping != INVALID_HANDLE_VALUE) {
+      // MSDN claims the return value on failure is NULL,
+      // but I've also seen it returned on success, so double-check.
+      if (mapping || GetLastError() == ERROR_SUCCESS) {
+        char * view = (char*)MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
+        if (view) {
+          DWORD fileSize = GetFileSize(exeFile, NULL);
+          retval = ReadPostSigningDataFromView(view, fileSize, data);
+        }
+        CloseHandle(mapping);
+      }
+    }
+    CloseHandle(exeFile);
+  }
+  return retval;
+}
+
+// Delayed load libraries are loaded when the first symbol is used.
+// The following ensures that we load the delayed loaded libraries from the
+// system directory.
+struct AutoLoadSystemDependencies
+{
+  AutoLoadSystemDependencies()
+  {
+    HMODULE module = ::GetModuleHandleW(L"kernel32.dll");
+    if (module) {
+      // SetDefaultDllDirectories is always available on Windows 8 and above. It
+      // is also available on Windows Vista, Windows Server 2008, and
+      // Windows 7 when MS KB2533623 has been applied.
+      typedef BOOL (WINAPI *SetDefaultDllDirectoriesType)(DWORD);
+      SetDefaultDllDirectoriesType setDefaultDllDirectories =
+        (SetDefaultDllDirectoriesType) GetProcAddress(module, "SetDefaultDllDirectories");
+      if (setDefaultDllDirectories) {
+        setDefaultDllDirectories(0x0800 /* LOAD_LIBRARY_SEARCH_SYSTEM32 */ );
+        return;
+      }
+    }
+
+    static LPCWSTR delayDLLs[] = { L"uxtheme.dll", L"userenv.dll",
+                                   L"setupapi.dll", L"apphelp.dll",
+                                   L"propsys.dll", L"dwmapi.dll",
+                                   L"cryptbase.dll", L"oleacc.dll",
+                                   L"clbcatq.dll" };
+    WCHAR systemDirectory[MAX_PATH + 1] = { L'\0' };
+    // If GetSystemDirectory fails we accept that we'll load the DLLs from the
+    // normal search path.
+    GetSystemDirectoryW(systemDirectory, MAX_PATH + 1);
+    size_t systemDirLen = wcslen(systemDirectory);
+
+    // Make the system directory path terminate with a slash
+    if (systemDirectory[systemDirLen - 1] != L'\\' && systemDirLen) {
+      systemDirectory[systemDirLen] = L'\\';
+      ++systemDirLen;
+      // No need to re-NULL terminate
+    }
+
+    // For each known DLL ensure it is loaded from the system32 directory
+    for (size_t i = 0; i < sizeof(delayDLLs) / sizeof(delayDLLs[0]); ++i) {
+      size_t fileLen = wcslen(delayDLLs[i]);
+      wcsncpy(systemDirectory + systemDirLen, delayDLLs[i],
+      MAX_PATH - systemDirLen);
+      if (systemDirLen + fileLen <= MAX_PATH) {
+        systemDirectory[systemDirLen + fileLen] = L'\0';
+      } else {
+        systemDirectory[MAX_PATH] = L'\0';
+      }
+      LPCWSTR fullModulePath = systemDirectory; // just for code readability
+      LoadLibraryW(fullModulePath);
+    }
+  }
+} loadDLLs;
+
+BOOL
+RemoveCurrentDirFromSearchPath()
+{
+  // kernel32.dll is in the knownDLL list so it is safe to load without a full path
+  HMODULE kernel32 = LoadLibraryW(L"kernel32.dll");
+  if (!kernel32) {
+    return FALSE;
+  }
+
+  typedef BOOL (WINAPI *SetDllDirectoryType)(LPCWSTR);
+  SetDllDirectoryType SetDllDirectoryFn =
+    (SetDllDirectoryType)GetProcAddress(kernel32, "SetDllDirectoryW");
+  if (!SetDllDirectoryFn) {
+    FreeLibrary(kernel32);
+    return FALSE;
+  }
+
+  // If this call fails we can't do much about it, so ignore it.
+  // It is unlikely to fail and this is just a precaution anyway.
+  SetDllDirectoryFn(L"");
+  FreeLibrary(kernel32);
+  return TRUE;
+}
+
+/* END Mozilla customizations */
+
 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */,
     #ifdef UNDER_CE
     LPWSTR
     #else
     LPSTR
     #endif
     /* lpCmdLine */,int /* nCmdShow */)
 {
+  /* BEGIN Mozilla customizations */
+  // Disable current directory from being in the search path.
+  // This call does not help with implicitly loaded DLLs.
+  if (!RemoveCurrentDirFromSearchPath()) {
+    WCHAR minOSTitle[512] = { '\0' };
+    WCHAR minOSText[512] = { '\0' };
+    LoadStringW(NULL, IDS_MIN_OS_TITLE, minOSTitle,
+                sizeof(minOSTitle) / sizeof(minOSTitle[0]));
+    LoadStringW(NULL, IDS_MIN_OS_TEXT, minOSText,
+                sizeof(minOSText) / sizeof(minOSText[0]));
+    MessageBoxW(NULL, minOSText, minOSTitle, MB_OK | MB_ICONERROR);
+    return 1;
+  }
+  /* END Mozilla customizations */
+
   g_hInstance = (HINSTANCE)hInstance;
 
   NT_CHECK
 
-  #ifdef _WIN32
-  LoadSecurityDlls();
-  #endif
+  // BEGIN Mozilla customizations
+  // Our AutoLoadSystemDependencies (see above) does the same job as the
+  // LoadSecurityDlls function, but slightly better because it runs as a static
+  // initializer, and it doesn't include LOAD_LIBRARY_SEARCH_USER_DIRS in
+  // the search path, which partially defeats the purpose of calling
+  // SetDefaultDllDirectories at all.
+  //#ifdef _WIN32
+  //LoadSecurityDlls();
+  //#endif
+  // END Mozilla customizations
 
   // InitCommonControls();
 
   UString archiveName, switches;
   #ifdef _SHELL_EXECUTE
   UString executeFile, executeParameters;
   #endif
   NCommandLineParser::SplitCommandLine(GetCommandLineW(), archiveName, switches);
@@ -167,16 +362,30 @@ int APIENTRY WinMain(HINSTANCE hInstance
     if (!assumeYes)
       ShowErrorMessage(L"Can't load config info");
     return 1;
   }
 
   UString dirPrefix ("." STRING_PATH_SEPARATOR);
   UString appLaunched;
   bool showProgress = true;
+
+  /* BEGIN Mozilla customizations */
+  bool extractOnly = false;
+  if (switches.IsPrefixedBy_NoCase(L"-ms") ||
+      switches.IsPrefixedBy_NoCase(L"/ini") ||
+      switches.IsPrefixedBy_NoCase(L"/s")) {
+    showProgress = false;
+  } else if (switches.IsPrefixedBy_NoCase(L"/extractdir=")) {
+    assumeYes = true;
+    showProgress = false;
+    extractOnly = true;
+  }
+  /* END Mozilla customizations */
+
   if (!config.IsEmpty())
   {
     CObjectVector<CTextConfigPair> pairs;
     if (!GetTextConfig(config, pairs))
     {
       if (!assumeYes)
         ShowErrorMessage(L"Config failed");
       return 1;
@@ -199,17 +408,18 @@ int APIENTRY WinMain(HINSTANCE hInstance
     
     #ifdef _SHELL_EXECUTE
     executeFile = GetTextConfigValue(pairs, "ExecuteFile");
     executeParameters = GetTextConfigValue(pairs, "ExecuteParameters");
     #endif
   }
 
   CTempDir tempDir;
-  if (!tempDir.Create(kTempDirPrefix))
+  /* Mozilla customizations - Added !extractOnly */
+  if (!extractOnly && !tempDir.Create(kTempDirPrefix))
   {
     if (!assumeYes)
       ShowErrorMessage(L"Can not create temp folder archive");
     return 1;
   }
 
   CCodecs *codecs = new CCodecs;
   CMyComPtr<IUnknown> compressCodecsInfo = codecs;
@@ -217,17 +427,19 @@ int APIENTRY WinMain(HINSTANCE hInstance
     HRESULT result = codecs->Load();
     if (result != S_OK)
     {
       ShowErrorMessage(L"Can not load codecs");
       return 1;
     }
   }
 
-  const FString tempDirPath = tempDir.GetPath();
+  /* BEGIN Mozilla customizations - added extractOnly  parameter support */
+  const FString tempDirPath = extractOnly ? switches.Ptr(12) : GetUnicodeString(tempDir.GetPath());
+  /* END Mozilla customizations */
   // tempDirPath = L"M:\\1\\"; // to test low disk space
   {
     bool isCorrupt = false;
     UString errorMessage;
     HRESULT result = ExtractArchive(codecs, fullPath, tempDirPath, showProgress,
       isCorrupt, errorMessage);
     
     if (result != S_OK)
@@ -245,16 +457,38 @@ int APIENTRY WinMain(HINSTANCE hInstance
             errorMessage = NError::MyFormatMessage(result);
           ::MessageBoxW(0, errorMessage, NWindows::MyLoadString(IDS_EXTRACTION_ERROR_TITLE), MB_ICONERROR);
         }
       }
       return 1;
     }
   }
 
+  /* BEGIN Mozilla customizations */
+  // Retrieve and store any data added to this file after signing.
+  {
+    AString postSigningData;
+    if (ReadPostSigningData(fullPath, postSigningData)) {
+      FString postSigningDataFilePath(tempDirPath);
+      NFile::NName::NormalizeDirPathPrefix(postSigningDataFilePath);
+      postSigningDataFilePath += L"postSigningData";
+
+      NFile::NIO::COutFile postSigningDataFile;
+      postSigningDataFile.Create(postSigningDataFilePath, true);
+
+      UInt32 written = 0;
+      postSigningDataFile.Write(postSigningData, postSigningData.Len(), written);
+    }
+  }
+
+  if (extractOnly) {
+    return 0;
+  }
+  /* END Mozilla customizations */
+
   #ifndef UNDER_CE
   CCurrentDirRestorer currentDirRestorer;
   if (!SetCurrentDir(tempDirPath))
     return 1;
   #endif
   
   HANDLE hProcess = 0;
 #ifdef _SHELL_EXECUTE
--- a/other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/resource.h
+++ b/other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/resource.h
@@ -1,6 +1,8 @@
 #define IDI_ICON  1
 
 #define IDS_EXTRACTION_ERROR_TITLE       7
 #define IDS_EXTRACTION_ERROR_MESSAGE     8
 #define IDS_CANNOT_CREATE_FOLDER      3003
 #define IDS_PROGRESS_EXTRACTING       3300
+#define IDS_MIN_OS_TITLE                70
+#define IDS_MIN_OS_TEXT                 71
--- a/other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/resource.rc
+++ b/other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/resource.rc
@@ -6,11 +6,13 @@ MY_VERSION_INFO_APP("7z Setup SFX", "7zS
 IDI_ICON  ICON "setup.ico"
 
 STRINGTABLE
 BEGIN
   IDS_EXTRACTION_ERROR_TITLE  "Extraction Failed"
   IDS_EXTRACTION_ERROR_MESSAGE  "File is corrupt"
   IDS_CANNOT_CREATE_FOLDER  "Cannot create folder '{0}'"
   IDS_PROGRESS_EXTRACTING  "Extracting"
+  IDS_MIN_OS_TITLE  "Setup Error"
+  IDS_MIN_OS_TEXT  "Microsoft Windows 7 or newer is required."
 END
 
 #include "../../UI/FileManager/ProgressDialog.rc"
--- a/other-licenses/7zstub/src/CPP/7zip/UI/FileManager/ProgressDialog.cpp
+++ b/other-licenses/7zstub/src/CPP/7zip/UI/FileManager/ProgressDialog.cpp
@@ -160,17 +160,18 @@ bool CProgressDialog::OnButtonClicked(in
 {
   switch (buttonID)
   {
     case IDCANCEL:
     {
       bool paused = Sync.GetPaused();
       Sync.SetPaused(true);
       _inCancelMessageBox = true;
-      int res = ::MessageBoxW(*this, L"Are you sure you want to cancel?", _title, MB_YESNOCANCEL);
+      // Mozilla Customization - Removed redundant cancel button from dialog.
+      int res = ::MessageBoxW(*this, L"Are you sure you want to cancel?", _title, MB_YESNO);
       _inCancelMessageBox = false;
       Sync.SetPaused(paused);
       if (res == IDCANCEL || res == IDNO)
       {
         if (_externalCloseMessageWasReceived)
           OnExternalCloseMessage();
         return true;
       }