mirror of https://github.com/ospab/ostp.git
feat: absolute dynamic Windows elevation using native ShellExecuteW (runas)
This commit is contained in:
parent
c2407f3637
commit
92c044217f
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue