Add pw module for user and group information;

which - check if our user can exec found file
This commit is contained in:
Nathan Fisher 2023-01-11 20:50:20 -05:00
parent cbe8b09c64
commit d77387f963
4 changed files with 103 additions and 15 deletions

View File

@ -246,20 +246,7 @@ impl BootstrapCmd for dyn Cmd {
let mut path = PathBuf::from(prefix); let mut path = PathBuf::from(prefix);
let binpath = self.path(); let binpath = self.path();
match binpath { match binpath {
Some(crate::Path::Bin) => path.push("bin"), Some(p) => path.push(p.to_str(usr)),
Some(crate::Path::Sbin) => path.push("sbin"),
Some(crate::Path::UsrBin) => {
if usr {
path.push("usr");
}
path.push("bin");
}
Some(crate::Path::UsrSbin) => {
if usr {
path.push("usr");
}
path.push("sbin");
}
None => return None, None => return None,
} }
path.push(self.name()); path.push(self.name());

View File

@ -62,7 +62,23 @@ fn which(command: &str, path: &[&str]) -> Option<String> {
if let Ok(exe) = File::open(&file) { if let Ok(exe) = File::open(&file) {
if let Ok(meta) = exe.metadata() { if let Ok(meta) = exe.metadata() {
let mode = meta.mode(); let mode = meta.mode();
if mode & 0o111 != 0 { let myuid = unsafe {
libc::geteuid()
};
let mygroups = crate::pw::get_gids();
// we own the file and it has u+x
if myuid == meta.uid() && mode & 0o100 != 0 {
return Some(format!("{}", file.display()));
// file has ug+x
} else if mode & 0o110 != 0 {
if let Ok(groups) = mygroups {
// one of our groups owns the file
if groups.contains(&meta.gid()) {
return Some(format!("{}", file.display()));
}
}
// the file has uga+x
} else if mode & 0o111 != 0 {
return Some(format!("{}", file.display())); return Some(format!("{}", file.display()));
} }
} }

View File

@ -4,6 +4,8 @@ use std::{env, error::Error, path::PathBuf, process, string::ToString};
pub mod cmd; pub mod cmd;
pub use cmd::Cmd; pub use cmd::Cmd;
pub mod math; pub mod math;
/// User and group related functionality
pub mod pw;
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum Path { pub enum Path {
@ -13,6 +15,19 @@ pub enum Path {
UsrSbin, UsrSbin,
} }
impl Path {
pub fn to_str(&self, usr: bool) -> &'static str {
match self {
Self::Bin => "bin",
Self::UsrBin if usr => "usr/bin",
Self::UsrBin => "bin",
Self::Sbin => "sbin",
Self::UsrSbin if usr => "usr/sbin",
Self::UsrSbin => "sbin",
}
}
}
#[must_use] #[must_use]
pub fn progname() -> Option<String> { pub fn progname() -> Option<String> {
env::args() env::args()

70
src/pw/mod.rs Normal file
View File

@ -0,0 +1,70 @@
use std::{error::Error, ffi::CStr, num};
pub fn get_username<'a>() -> Result<&'a str, std::str::Utf8Error> {
let user = unsafe {
let uid = libc::getuid();
let pw = libc::getpwuid(uid);
let name = (*pw).pw_name;
CStr::from_ptr(name)
};
user.to_str()
}
pub fn get_eusername<'a>() -> Result<&'a str, std::str::Utf8Error> {
let user = unsafe {
let uid = libc::geteuid();
let pw = libc::getpwuid(uid);
let name = (*pw).pw_name;
CStr::from_ptr(name)
};
user.to_str()
}
pub fn get_grpname<'a>() -> Result<&'a str, std::str::Utf8Error> {
let group = unsafe {
let gid = libc::getgid();
let gr = libc::getgrgid(gid);
let name = (*gr).gr_name;
CStr::from_ptr(name)
};
group.to_str()
}
pub fn get_egrpname<'a>() -> Result<&'a str, std::str::Utf8Error> {
let group = unsafe {
let gid = libc::getegid();
let gr = libc::getgrgid(gid);
let name = (*gr).gr_name;
CStr::from_ptr(name)
};
group.to_str()
}
pub fn get_gids() -> Result<Vec<u32>, num::TryFromIntError> {
let mut buf: Vec<libc::gid_t>;
unsafe {
buf = vec![0; 1];
let num = libc::getgroups(0, buf.as_mut_ptr());
buf = vec![0; num.try_into()?];
let _num = libc::getgroups(num, buf.as_mut_ptr());
buf.push(libc::getegid());
};
buf.dedup();
Ok(buf)
}
pub fn get_group_names() -> Result<Vec<String>, Box<dyn Error>> {
let gids = get_gids()?;
let mut names = vec![];
for id in gids {
let name = unsafe {
let gr = libc::getgrgid(id);
let name = (*gr).gr_name;
// if we don't take ownership here the OS can (and will)
// reuse the memory
CStr::from_ptr(name).to_str()?.to_string()
};
names.push(name);
}
Ok(names)
}