feat: absolute dynamic Windows elevation using native ShellExecuteW (runas)

This commit is contained in:
ospab 2026-05-15 16:41:20 +03:00
parent c2407f3637
commit 92c044217f
1 changed files with 47 additions and 20 deletions

View File

@ -44,31 +44,58 @@ fn is_admin() -> bool {
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
fn relaunch_as_admin() -> Result<()> { fn relaunch_as_admin() -> Result<()> {
let current_exe = std::env::current_exe()?; use std::ffi::OsStr;
let exe_str = current_exe.to_string_lossy().replace('\'', "''"); use std::os::windows::ffi::OsStrExt;
use std::ptr::null_mut;
let current_dir = std::env::current_dir()?;
let dir_str = current_dir.to_string_lossy().replace('\'', "''");
let mut arg_parts = Vec::new(); let exe = std::env::current_exe()?;
let exe_wstr: Vec<u16> = exe.as_os_str().encode_wide().chain(Some(0)).collect();
let mut args_joined = String::new();
for arg in std::env::args().skip(1) { for arg in std::env::args().skip(1) {
arg_parts.push(format!("'{}'", arg.replace('\'', "''"))); if !args_joined.is_empty() {
args_joined.push(' ');
}
args_joined.push('"');
args_joined.push_str(&arg.replace('"', "\\\""));
args_joined.push('"');
}
let args_wstr: Vec<u16> = OsStr::new(&args_joined).encode_wide().chain(Some(0)).collect();
let dir = std::env::current_dir()?;
let dir_wstr: Vec<u16> = dir.as_os_str().encode_wide().chain(Some(0)).collect();
let verb_wstr: Vec<u16> = OsStr::new("runas").encode_wide().chain(Some(0)).collect();
#[link(name = "shell32")]
extern "system" {
fn ShellExecuteW(
hwnd: *mut std::ffi::c_void,
lpOperation: *const u16,
lpFile: *const u16,
lpParameters: *const u16,
lpDirectory: *const u16,
nShowCmd: i32,
) -> isize;
} }
let arg_list_str = if !arg_parts.is_empty() { unsafe {
format!("-ArgumentList {}", arg_parts.join(",")) let ret = ShellExecuteW(
} else { null_mut(),
String::new() verb_wstr.as_ptr(),
}; exe_wstr.as_ptr(),
args_wstr.as_ptr(),
dir_wstr.as_ptr(),
1, // SW_SHOWNORMAL = 1
);
if ret <= 32 {
return Err(anyhow::anyhow!(
"Windows UAC Elevation failed or was denied by policy (ShellExecuteW code: {})",
ret
));
}
}
let ps_script = format!(
"Start-Process -FilePath '{}' {} -WorkingDirectory '{}' -Verb RunAs",
exe_str, arg_list_str, dir_str
);
let _ = std::process::Command::new("powershell")
.args(["-Command", &ps_script])
.status()?;
std::process::exit(0); std::process::exit(0);
} }