Skip to content

Commit 95a5c3f

Browse files
committed
feat: add getting admin to cross, knock out a todo
1 parent 9cfb73d commit 95a5c3f

File tree

5 files changed

+139
-5
lines changed

5 files changed

+139
-5
lines changed

shell/src/ash.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@ impl Command for Ash {
1010
fn execute(&self) {
1111
loop {
1212
let path = env::current_dir();
13-
print!(
14-
"{} $ ", // TODO: display "#" if root
15-
path.expect("unknown").display()
16-
);
13+
let userchar = if boxutils::cross::user::is_admin() {
14+
'#'
15+
} else {
16+
'$'
17+
};
18+
print!("{} {} ", path.expect("unknown").display(), userchar);
1719
let _ = io::stdout().flush();
1820
let mut input = String::new();
1921
io::stdin().read_line(&mut input).unwrap();

utils/src/cross/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
pub mod fs;
1+
pub mod fs;
2+
pub mod user;

utils/src/cross/user/mod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#[cfg(windows)]
2+
mod win;
3+
4+
#[cfg(windows)]
5+
pub use win::*;
6+
7+
#[cfg(unix)]
8+
mod unix;
9+
10+
#[cfg(unix)]
11+
pub use unix::*;

utils/src/cross/user/unix.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#![cfg(unix)]
2+
3+
use std::fs;
4+
use std::process::Command;
5+
6+
/// A safe wrapper for checking if the user is root.
7+
struct UserPrivileges;
8+
9+
impl UserPrivileges {
10+
fn is_root() -> bool {
11+
if let Ok(status) = fs::read_to_string("/proc/self/status") {
12+
for line in status.lines() {
13+
if line.starts_with("Uid:") {
14+
let uid: u32 = line
15+
.split_whitespace()
16+
.nth(1)
17+
.unwrap_or("1")
18+
.parse()
19+
.unwrap_or(1);
20+
return uid == 0;
21+
}
22+
}
23+
}
24+
25+
// Fallback: Run `id -u`
26+
Command::new("id")
27+
.arg("-u")
28+
.output()
29+
.map(|o| o.stdout == b"0\n")
30+
.unwrap_or(false)
31+
}
32+
}
33+
34+
/// Safe function to check if the user has root privileges.
35+
pub fn is_admin() -> bool {
36+
UserPrivileges::is_root()
37+
}

utils/src/cross/user/win.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#![allow(dead_code)]
2+
#![cfg(windows)]
3+
4+
use std::ptr;
5+
use std::ffi::c_void;
6+
use std::mem::{size_of, zeroed};
7+
use std::os::raw::c_ulong;
8+
9+
#[link(name = "advapi32")]
10+
unsafe extern "system" {
11+
fn OpenProcessToken(process: *mut c_void, access: c_ulong, token: *mut *mut c_void) -> i32;
12+
fn GetTokenInformation(
13+
token_handle: *mut c_void,
14+
token_info_class: c_ulong,
15+
token_info: *mut c_void,
16+
token_info_length: c_ulong,
17+
return_length: *mut c_ulong,
18+
) -> i32;
19+
fn GetCurrentProcess() -> *mut c_void;
20+
fn CloseHandle(handle: *mut c_void) -> i32;
21+
}
22+
23+
const TOKEN_QUERY: c_ulong = 0x0008;
24+
const TOKEN_ELEVATION: c_ulong = 20;
25+
26+
#[repr(C)]
27+
struct TokenElevation {
28+
token_is_elevated: c_ulong,
29+
}
30+
31+
/// A safe wrapper around a Windows access token handle.
32+
struct AccessToken {
33+
handle: *mut c_void,
34+
}
35+
36+
impl AccessToken {
37+
/// Opens the access token for the current process.
38+
fn open() -> Option<Self> {
39+
let process = unsafe { GetCurrentProcess() };
40+
let mut token_handle: *mut c_void = ptr::null_mut();
41+
42+
let success = unsafe { OpenProcessToken(process, TOKEN_QUERY, &mut token_handle) };
43+
if success == 0 {
44+
return None;
45+
}
46+
47+
Some(Self { handle: token_handle })
48+
}
49+
50+
/// Checks if the token is elevated (i.e., running as an administrator).
51+
fn is_elevated(&self) -> bool {
52+
let mut elevation: TokenElevation = unsafe { zeroed() };
53+
let mut return_length: c_ulong = 0;
54+
55+
let success = unsafe {
56+
GetTokenInformation(
57+
self.handle,
58+
TOKEN_ELEVATION,
59+
&mut elevation as *mut _ as *mut c_void,
60+
size_of::<TokenElevation>() as c_ulong,
61+
&mut return_length,
62+
)
63+
};
64+
65+
success != 0 && elevation.token_is_elevated != 0
66+
}
67+
}
68+
69+
impl Drop for AccessToken {
70+
/// Ensures the token handle is always closed properly.
71+
fn drop(&mut self) {
72+
unsafe { CloseHandle(self.handle) };
73+
}
74+
}
75+
76+
/// Safe function to check if the user is an administrator.
77+
pub fn is_admin() -> bool {
78+
if let Some(token) = AccessToken::open() {
79+
token.is_elevated()
80+
} else {
81+
false
82+
}
83+
}

0 commit comments

Comments
 (0)