diff options
| -rw-r--r-- | .github/workflows/daemon.yml | 1 | ||||
| -rw-r--r-- | CHANGELOG.md | 3 | ||||
| -rw-r--r-- | Cargo.lock | 52 | ||||
| -rw-r--r-- | Cargo.toml | 1 | ||||
| -rw-r--r-- | mullvad-nsis/Cargo.toml | 17 | ||||
| -rw-r--r-- | mullvad-nsis/build.rs | 14 | ||||
| -rw-r--r-- | mullvad-nsis/include/mullvad-nsis.h | 24 | ||||
| -rw-r--r-- | mullvad-nsis/src/lib.rs | 58 | ||||
| -rw-r--r-- | mullvad-paths/Cargo.toml | 2 | ||||
| -rw-r--r-- | mullvad-paths/src/lib.rs | 2 | ||||
| -rw-r--r-- | mullvad-paths/src/windows.rs | 281 | ||||
| -rw-r--r-- | windows/nsis-plugins/src/cleanup/cleaningops.cpp | 39 | ||||
| -rw-r--r-- | windows/nsis-plugins/src/cleanup/cleanup.vcxproj | 20 |
13 files changed, 346 insertions, 168 deletions
diff --git a/.github/workflows/daemon.yml b/.github/workflows/daemon.yml index b9fb2988fa..2300169679 100644 --- a/.github/workflows/daemon.yml +++ b/.github/workflows/daemon.yml @@ -143,6 +143,7 @@ jobs: uses: actions-rs/toolchain@v1.0.6 with: toolchain: stable + target: i686-pc-windows-msvc default: true - name: Install Go diff --git a/CHANGELOG.md b/CHANGELOG.md index 98b360c3eb..a2791a37fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,9 @@ Line wrap the file at 100 chars. Th #### Android - Fix adaptive app icon which previously had a displaced nose and some other oddities. +#### Windows +- Fix service not starting when LSA protection is enabled (which is the default on Windows 11 22H2). + ## [2023.1] - 2023-02-20 ### Fixed diff --git a/Cargo.lock b/Cargo.lock index 8c7c22bd09..f058410aea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -289,6 +289,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" [[package]] +name = "cbindgen" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6358dedf60f4d9b8db43ad187391afe959746101346fe51bb978126bec61dfb" +dependencies = [ + "clap", + "heck", + "indexmap", + "log", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn", + "tempfile", + "toml", +] + +[[package]] name = "cc" version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -358,15 +377,15 @@ dependencies = [ [[package]] name = "clap" -version = "3.0.14" +version = "3.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b63edc3f163b3c71ec8aa23f9bd6070f77edbf3d1d198b164afa90ff00e4ec62" +checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" dependencies = [ "atty", "bitflags", + "clap_lex", "indexmap", - "lazy_static", - "os_str_bytes", + "once_cell", "strsim 0.10.0", "termcolor", "textwrap", @@ -382,6 +401,15 @@ dependencies = [ ] [[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + +[[package]] name = "classic-mceliece-rust" version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1745,11 +1773,20 @@ dependencies = [ ] [[package]] +name = "mullvad-nsis" +version = "0.0.0" +dependencies = [ + "cbindgen", + "mullvad-paths", +] + +[[package]] name = "mullvad-paths" version = "0.0.0" dependencies = [ "err-derive", "log", + "once_cell", "widestring 1.0.2", "windows-sys 0.42.0", ] @@ -2066,9 +2103,6 @@ name = "os_str_bytes" version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" -dependencies = [ - "memchr", -] [[package]] name = "p256" @@ -3450,9 +3484,9 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.14.2" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" diff --git a/Cargo.toml b/Cargo.toml index 1868ba9dfe..9cfeba5053 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ members = [ "mullvad-api", "mullvad-exclude", "mullvad-version", + "mullvad-nsis", "talpid-openvpn-plugin", "talpid-core", "talpid-dbus", diff --git a/mullvad-nsis/Cargo.toml b/mullvad-nsis/Cargo.toml new file mode 100644 index 0000000000..0c83da480b --- /dev/null +++ b/mullvad-nsis/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "mullvad-nsis" +version = "0.0.0" +authors = ["Mullvad VPN"] +description = "Helper library used by Mullvad NSIS plugins" +license = "GPL-3.0" +edition = "2021" +publish = false + +[lib] +crate_type = ["staticlib"] + +[target.i686-pc-windows-msvc.dependencies] +mullvad-paths = { path = "../mullvad-paths" } + +[target.i686-pc-windows-msvc.build-dependencies] +cbindgen = "0.24.3" diff --git a/mullvad-nsis/build.rs b/mullvad-nsis/build.rs new file mode 100644 index 0000000000..1765ff54ed --- /dev/null +++ b/mullvad-nsis/build.rs @@ -0,0 +1,14 @@ +fn main() { + #[cfg(all(target_arch = "x86", target_os = "windows"))] + { + extern crate cbindgen; + use std::env; + + let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); + let mut config: cbindgen::Config = Default::default(); + config.language = cbindgen::Language::Cxx; + cbindgen::generate_with_config(&crate_dir, config) + .unwrap() + .write_to_file("include/mullvad-nsis.h"); + } +} diff --git a/mullvad-nsis/include/mullvad-nsis.h b/mullvad-nsis/include/mullvad-nsis.h new file mode 100644 index 0000000000..5c71a517f1 --- /dev/null +++ b/mullvad-nsis/include/mullvad-nsis.h @@ -0,0 +1,24 @@ +#include <cstdarg> +#include <cstdint> +#include <cstdlib> +#include <ostream> +#include <new> + +enum class Status { + Ok, + InvalidArguments, + InsufficientBufferSize, + OsError, + Panic, +}; + +extern "C" { + +/// Writes the system's app data path 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. +Status get_system_local_appdata(uint16_t *buffer, uintptr_t *buffer_size); + +} // extern "C" diff --git a/mullvad-nsis/src/lib.rs b/mullvad-nsis/src/lib.rs new file mode 100644 index 0000000000..0ac85418e8 --- /dev/null +++ b/mullvad-nsis/src/lib.rs @@ -0,0 +1,58 @@ +#![cfg(all(target_arch = "x86", target_os = "windows"))] + +use std::{os::windows::ffi::OsStrExt, panic::UnwindSafe, ptr}; + +#[repr(C)] +pub enum Status { + Ok, + InvalidArguments, + InsufficientBufferSize, + OsError, + Panic, +} + +/// Writes the system's app data path 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_local_appdata( + buffer: *mut u16, + buffer_size: *mut usize, +) -> Status { + catch_and_log_unwind(|| { + if buffer_size.is_null() { + return Status::InvalidArguments; + } + + let path = match mullvad_paths::windows::get_system_service_appdata() { + Ok(path) => path, + Err(_error) => { + return Status::OsError; + } + }; + + let path = path.as_os_str(); + let path_u16: Vec<u16> = path.encode_wide().chain(std::iter::once(0u16)).collect(); + + let prev_len = *buffer_size; + + *buffer_size = path_u16.len(); + + if prev_len < path_u16.len() || buffer.is_null() { + return Status::InsufficientBufferSize; + } + + ptr::copy_nonoverlapping(path_u16.as_ptr(), buffer, path_u16.len()); + + Status::Ok + }) +} + +fn catch_and_log_unwind(func: impl FnOnce() -> Status + UnwindSafe) -> Status { + match std::panic::catch_unwind(func) { + Ok(status) => status, + Err(_error) => Status::Panic, + } +} diff --git a/mullvad-paths/Cargo.toml b/mullvad-paths/Cargo.toml index 3c4303c5b9..1d56987aaf 100644 --- a/mullvad-paths/Cargo.toml +++ b/mullvad-paths/Cargo.toml @@ -15,12 +15,14 @@ log = "0.4" [target.'cfg(windows)'.dependencies] widestring = "1.0" +once_cell = "1.13" [target.'cfg(target_os = "windows")'.dependencies.windows-sys] version = "0.42.0" features = [ "Win32_Foundation", "Win32_Security", + "Win32_Storage_FileSystem", "Win32_System_Com", "Win32_System_ProcessStatus", "Win32_System_SystemServices", diff --git a/mullvad-paths/src/lib.rs b/mullvad-paths/src/lib.rs index 88bd23d74b..e78b02bf2d 100644 --- a/mullvad-paths/src/lib.rs +++ b/mullvad-paths/src/lib.rs @@ -71,4 +71,4 @@ mod settings; pub use crate::settings::{get_default_settings_dir, settings_dir}; #[cfg(windows)] -mod windows; +pub mod windows; diff --git a/mullvad-paths/src/windows.rs b/mullvad-paths/src/windows.rs index ea9fe2b64e..8237a983b9 100644 --- a/mullvad-paths/src/windows.rs +++ b/mullvad-paths/src/windows.rs @@ -1,28 +1,27 @@ -use std::{ - ffi::OsString, - io, mem, - os::windows::ffi::OsStringExt, - path::{Path, PathBuf}, - ptr, -}; +use once_cell::sync::OnceCell; +use std::{io, mem, path::PathBuf, ptr}; use widestring::{WideCStr, WideCString}; use windows_sys::{ core::{GUID, PWSTR}, Win32::{ - Foundation::{CloseHandle, ERROR_NO_TOKEN, ERROR_SUCCESS, HANDLE, LUID, S_OK}, + Foundation::{ + CloseHandle, ERROR_INSUFFICIENT_BUFFER, ERROR_SUCCESS, HANDLE, INVALID_HANDLE_VALUE, + LUID, S_OK, + }, Security::{ - AdjustTokenPrivileges, ImpersonateSelf, LookupPrivilegeValueW, RevertToSelf, - SecurityImpersonation, LUID_AND_ATTRIBUTES, SE_PRIVILEGE_ENABLED, - TOKEN_ADJUST_PRIVILEGES, TOKEN_DUPLICATE, TOKEN_IMPERSONATE, TOKEN_PRIVILEGES, - TOKEN_QUERY, + AdjustTokenPrivileges, CreateWellKnownSid, EqualSid, GetTokenInformation, + ImpersonateSelf, LookupPrivilegeValueW, RevertToSelf, SecurityImpersonation, TokenUser, + WinLocalSystemSid, LUID_AND_ATTRIBUTES, SE_PRIVILEGE_ENABLED, TOKEN_ADJUST_PRIVILEGES, + TOKEN_DUPLICATE, TOKEN_IMPERSONATE, TOKEN_PRIVILEGES, TOKEN_QUERY, TOKEN_USER, }, + Storage::FileSystem::MAX_SID_SIZE, System::{ Com::CoTaskMemFree, ProcessStatus::K32EnumProcesses, SystemServices::GENERIC_READ, Threading::{ GetCurrentThread, OpenProcess, OpenProcessToken, OpenThreadToken, - QueryFullProcessImageNameW, PROCESS_QUERY_INFORMATION, + PROCESS_QUERY_INFORMATION, }, }, UI::Shell::{ @@ -31,69 +30,89 @@ use windows_sys::{ }, }; -pub(crate) fn get_system_service_appdata() -> io::Result<PathBuf> { - get_system_service_known_folder(&FOLDERID_LocalAppData) +struct Handle(HANDLE); + +impl Drop for Handle { + fn drop(&mut self) { + if self.0 != 0 && self.0 != INVALID_HANDLE_VALUE { + unsafe { + CloseHandle(self.0); + } + } + } +} + +/// Get local AppData path for the system service user. +pub fn get_system_service_appdata() -> io::Result<PathBuf> { + static APPDATA_PATH: OnceCell<PathBuf> = OnceCell::new(); + + APPDATA_PATH + .get_or_try_init(|| { + let join_handle = std::thread::spawn(|| { + impersonate_self(|| { + let user_token = get_system_user_token()?; + get_known_folder_path(&FOLDERID_LocalAppData, KF_FLAG_DEFAULT, user_token.0) + }) + .or_else(|error| { + log::error!("Failed to get AppData path: {error}"); + infer_appdata_from_system_directory() + }) + }); + join_handle.join().unwrap() + }) + .cloned() } -/// Get local AppData path for the system service user. Requires elevated privileges to work. +/// Get user token for the system service user. Requires elevated privileges to work. /// Useful for deducing the config path for the daemon on Windows when running as a user that /// isn't the system service. -fn get_system_service_known_folder(known_folder_id: *const GUID) -> std::io::Result<PathBuf> { - let system_debug_priv = WideCString::from_str("SeDebugPrivilege").unwrap(); +/// If the current user is system, this function succeeds and returns a `NULL` handle; +fn get_system_user_token() -> io::Result<Handle> { + let thread_token = get_current_thread_token()?; - adjust_current_thread_token_privilege(&system_debug_priv, true)?; - let known_folder: io::Result<PathBuf> = (|| { - let mut lsass_path = get_known_folder_path(&FOLDERID_System, KF_FLAG_DEFAULT, 0)?; - lsass_path.push("lsass.exe"); + if is_local_system_user_token(thread_token.0)? { + return Ok(Handle(0)); + } - let lsass_pid = get_running_process_id_from_name(&lsass_path)?; - let lsass_handle = unsafe { OpenProcess(PROCESS_QUERY_INFORMATION, 0, lsass_pid) }; - if lsass_handle == 0 { - return Err(io::Error::new( - io::ErrorKind::NotFound, - format!( - "Failed to open process {:?} to query information", - lsass_handle - ), - )); - } + let system_debug_priv = WideCString::from_str("SeDebugPrivilege").unwrap(); + adjust_token_privilege(thread_token.0, &system_debug_priv, true)?; - let mut lsass_token: HANDLE = 0; - let status = unsafe { - OpenProcessToken( - lsass_handle, - GENERIC_READ | TOKEN_IMPERSONATE | TOKEN_DUPLICATE, - &mut lsass_token, - ) - }; - unsafe { CloseHandle(lsass_handle) }; - if status == 0 { - return Err(io::Error::new( - io::ErrorKind::PermissionDenied, - format!("Failed to open process token, failure code {}", status), - )); + let find_result = find_process(|process_handle| { + let process_token = open_process_token( + process_handle, + GENERIC_READ | TOKEN_IMPERSONATE | TOKEN_DUPLICATE, + ) + .ok()?; + + match is_local_system_user_token(process_token.0) { + Ok(true) => Some(process_token), + _ => None, } + }); - let known_folder = get_known_folder_path(known_folder_id, KF_FLAG_DEFAULT, lsass_token); - unsafe { CloseHandle(lsass_token) }; + if let Err(err) = adjust_token_privilege(thread_token.0, &system_debug_priv, false) { + log::error!("Failed to drop SeDebugPrivilege: {}", err); + } - known_folder - })(); + find_result +} - if let Err(err) = adjust_current_thread_token_privilege(&system_debug_priv, false) { - eprintln!("Failed to drop SeDebugPrivilege: {}", err); - } - if unsafe { RevertToSelf() } == 0 { +fn open_process_token(process: HANDLE, access: u32) -> io::Result<Handle> { + let mut process_token = 0; + if unsafe { OpenProcessToken(process, access, &mut process_token) } == 0 { return Err(io::Error::last_os_error()); } + Ok(Handle(process_token)) +} - known_folder +/// If all else fails, infer the AppData path from the system directory. +fn infer_appdata_from_system_directory() -> io::Result<PathBuf> { + let mut sysdir = get_known_folder_path(&FOLDERID_System, KF_FLAG_DEFAULT, 0)?; + sysdir.extend(["config", "systemprofile", "AppData", "Local"]); + Ok(sysdir) } -fn adjust_current_thread_token_privilege( - privilege: &WideCStr, - enable: bool, -) -> std::io::Result<()> { +fn get_current_thread_token() -> std::io::Result<Handle> { let mut token_handle: HANDLE = 0; if unsafe { OpenThreadToken( @@ -104,30 +123,22 @@ fn adjust_current_thread_token_privilege( ) } == 0 { - let thread_token_error = std::io::Error::last_os_error(); - if thread_token_error.raw_os_error() == Some(ERROR_NO_TOKEN as i32) { - if unsafe { ImpersonateSelf(SecurityImpersonation) } == 0 { - return Err(std::io::Error::last_os_error()); - } + return Err(std::io::Error::last_os_error()); + } + Ok(Handle(token_handle)) +} - if unsafe { - OpenThreadToken( - GetCurrentThread(), - TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, - 0, - &mut token_handle, - ) - } == 0 - { - return Err(std::io::Error::last_os_error()); - } - } else { - return Err(thread_token_error); - } +fn impersonate_self<T>(func: impl FnOnce() -> io::Result<T>) -> io::Result<T> { + if unsafe { ImpersonateSelf(SecurityImpersonation) } == 0 { + return Err(std::io::Error::last_os_error()); + } + + let result = func(); + + if unsafe { RevertToSelf() } == 0 { + log::error!("RevertToSelf failed: {}", io::Error::last_os_error()); } - let result = adjust_token_privilege(token_handle, privilege, enable); - unsafe { CloseHandle(token_handle) }; result } @@ -178,7 +189,7 @@ fn get_known_folder_path( let status = unsafe { SHGetKnownFolderPath(folder_id, flags, user_token, &mut folder_path) }; let result = if status == S_OK { let path = unsafe { WideCStr::from_ptr_str(folder_path) }; - Ok(path.to_ustring().to_os_string().into()) + Ok(PathBuf::from(path.to_os_string())) } else { Err(io::Error::new( io::ErrorKind::NotFound, @@ -190,17 +201,12 @@ fn get_known_folder_path( result } -/// Find the PID of a process with the given image path. In case of multiple processes matching -/// the path, the first one found to match the path will be returned - the ordering of PIDs is -/// determined by `K32EnumProcesses`. -fn get_running_process_id_from_name(target_name: &Path) -> io::Result<u32> { - let mut num_procs: u32 = 2048; - let mut pid_buffer = vec![]; - let canonical_target = target_name - .canonicalize() - .unwrap_or(target_name.to_path_buf()); +/// Enumerate over all processes until `handle_process` returns a result or until there are +/// no more processes left. In the latter case, an error is returned. +fn find_process<T>(handle_process: impl Fn(HANDLE) -> Option<T>) -> io::Result<T> { + let mut pid_buffer = vec![0u32; 2048]; + let mut num_procs: u32 = u32::try_from(pid_buffer.len()).unwrap(); - pid_buffer.resize(num_procs as usize, 0); let bytes_available = num_procs * (mem::size_of::<u32>() as u32); let mut bytes_written = 0; if unsafe { K32EnumProcesses(pid_buffer.as_mut_ptr(), bytes_available, &mut bytes_written) } @@ -212,46 +218,73 @@ fn get_running_process_id_from_name(target_name: &Path) -> io::Result<u32> { num_procs = bytes_written / (mem::size_of::<u32>() as u32); pid_buffer.resize(num_procs as usize, 0); - for process in pid_buffer { - let process_handle = unsafe { OpenProcess(PROCESS_QUERY_INFORMATION, 0, process) }; - if process_handle == 0 { - eprintln!( - "Failed to open process {}: {}", - process, - io::Error::last_os_error() - ); - continue; - } + pid_buffer + .into_iter() + .find_map(|process| { + let process_handle = + Handle(unsafe { OpenProcess(PROCESS_QUERY_INFORMATION, 0, process) }); + if process_handle.0 == 0 { + return None; + } + handle_process(process_handle.0) + }) + .ok_or(io::Error::new( + io::ErrorKind::NotFound, + "Could not find matching process", + )) +} + +fn is_local_system_user_token(token: HANDLE) -> io::Result<bool> { + let mut token_info = vec![0u8; 1024]; - let mut process_name = vec![0u16; 512]; - let mut process_name_size = process_name.len() as u32; + loop { + let mut returned_info_len = 0; - let status = unsafe { - QueryFullProcessImageNameW( - process_handle, - 0, - process_name.as_mut_ptr(), - &mut process_name_size, + let info_result = unsafe { + GetTokenInformation( + token, + TokenUser, + token_info.as_mut_ptr() as _, + u32::try_from(token_info.len()).expect("len must fit in u32"), + &mut returned_info_len, ) }; - unsafe { CloseHandle(process_handle) }; - if 0 == status || process_name_size == 0 { - continue; - }; + let err = io::Error::last_os_error(); + if info_result == 0 && err.raw_os_error() != Some(ERROR_INSUFFICIENT_BUFFER as i32) { + log::error!("Failed to obtain token information: {}", err); + return Err(err); + } - process_name.resize(process_name_size as usize, 0u16); + token_info.resize( + usize::try_from(returned_info_len).expect("u32 must fit in usize"), + 0, + ); + if info_result != 0 { + break; + } + } - let process_path = PathBuf::from(OsString::from_wide(&process_name)); - let canonical_process_path = process_path.canonicalize().unwrap_or(process_path); + // SAFETY: We specified `TokenUser` as the class, so that is what GetTokenInformation should + // return. This reference is valid for as long as `token_info` is valid. + let token_user = unsafe { &*(token_info.as_mut_ptr() as *const TOKEN_USER) }; - if canonical_target == canonical_process_path { - return Ok(process); - } + let mut local_system_sid = [0u8; MAX_SID_SIZE as usize]; + let mut local_system_size = u32::try_from(local_system_sid.len()).unwrap(); + + if unsafe { + CreateWellKnownSid( + WinLocalSystemSid, + std::ptr::null_mut(), + local_system_sid.as_mut_ptr() as _, + &mut local_system_size, + ) + } == 0 + { + let err = io::Error::last_os_error(); + log::error!("CreateWellKnownSid failed: {}", err); + return Err(err); } - Err(io::Error::new( - io::ErrorKind::NotFound, - format!("Process ID for {} not found", target_name.to_string_lossy()), - )) + Ok(unsafe { EqualSid(token_user.User.Sid, local_system_sid.as_ptr() as _) } != 0) } diff --git a/windows/nsis-plugins/src/cleanup/cleaningops.cpp b/windows/nsis-plugins/src/cleanup/cleaningops.cpp index 2a29e8dd1c..831cf96bf3 100644 --- a/windows/nsis-plugins/src/cleanup/cleaningops.cpp +++ b/windows/nsis-plugins/src/cleanup/cleaningops.cpp @@ -12,6 +12,7 @@ #include <utility> #include <functional> #include <processthreadsapi.h> +#include <mullvad-nsis.h> namespace { @@ -66,43 +67,25 @@ std::wstring ConstructUserPath(const std::wstring &users, const std::wstring &us std::wstring GetSystemUserLocalAppData() { - common::security::AdjustCurrentProcessTokenPrivilege(L"SeDebugPrivilege"); + std::vector<uint16_t> buffer(256); + size_t bufferSize = buffer.size(); - common::memory::ScopeDestructor sd; +GET_LOCAL_APPDATA: - sd += [] - { - common::security::AdjustCurrentProcessTokenPrivilege(L"SeDebugPrivilege", false); - }; - - auto systemDir = common::fs::GetKnownFolderPath(FOLDERID_System); - auto lsassPath = std::filesystem::path(systemDir).append(L"lsass.exe"); - auto lsassPid = common::process::GetProcessIdFromName(lsassPath); + auto result = get_system_local_appdata(buffer.data(), &bufferSize); - auto processHandle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, lsassPid); - - if (nullptr == processHandle) + if (Status::InsufficientBufferSize == result) { - THROW_ERROR("Failed to access the \"LSASS\" process"); + buffer.resize(bufferSize); + goto GET_LOCAL_APPDATA; } - HANDLE processToken; - - auto status = OpenProcessToken(processHandle, TOKEN_READ | TOKEN_IMPERSONATE | TOKEN_DUPLICATE, &processToken); - - CloseHandle(processHandle); - - if (FALSE == status) + if (Status::Ok != result) { - THROW_ERROR("Failed to acquire process token for the \"LSASS\" process"); + THROW_ERROR("Failed to acquire system app data path"); } - sd += [&]() - { - CloseHandle(processToken); - }; - - return common::fs::GetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_DEFAULT, processToken); + return std::wstring(reinterpret_cast<wchar_t *>(buffer.data())); } std::filesystem::path GetSystemCacheDirectory() diff --git a/windows/nsis-plugins/src/cleanup/cleanup.vcxproj b/windows/nsis-plugins/src/cleanup/cleanup.vcxproj index 879866e530..287c7ab418 100644 --- a/windows/nsis-plugins/src/cleanup/cleanup.vcxproj +++ b/windows/nsis-plugins/src/cleanup/cleanup.vcxproj @@ -61,7 +61,7 @@ <SDLCheck>true</SDLCheck> <PreprocessorDefinitions>WIN32;_DEBUG;CLEANUP_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ConformanceMode>true</ConformanceMode> - <AdditionalIncludeDirectories>$(ProjectDir)../../../../dist-assets/binaries/x86_64-pc-windows-msvc/;$(ProjectDir)../../../windows-libraries/src/</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>$(ProjectDir)../../../../mullvad-nsis/include;$(ProjectDir)../../../../dist-assets/binaries/x86_64-pc-windows-msvc/;$(ProjectDir)../../../windows-libraries/src/</AdditionalIncludeDirectories> <LanguageStandard>stdcpplatest</LanguageStandard> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> </ClCompile> @@ -69,11 +69,15 @@ <SubSystem>Windows</SubSystem> <GenerateDebugInformation>true</GenerateDebugInformation> <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> - <AdditionalLibraryDirectories>$(ProjectDir)../../../../dist-assets/binaries/x86_64-pc-windows-msvc/nsis/;$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories> - <AdditionalDependencies>libcommon.lib;pluginapi-x86-unicode.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;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalLibraryDirectories>$(ProjectDir)../../../../target/i686-pc-windows-msvc/release;$(ProjectDir)../../../../dist-assets/binaries/x86_64-pc-windows-msvc/nsis/;$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories> + <AdditionalDependencies>mullvad_nsis.lib;libcommon.lib;pluginapi-x86-unicode.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;%(AdditionalDependencies)</AdditionalDependencies> <IgnoreSpecificDefaultLibraries>libc.lib</IgnoreSpecificDefaultLibraries> <ModuleDefinitionFile>cleanup.def</ModuleDefinitionFile> </Link> + <PreBuildEvent> + <Command>cargo build --target i686-pc-windows-msvc --release -p mullvad-nsis</Command> + <Message>Build mullvad-nsis library</Message> + </PreBuildEvent> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ClCompile> @@ -85,7 +89,7 @@ <SDLCheck>true</SDLCheck> <PreprocessorDefinitions>WIN32;NDEBUG;CLEANUP_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ConformanceMode>true</ConformanceMode> - <AdditionalIncludeDirectories>$(ProjectDir)../../../../dist-assets/binaries/x86_64-pc-windows-msvc/;$(ProjectDir)../../../windows-libraries/src/</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>$(ProjectDir)../../../../mullvad-nsis/include;$(ProjectDir)../../../../dist-assets/binaries/x86_64-pc-windows-msvc/;$(ProjectDir)../../../windows-libraries/src/</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <LanguageStandard>stdcpplatest</LanguageStandard> </ClCompile> @@ -95,11 +99,15 @@ <OptimizeReferences>true</OptimizeReferences> <GenerateDebugInformation>true</GenerateDebugInformation> <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> - <AdditionalLibraryDirectories>$(ProjectDir)../../../../dist-assets/binaries/x86_64-pc-windows-msvc/nsis/;$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories> - <AdditionalDependencies>libcommon.lib;pluginapi-x86-unicode.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;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalLibraryDirectories>$(ProjectDir)../../../../target/i686-pc-windows-msvc/release;$(ProjectDir)../../../../dist-assets/binaries/x86_64-pc-windows-msvc/nsis/;$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories> + <AdditionalDependencies>mullvad_nsis.lib;libcommon.lib;pluginapi-x86-unicode.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;%(AdditionalDependencies)</AdditionalDependencies> <IgnoreSpecificDefaultLibraries>libc.lib</IgnoreSpecificDefaultLibraries> <ModuleDefinitionFile>cleanup.def</ModuleDefinitionFile> </Link> + <PreBuildEvent> + <Command>cargo build --target i686-pc-windows-msvc --release -p mullvad-nsis</Command> + <Message>Build mullvad-nsis library</Message> + </PreBuildEvent> </ItemDefinitionGroup> <ItemGroup> <ClInclude Include="cleaningops.h" /> |
