summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephan Bergmann <stephan.bergmann@allotropia.de>2023-12-21 14:11:59 +0100
committerStephan Bergmann <stephan.bergmann@allotropia.de>2023-12-21 16:50:25 +0100
commit04b18e28d3b44e2175331e78183e3b0fe6d81187 (patch)
treef70539ddadd8619794c4658f8cbabc3de9568fd8
parent522f2174561a58cd9b29aba2a94f7268281bf880 (diff)
Windows MSI custom action for --enable-online-update-mar
...which needs to call update_service.exe with "install" (resp. "uninstall") and needs to create (resp. delete) a registry entry containing the issuer and name of the certificate with which the updater.exe is signed (which is required by one of the many sanity and security checks performed by update_service.exe before it will actually do an automatic update). (The issuer and name of the certificate are for now hardcoded to the values used by TDF when signing its Windows builds.) (gid_Customaction_uninstall_updateservice needs to run rather early, when update_service.exe has not yet been removed, so I rather randomly picked "MigrateFeatureStates" as the point where to run it.) Change-Id: I6e0f62ec3e51d74d4a526a490badc7c14ebe99ae Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161102 Tested-by: Jenkins Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
-rw-r--r--Repository.mk1
-rw-r--r--external/onlineupdate/Library_install_updateservice.mk54
-rw-r--r--external/onlineupdate/Module_onlineupdate.mk1
-rw-r--r--external/onlineupdate/install_updateservice.cxx179
-rw-r--r--external/onlineupdate/install_updateservice.def4
-rw-r--r--scp2/source/ooo/windowscustomaction_ooo.scp23
6 files changed, 262 insertions, 0 deletions
diff --git a/Repository.mk b/Repository.mk
index 9ef08e814a20..a53d923f36b5 100644
--- a/Repository.mk
+++ b/Repository.mk
@@ -743,6 +743,7 @@ $(eval $(call gb_Helper_register_libraries_for_install,PLAINLIBS_OOO,ooobinaryta
sdqsmsi \
sellangmsi \
sn_tools \
+ $(if $(ENABLE_ONLINE_UPDATE_MAR),install_updateservice) \
) \
))
diff --git a/external/onlineupdate/Library_install_updateservice.mk b/external/onlineupdate/Library_install_updateservice.mk
new file mode 100644
index 000000000000..216b81a95a07
--- /dev/null
+++ b/external/onlineupdate/Library_install_updateservice.mk
@@ -0,0 +1,54 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 100 -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Library_Library,install_updateservice))
+
+$(eval $(call gb_Library_use_unpacked,install_updateservice,onlineupdate))
+
+$(eval $(call gb_Library_set_include,install_updateservice, \
+ -I$(call gb_UnpackedTarball_get_dir,onlineupdate)/onlineupdate/source/update/common \
+ $$(INCLUDE) \
+))
+
+$(eval $(call gb_Library_add_defs,install_updateservice, \
+ -U_DLL \
+))
+
+$(eval $(call gb_Library_add_cxxflags,install_updateservice, \
+ $(if $(MSVC_USE_DEBUG_RUNTIME),/MTd,/MT) \
+ $(if $(filter -fsanitize=%,$(CC)),,/fno-sanitize-address-vcasan-lib) \
+))
+
+$(eval $(call gb_Library_add_ldflags,install_updateservice, \
+ /DEF:$(SRCDIR)/external/onlineupdate/install_updateservice.def \
+ /NODEFAULTLIB \
+))
+
+$(eval $(call gb_Library_add_exception_objects,install_updateservice, \
+ external/onlineupdate/install_updateservice \
+))
+
+$(eval $(call gb_Library_use_static_libraries,install_updateservice, \
+ updatehelper \
+))
+
+$(eval $(call gb_Library_use_system_win32_libs,install_updateservice, \
+ libcmt \
+ libcpmt \
+ libucrt \
+ libvcruntime \
+ msi \
+ kernel32 \
+ user32 \
+ advapi32 \
+ shell32 \
+ shlwapi \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/external/onlineupdate/Module_onlineupdate.mk b/external/onlineupdate/Module_onlineupdate.mk
index a6bc698aa3ca..97f7d5c3f7bd 100644
--- a/external/onlineupdate/Module_onlineupdate.mk
+++ b/external/onlineupdate/Module_onlineupdate.mk
@@ -18,6 +18,7 @@ $(eval $(call gb_Module_add_targets,onlineupdate,\
StaticLibrary_updatehelper \
$(if $(filter WNT,$(OS)),\
Executable_update_service \
+ Library_install_updateservice \
WinResTarget_updater )\
Executable_test_updater_dialog \
Executable_mar \
diff --git a/external/onlineupdate/install_updateservice.cxx b/external/onlineupdate/install_updateservice.cxx
new file mode 100644
index 000000000000..4604e55462d6
--- /dev/null
+++ b/external/onlineupdate/install_updateservice.cxx
@@ -0,0 +1,179 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sal/config.h>
+
+#include <cstddef>
+#include <limits>
+#include <memory>
+#include <string>
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <msiquery.h>
+
+#include <pathhash.h>
+
+// Replacements for functions used in
+// workdir/UnpackedTarball/onlineupdate/onlineupdate/source/update/common/pathhash.cpp but not
+// available here:
+
+extern "C" wchar_t* _wcslwr(wchar_t* str)
+{
+ for (auto p = str; *p != L'\0'; ++p)
+ {
+ if (*p >= L'A' && *p <= L'Z')
+ {
+ *p += L'a' - L'A';
+ }
+ }
+ return str;
+};
+
+extern "C" wchar_t* wcsncpy(wchar_t* strDest, wchar_t const* strSource, std::size_t count)
+{
+ for (std::size_t i = 0; i != count; ++i)
+ {
+ strDest[i] = *strSource;
+ if (*strSource != L'\0')
+ {
+ ++strSource;
+ }
+ }
+ return strDest;
+}
+
+namespace
+{
+bool getInstallLocation(MSIHANDLE handle, std::wstring* installLocation)
+{
+ DWORD n = 0;
+ if (MsiGetPropertyW(handle, L"INSTALLLOCATION", const_cast<wchar_t*>(L""), &n)
+ != ERROR_MORE_DATA
+ || n == std::numeric_limits<DWORD>::max())
+ {
+ return false;
+ }
+ ++n;
+ auto buf = std::make_unique<wchar_t[]>(n);
+ if (MsiGetPropertyW(handle, L"INSTALLLOCATION", buf.get(), &n) != ERROR_SUCCESS)
+ {
+ return false;
+ }
+ if (n != 0 && buf[n - 1] == L'\\')
+ {
+ --n;
+ }
+ installLocation->assign(buf.get(), n);
+ return true;
+}
+
+typedef std::unique_ptr<void, decltype(&CloseHandle)> CloseHandleGuard;
+
+CloseHandleGuard guard(HANDLE handle) { return CloseHandleGuard(handle, CloseHandle); }
+
+bool runExecutable(std::wstring const& installLocation, wchar_t const* commandLine)
+{
+ STARTUPINFOW si{};
+ si.cb = sizeof(si);
+ PROCESS_INFORMATION pi{};
+ if (!CreateProcessW((installLocation + L"\\program\\update_service.exe").c_str(),
+ const_cast<LPWSTR>(commandLine), nullptr, nullptr, FALSE, CREATE_NO_WINDOW,
+ nullptr, nullptr, &si, &pi))
+ {
+ return false;
+ }
+ auto const g(guard(pi.hProcess));
+ DWORD res = WaitForSingleObject(pi.hProcess, INFINITE);
+ if (res != WAIT_OBJECT_0)
+ {
+ return false;
+ }
+ DWORD ec = 0;
+ if (!GetExitCodeProcess(pi.hProcess, &ec))
+ {
+ return false;
+ }
+ if (ec != 0)
+ {
+ return false;
+ }
+ return true;
+}
+}
+
+extern "C" __declspec(dllexport) UINT __stdcall InstallUpdateservice(MSIHANDLE handle)
+{
+ std::wstring loc;
+ if (!getInstallLocation(handle, &loc))
+ {
+ return false;
+ }
+ if (!runExecutable(loc, L"install"))
+ {
+ return ERROR_INVALID_FUNCTION;
+ }
+ WCHAR maintenanceServiceKey[MAX_PATH + 1];
+ if (!CalculateRegistryPathFromFilePath(loc.c_str(), maintenanceServiceKey))
+ {
+ return ERROR_INVALID_FUNCTION;
+ }
+ HKEY key;
+ if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, (std::wstring(maintenanceServiceKey) + L"\\0").c_str(),
+ 0, nullptr, REG_OPTION_NON_VOLATILE, KEY_WRITE | KEY_WOW64_64KEY, nullptr,
+ &key, nullptr)
+ != ERROR_SUCCESS)
+ {
+ return ERROR_INVALID_FUNCTION;
+ }
+ if (RegSetValueExW(key, L"issuer", 0, REG_SZ,
+ reinterpret_cast<BYTE const*>(L"Certum Code Signing 2021 CA"),
+ sizeof L"Certum Code Signing 2021 CA")
+ != ERROR_SUCCESS)
+ {
+ return ERROR_INVALID_FUNCTION;
+ }
+ if (RegSetValueExW(key, L"name", 0, REG_SZ,
+ reinterpret_cast<BYTE const*>(L"The Document Foundation"),
+ sizeof L"The Document Foundation")
+ != ERROR_SUCCESS)
+ {
+ return ERROR_INVALID_FUNCTION;
+ }
+ if (RegCloseKey(key) != ERROR_SUCCESS)
+ {
+ return ERROR_INVALID_FUNCTION;
+ }
+ return ERROR_SUCCESS;
+}
+
+extern "C" __declspec(dllexport) UINT __stdcall UninstallUpdateservice(MSIHANDLE handle)
+{
+ std::wstring loc;
+ if (!getInstallLocation(handle, &loc))
+ {
+ return false;
+ }
+ if (!runExecutable(loc, L"uninstall"))
+ {
+ return ERROR_INVALID_FUNCTION;
+ }
+ WCHAR maintenanceServiceKey[MAX_PATH + 1];
+ if (!CalculateRegistryPathFromFilePath(loc.c_str(), maintenanceServiceKey))
+ {
+ return ERROR_INVALID_FUNCTION;
+ }
+ if (RegDeleteTreeW(HKEY_LOCAL_MACHINE, maintenanceServiceKey) != ERROR_SUCCESS)
+ {
+ return ERROR_INVALID_FUNCTION;
+ }
+ return ERROR_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/external/onlineupdate/install_updateservice.def b/external/onlineupdate/install_updateservice.def
new file mode 100644
index 000000000000..a210387fce33
--- /dev/null
+++ b/external/onlineupdate/install_updateservice.def
@@ -0,0 +1,4 @@
+LIBRARY "install_updateservice.dll"
+EXPORTS
+ InstallUpdateservice
+ UninstallUpdateservice
diff --git a/scp2/source/ooo/windowscustomaction_ooo.scp b/scp2/source/ooo/windowscustomaction_ooo.scp
index 41b78daad13b..0bd451c04f9d 100644
--- a/scp2/source/ooo/windowscustomaction_ooo.scp
+++ b/scp2/source/ooo/windowscustomaction_ooo.scp
@@ -16,6 +16,7 @@
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
+#include "config_features.h"
#include "macros.inc"
WindowsCustomAction gid_Customaction_Regallmsdocdll
@@ -244,3 +245,25 @@ WindowsCustomAction gid_Customaction_prep_reg_dlls
Inbinarytable = 1;
Assignment1 = ("InstallExecuteSequence", "", "behind_CostFinalize");
End
+
+#if HAVE_FEATURE_UPDATE_MAR
+
+WindowsCustomAction gid_Customaction_install_updateservice
+ Name = "install_updateservice";
+ Typ = "65";
+ Source = "install_updateservice.dll";
+ Target = "InstallUpdateservice";
+ Inbinarytable = 1;
+ Assignment1 = ("InstallExecuteSequence", "Not REMOVE=\"ALL\"", "end");
+End
+
+WindowsCustomAction gid_Customaction_uninstall_updateservice
+ Name = "uninstall_updateservice";
+ Typ = "65";
+ Source = "install_updateservice.dll";
+ Target = "UninstallUpdateservice";
+ Inbinarytable = 1;
+ Assignment1 = ("InstallExecuteSequence", "REMOVE=\"ALL\"", "MigrateFeatureStates");
+End
+
+#endif