summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/daemon.yml1
-rw-r--r--CHANGELOG.md3
-rw-r--r--Cargo.lock52
-rw-r--r--Cargo.toml1
-rw-r--r--mullvad-nsis/Cargo.toml17
-rw-r--r--mullvad-nsis/build.rs14
-rw-r--r--mullvad-nsis/include/mullvad-nsis.h24
-rw-r--r--mullvad-nsis/src/lib.rs58
-rw-r--r--mullvad-paths/Cargo.toml2
-rw-r--r--mullvad-paths/src/lib.rs2
-rw-r--r--mullvad-paths/src/windows.rs281
-rw-r--r--windows/nsis-plugins/src/cleanup/cleaningops.cpp39
-rw-r--r--windows/nsis-plugins/src/cleanup/cleanup.vcxproj20
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" />