diff options
| author | Markus Pettersson <markus.pettersson@mullvad.net> | 2024-02-07 17:52:31 +0100 |
|---|---|---|
| committer | Markus Pettersson <markus.pettersson@mullvad.net> | 2024-02-08 16:24:05 +0100 |
| commit | 32375a1ccbf41dd298be4bc828bb0cef20fb37fa (patch) | |
| tree | acdcbc6e457363027f60afcfe9e11ca7ea0f32a9 | |
| parent | b8b9f2971d3bf9870dbd89beeccd3ef2518f8b89 (diff) | |
| download | mullvadvpn-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.lock | 1 | ||||
| -rw-r--r-- | mullvad-nsis/Cargo.toml | 1 | ||||
| -rw-r--r-- | mullvad-nsis/include/mullvad-nsis.h | 2 | ||||
| -rw-r--r-- | mullvad-nsis/src/lib.rs | 31 | ||||
| -rw-r--r-- | windows/nsis-plugins/src/log/log.cpp | 152 |
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) { |
