summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMarkus Pettersson <markus.pettersson@mullvad.net>2024-02-07 17:52:31 +0100
committerMarkus Pettersson <markus.pettersson@mullvad.net>2024-02-08 16:24:05 +0100
commit32375a1ccbf41dd298be4bc828bb0cef20fb37fa (patch)
treeacdcbc6e457363027f60afcfe9e11ca7ea0f32a9
parentb8b9f2971d3bf9870dbd89beeccd3ef2518f8b89 (diff)
downloadmullvadvpn-32375a1ccbf41dd298be4bc828bb0cef20fb37fa.tar.xz
mullvadvpn-32375a1ccbf41dd298be4bc828bb0cef20fb37fa.zip
Log version using `mullvad-nsis` in Windows installer
Expose the functionally for calling `RtlGetVersion` from `talpid-platform-metadata` through `mullvad-nsis`. This is used for getting the Windows build version during the windows installer.
-rw-r--r--Cargo.lock1
-rw-r--r--mullvad-nsis/Cargo.toml1
-rw-r--r--mullvad-nsis/include/mullvad-nsis.h2
-rw-r--r--mullvad-nsis/src/lib.rs31
-rw-r--r--windows/nsis-plugins/src/log/log.cpp152
5 files changed, 46 insertions, 141 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 5f37db970b..a2c553ab1e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1967,6 +1967,7 @@ version = "0.0.0"
dependencies = [
"cbindgen",
"mullvad-paths",
+ "talpid-platform-metadata",
]
[[package]]
diff --git a/mullvad-nsis/Cargo.toml b/mullvad-nsis/Cargo.toml
index 460057c9bb..b1394375bd 100644
--- a/mullvad-nsis/Cargo.toml
+++ b/mullvad-nsis/Cargo.toml
@@ -15,6 +15,7 @@ crate_type = ["staticlib"]
[target.i686-pc-windows-msvc.dependencies]
mullvad-paths = { path = "../mullvad-paths" }
+talpid-platform-metadata = { path = "../talpid-platform-metadata" }
[target.i686-pc-windows-msvc.build-dependencies]
cbindgen = { version = "0.24.3", default-features = false }
diff --git a/mullvad-nsis/include/mullvad-nsis.h b/mullvad-nsis/include/mullvad-nsis.h
index 5d9f1ddd23..ef55b2fc73 100644
--- a/mullvad-nsis/include/mullvad-nsis.h
+++ b/mullvad-nsis/include/mullvad-nsis.h
@@ -23,4 +23,6 @@ Status get_system_local_appdata(uint16_t *buffer, uintptr_t *buffer_size);
Status create_privileged_directory(const uint16_t* path);
+Status get_system_version(uint16_t *buffer, uintptr_t *buffer_size);
+
} // extern "C"
diff --git a/mullvad-nsis/src/lib.rs b/mullvad-nsis/src/lib.rs
index 7dd707b5e0..b97685169f 100644
--- a/mullvad-nsis/src/lib.rs
+++ b/mullvad-nsis/src/lib.rs
@@ -2,6 +2,7 @@
use std::{
ffi::OsString,
+ iter,
os::windows::ffi::{OsStrExt, OsStringExt},
panic::UnwindSafe,
path::Path,
@@ -85,6 +86,36 @@ pub unsafe extern "C" fn get_system_local_appdata(
})
}
+/// Writes the system's version data into `buffer` when `Status::Ok` is
+/// returned. If `buffer` is `null`, or if the buffer is too small,
+/// `InsufficientBufferSize` is returned, and the required buffer size (in
+/// chars) is returned in `buffer_size`. On success, `buffer_size` is set to the
+/// length of the string, including the final null terminator.
+#[no_mangle]
+pub unsafe extern "C" fn get_system_version(buffer: *mut u16, buffer_size: *mut usize) -> Status {
+ use talpid_platform_metadata::version;
+ catch_and_log_unwind(|| {
+ if buffer_size.is_null() {
+ return Status::InvalidArguments;
+ }
+
+ let build_number_string = OsString::from(version());
+ let build_number: Vec<u16> = build_number_string
+ .encode_wide()
+ .chain(iter::once(0u16))
+ .collect();
+
+ if *buffer_size < build_number.len() || buffer.is_null() {
+ return Status::InsufficientBufferSize;
+ }
+
+ *buffer_size = build_number.len();
+
+ ptr::copy_nonoverlapping(build_number.as_ptr(), buffer, build_number.len());
+ Status::Ok
+ })
+}
+
fn catch_and_log_unwind(func: impl FnOnce() -> Status + UnwindSafe) -> Status {
match std::panic::catch_unwind(func) {
Ok(status) => status,
diff --git a/windows/nsis-plugins/src/log/log.cpp b/windows/nsis-plugins/src/log/log.cpp
index 80338b80fe..d1e37d7669 100644
--- a/windows/nsis-plugins/src/log/log.cpp
+++ b/windows/nsis-plugins/src/log/log.cpp
@@ -90,142 +90,20 @@ std::vector<std::wstring> BlockToRows(const std::wstring &textBlock)
return common::string::Tokenize(textBlock, L"\r\n");
}
-std::wstring GetWindowsProductName()
-{
- auto regkey = common::registry::Registry::OpenKey(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
- false, common::registry::RegistryView::Force64);
-
- return regkey->readString(L"ProductName");
-}
-
std::wstring GetWindowsVersion()
{
- common::fs::ScopedNativeFileSystem nativeFileSystem;
-
- const auto systemDir = common::fs::GetKnownFolderPath(FOLDERID_System);
- const auto systemModule = std::filesystem::path(systemDir).append(L"ntoskrnl.exe");
-
- DWORD dummy;
-
- const auto versionSize = GetFileVersionInfoSizeW(systemModule.c_str(), &dummy);
-
- if (0 == versionSize)
- {
- THROW_WINDOWS_ERROR(GetLastError(), "GetFileVersionInfoSizeW");
- }
-
- std::vector<uint8_t> buf(versionSize);
-
- auto status = GetFileVersionInfoW(systemModule.c_str(), 0, static_cast<DWORD>(buf.size()), &buf[0]);
-
- if (FALSE == status)
- {
- THROW_WINDOWS_ERROR(GetLastError(), "GetFileVersionInfoW");
- }
-
- //
- // Get the translation table.
- // This is required to build the path to the value we're actually after.
- //
-
- struct LANGANDCODEPAGE
- {
- WORD wLanguage;
- WORD wCodePage;
- }
- *translations = nullptr;
-
- UINT translationsSize = 0;
-
- status = VerQueryValueW(&buf[0], L"\\VarFileInfo\\Translation", reinterpret_cast<LPVOID *>(&translations), &translationsSize);
-
- if (FALSE == status)
- {
- THROW_WINDOWS_ERROR(GetLastError(), "VerQueryValueW");
- }
+ std::vector<uint16_t> version(256);
+ size_t bufferSize = version.size();
- if (translationsSize < sizeof(LANGANDCODEPAGE))
+ // Call into the mullvad-nsis function 'get_system_version', which will
+ // retrieve a formatted Windows version.
+ auto result = get_system_version(version.data(), &bufferSize);
+ if (Status::Ok != result)
{
- THROW_ERROR("Invalid VERSION_INFO translation table");
+ THROW_ERROR("Failed to acquire Windows version");
}
- //
- // Use primary translation.
- //
-
- std::wstringstream ss;
-
- ss << L"\\StringFileInfo\\"
- << std::setw(4) << std::setfill(L'0') << std::hex
- << translations[0].wLanguage
- << std::setw(4) << std::setfill(L'0') << std::hex
- << translations[0].wCodePage
- << L"\\ProductVersion";
-
- const auto productVersionName = ss.str();
-
- void *productVersion = nullptr;
- UINT productVersionSize = 0;
-
- status = VerQueryValueW(&buf[0], productVersionName.c_str(), &productVersion, &productVersionSize);
-
- if (FALSE == status)
- {
- THROW_WINDOWS_ERROR(GetLastError(), "VerQueryValueW");
- }
-
- // Size returned is the length in characters.
- std::wstring version(reinterpret_cast<const wchar_t *>(productVersion), productVersionSize);
-
- // Chop off trailing terminators.
- while ((false == version.empty()) && (*version.rbegin() == L'\0'))
- {
- version.resize(version.size() - 1);
- }
-
- if (version.empty())
- {
- THROW_ERROR("Invalid version information");
- }
-
- return version;
-}
-
-//
-// FixupWindows11ProductName()
-//
-// Patch product name based on Windows version.
-// The registry value that holds the product name seems to be deprecated in Win11.
-//
-std::wstring FixupWindows11ProductName(const std::wstring &productName, const std::wstring &version)
-{
- const auto versionTokens = common::string::Tokenize(version, L".");
-
- if (versionTokens.size() < 3)
- {
- return productName;
- }
-
- const auto major = common::string::LexicalCast<uint32_t>(versionTokens[0]);
- const auto minor = common::string::LexicalCast<uint32_t>(versionTokens[1]);
- const auto build = common::string::LexicalCast<uint32_t>(versionTokens[2]);
-
- if (major != 10 || minor != 0 || build < 22000)
- {
- return productName;
- }
-
- auto productTokens = common::string::Tokenize(productName, L" ");
-
- for (auto &token : productTokens)
- {
- if (0 == token.compare(L"10"))
- {
- token = L"11";
- }
- }
-
- return common::string::Join(productTokens, L" ");
+ return std::wstring(reinterpret_cast<wchar_t *>(version.data()));
}
} // anonymous namespace
@@ -408,17 +286,9 @@ void __declspec(dllexport) NSISCALL LogWindowsVersion
try
{
- const auto productName = GetWindowsProductName();
- const auto version = GetWindowsVersion();
-
- std::wstringstream ss;
-
- ss << L"Windows version: "
- << FixupWindows11ProductName(productName, version)
- << L", "
- << version;
-
- g_logger->log(ss.str());
+ std::wstringstream version;
+ version << L"Windows version: " << GetWindowsVersion();
+ g_logger->log(version.str());
}
catch (std::exception &err)
{