use std::io::Error;
use windows_sys::Win32::Foundation::{CloseHandle, HANDLE};
use windows_sys::Win32::Security::GetTokenInformation;
use windows_sys::Win32::Security::{TokenElevation, TOKEN_ELEVATION, TOKEN_QUERY};
use windows_sys::Win32::System::Threading::{GetCurrentProcess, OpenProcessToken};
use super::Privilege;
pub fn get_privilege() -> Privilege {
match is_elevated() {
Ok(true) => Privilege::Root,
Ok(false) => Privilege::User,
Err(_) => Privilege::User,
}
}
fn is_elevated() -> Result<bool, Error> {
let token = QueryAccessToken::from_current_process()?;
token.is_elevated()
}
struct QueryAccessToken(HANDLE);
impl QueryAccessToken {
fn from_current_process() -> Result<Self, Error> {
unsafe {
let mut handle = HANDLE::default();
if OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &mut handle) != 0 {
Ok(Self(handle))
} else {
Err(Error::last_os_error())
}
}
}
fn is_elevated(&self) -> Result<bool, Error> {
unsafe {
let mut elevation: TOKEN_ELEVATION = TOKEN_ELEVATION { TokenIsElevated: 0 };
let size = std::mem::size_of::<TOKEN_ELEVATION>() as u32;
let mut ret_size = size;
if GetTokenInformation(
self.0,
TokenElevation,
&mut elevation as *const _ as *mut _,
size,
&mut ret_size,
) != 0
{
Ok(elevation.TokenIsElevated != 0)
} else {
Err(Error::last_os_error())
}
}
}
}
impl Drop for QueryAccessToken {
fn drop(&mut self) {
unsafe { CloseHandle(self.0) };
}
}