feat: add getting admin to cross, knock out a todo
This commit is contained in:
parent
9cfb73d19c
commit
95a5c3f565
5 changed files with 139 additions and 5 deletions
|
|
@ -10,10 +10,12 @@ impl Command for Ash {
|
|||
fn execute(&self) {
|
||||
loop {
|
||||
let path = env::current_dir();
|
||||
print!(
|
||||
"{} $ ", // TODO: display "#" if root
|
||||
path.expect("unknown").display()
|
||||
);
|
||||
let userchar = if boxutils::cross::user::is_admin() {
|
||||
'#'
|
||||
} else {
|
||||
'$'
|
||||
};
|
||||
print!("{} {} ", path.expect("unknown").display(), userchar);
|
||||
let _ = io::stdout().flush();
|
||||
let mut input = String::new();
|
||||
io::stdin().read_line(&mut input).unwrap();
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
pub mod fs;
|
||||
pub mod fs;
|
||||
pub mod user;
|
||||
11
utils/src/cross/user/mod.rs
Normal file
11
utils/src/cross/user/mod.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#[cfg(windows)]
|
||||
mod win;
|
||||
|
||||
#[cfg(windows)]
|
||||
pub use win::*;
|
||||
|
||||
#[cfg(unix)]
|
||||
mod unix;
|
||||
|
||||
#[cfg(unix)]
|
||||
pub use unix::*;
|
||||
37
utils/src/cross/user/unix.rs
Normal file
37
utils/src/cross/user/unix.rs
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#![cfg(unix)]
|
||||
|
||||
use std::fs;
|
||||
use std::process::Command;
|
||||
|
||||
/// A safe wrapper for checking if the user is root.
|
||||
struct UserPrivileges;
|
||||
|
||||
impl UserPrivileges {
|
||||
fn is_root() -> bool {
|
||||
if let Ok(status) = fs::read_to_string("/proc/self/status") {
|
||||
for line in status.lines() {
|
||||
if line.starts_with("Uid:") {
|
||||
let uid: u32 = line
|
||||
.split_whitespace()
|
||||
.nth(1)
|
||||
.unwrap_or("1")
|
||||
.parse()
|
||||
.unwrap_or(1);
|
||||
return uid == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: Run `id -u`
|
||||
Command::new("id")
|
||||
.arg("-u")
|
||||
.output()
|
||||
.map(|o| o.stdout == b"0\n")
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
/// Safe function to check if the user has root privileges.
|
||||
pub fn is_admin() -> bool {
|
||||
UserPrivileges::is_root()
|
||||
}
|
||||
83
utils/src/cross/user/win.rs
Normal file
83
utils/src/cross/user/win.rs
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
#![allow(dead_code)]
|
||||
#![cfg(windows)]
|
||||
|
||||
use std::ptr;
|
||||
use std::ffi::c_void;
|
||||
use std::mem::{size_of, zeroed};
|
||||
use std::os::raw::c_ulong;
|
||||
|
||||
#[link(name = "advapi32")]
|
||||
unsafe extern "system" {
|
||||
fn OpenProcessToken(process: *mut c_void, access: c_ulong, token: *mut *mut c_void) -> i32;
|
||||
fn GetTokenInformation(
|
||||
token_handle: *mut c_void,
|
||||
token_info_class: c_ulong,
|
||||
token_info: *mut c_void,
|
||||
token_info_length: c_ulong,
|
||||
return_length: *mut c_ulong,
|
||||
) -> i32;
|
||||
fn GetCurrentProcess() -> *mut c_void;
|
||||
fn CloseHandle(handle: *mut c_void) -> i32;
|
||||
}
|
||||
|
||||
const TOKEN_QUERY: c_ulong = 0x0008;
|
||||
const TOKEN_ELEVATION: c_ulong = 20;
|
||||
|
||||
#[repr(C)]
|
||||
struct TokenElevation {
|
||||
token_is_elevated: c_ulong,
|
||||
}
|
||||
|
||||
/// A safe wrapper around a Windows access token handle.
|
||||
struct AccessToken {
|
||||
handle: *mut c_void,
|
||||
}
|
||||
|
||||
impl AccessToken {
|
||||
/// Opens the access token for the current process.
|
||||
fn open() -> Option<Self> {
|
||||
let process = unsafe { GetCurrentProcess() };
|
||||
let mut token_handle: *mut c_void = ptr::null_mut();
|
||||
|
||||
let success = unsafe { OpenProcessToken(process, TOKEN_QUERY, &mut token_handle) };
|
||||
if success == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(Self { handle: token_handle })
|
||||
}
|
||||
|
||||
/// Checks if the token is elevated (i.e., running as an administrator).
|
||||
fn is_elevated(&self) -> bool {
|
||||
let mut elevation: TokenElevation = unsafe { zeroed() };
|
||||
let mut return_length: c_ulong = 0;
|
||||
|
||||
let success = unsafe {
|
||||
GetTokenInformation(
|
||||
self.handle,
|
||||
TOKEN_ELEVATION,
|
||||
&mut elevation as *mut _ as *mut c_void,
|
||||
size_of::<TokenElevation>() as c_ulong,
|
||||
&mut return_length,
|
||||
)
|
||||
};
|
||||
|
||||
success != 0 && elevation.token_is_elevated != 0
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for AccessToken {
|
||||
/// Ensures the token handle is always closed properly.
|
||||
fn drop(&mut self) {
|
||||
unsafe { CloseHandle(self.handle) };
|
||||
}
|
||||
}
|
||||
|
||||
/// Safe function to check if the user is an administrator.
|
||||
pub fn is_admin() -> bool {
|
||||
if let Some(token) = AccessToken::open() {
|
||||
token.is_elevated()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue