use crate::platform::elevated_cli_args;
use crate::platform::traits::{ElevationCapability, PrivilegeOps};
use std::ffi::OsStr;
use std::mem;
use std::os::windows::ffi::OsStrExt;
use std::ptr;
use winapi::um::handleapi::CloseHandle;
use winapi::um::processthreadsapi::{GetCurrentProcess, OpenProcessToken};
use winapi::um::securitybaseapi::GetTokenInformation;
use winapi::um::shellapi::ShellExecuteW;
use winapi::um::winnt::{TokenElevation, TOKEN_ELEVATION, TOKEN_QUERY};
use winapi::um::winuser::SW_SHOW;
use super::WindowsPlatform;
impl PrivilegeOps for WindowsPlatform {
fn elevation_method() -> &'static str {
"uac"
}
fn is_elevated() -> bool {
unsafe {
let mut token = ptr::null_mut();
if OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &mut token) == 0 {
return false;
}
let mut elevation = TOKEN_ELEVATION { TokenIsElevated: 0 };
let mut size = 0;
let ok = GetTokenInformation(
token,
TokenElevation,
&mut elevation as *mut _ as *mut _,
mem::size_of::<TOKEN_ELEVATION>() as u32,
&mut size,
);
CloseHandle(token);
ok != 0 && elevation.TokenIsElevated != 0
}
}
fn elevation_capability() -> ElevationCapability {
if Self::is_elevated() {
ElevationCapability {
ready: true,
status_label: "elevated",
}
} else {
ElevationCapability {
ready: true,
status_label: "UAC available",
}
}
}
fn validate_elevation_prerequisites() -> Result<(), String> {
Ok(())
}
fn elevation_dialog_lines() -> [&'static str; 3] {
[
"Flash and clone operations require administrator access.",
"You will be prompted by User Account Control (UAC).",
"This window will close and a new elevated session will start.",
]
}
fn relaunch_elevated(mode: &str, device: &str, image: &str) -> Result<(), String> {
if Self::is_elevated() {
return Err("Already running with administrator privileges.".into());
}
let exe =
std::env::current_exe().map_err(|e| format!("Could not resolve executable: {e}"))?;
let parameters = windows_command_line(&elevated_cli_args(mode, device, image));
let status = unsafe {
ShellExecuteW(
ptr::null_mut(),
wide("runas").as_ptr(),
wide(&exe.to_string_lossy()).as_ptr(),
wide(¶meters).as_ptr(),
ptr::null(),
SW_SHOW,
)
};
if (status as isize) <= 32 {
return Err(format!(
"UAC elevation was denied or failed (ShellExecute code {}). \
Try running litho-tui from an elevated terminal.",
status as isize
));
}
Ok(())
}
}
fn windows_command_line(args: &[String]) -> String {
args.iter()
.map(|arg| {
if arg.chars().any(|c| c.is_whitespace() || c == '"') {
format!("\"{}\"", arg.replace('"', "\\\""))
} else {
arg.clone()
}
})
.collect::<Vec<_>>()
.join(" ")
}
fn wide(value: &str) -> Vec<u16> {
OsStr::new(value).encode_wide().chain(Some(0)).collect()
}