207 lines
6.0 KiB
Rust
207 lines
6.0 KiB
Rust
#![warn(clippy::all, clippy::pedantic)]
|
|
#![allow(clippy::missing_errors_doc, clippy::must_use_candidate)]
|
|
//! Wraps certain libc functions around groups and users
|
|
use std::{
|
|
error::Error,
|
|
ffi::{c_int, CStr, CString},
|
|
io, num,
|
|
};
|
|
|
|
/// Gets the current username of this process
|
|
/// # Errors
|
|
/// The user name must be valid utf8
|
|
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()
|
|
}
|
|
|
|
/// Gets the current effective user name of this process
|
|
/// # Errors
|
|
/// The user name must be valid utf8
|
|
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_username_for_uid<'a>(uid: u32) -> Result<&'a str, std::str::Utf8Error> {
|
|
let user = unsafe {
|
|
let pw = libc::getpwuid(uid);
|
|
let name = (*pw).pw_name;
|
|
CStr::from_ptr(name)
|
|
};
|
|
user.to_str()
|
|
}
|
|
|
|
/// Gets the uid associated with the given name
|
|
#[must_use]
|
|
pub fn get_uid_for_name(name: &str) -> Option<u32> {
|
|
let Ok(user) = CString::new(name.as_bytes()) else { return None };
|
|
unsafe {
|
|
let pw = libc::getpwnam(user.as_ptr());
|
|
if pw.is_null() {
|
|
None
|
|
} else {
|
|
Some((*pw).pw_uid)
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Gets the gid for the main group associated with the given user
|
|
#[must_use]
|
|
pub fn get_pgid_for_name(name: &str) -> Option<u32> {
|
|
let Ok(user) = CString::new(name.as_bytes()) else { return None };
|
|
unsafe {
|
|
let pw = libc::getpwnam(user.as_ptr());
|
|
if pw.is_null() {
|
|
None
|
|
} else {
|
|
Some((*pw).pw_gid)
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Gets the main group name for the current process
|
|
/// # Errors
|
|
/// The name must be valid utf8
|
|
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_gid_for_groupname(groupname: &str) -> Option<u32> {
|
|
let Ok(grp) = CString::new(groupname.as_bytes()) else { return None };
|
|
unsafe { Some((*libc::getgrnam(grp.as_ptr())).gr_gid) }
|
|
}
|
|
|
|
pub fn get_groupname_for_gid<'a>(gid: u32) -> Result<&'a str, std::str::Utf8Error> {
|
|
let group = unsafe {
|
|
let gr = libc::getgrgid(gid);
|
|
let name = (*gr).gr_name;
|
|
CStr::from_ptr(name)
|
|
};
|
|
group.to_str()
|
|
}
|
|
|
|
/// Gets the effective group for the current process
|
|
/// # Errors
|
|
/// The name must be valid utf8
|
|
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()
|
|
}
|
|
|
|
/// Gets the group ids for all groups the current effective user belongs to
|
|
/// # Errors
|
|
/// Can only error if unable to make a valid usize from the number
|
|
/// of groups returned via `libc::getgroups`
|
|
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)
|
|
}
|
|
|
|
/// Gets the group ids for all groups the named user belongs to
|
|
/// # Errors
|
|
/// Errors if a valid `CString` cannot be made
|
|
/// Errors if a user belongs to more than 1024 groups
|
|
#[allow(clippy::cast_sign_loss)]
|
|
pub fn get_gids_for_name(name: &str) -> Result<Vec<u32>, Box<dyn Error>> {
|
|
let gid = match get_pgid_for_name(name) {
|
|
Some(g) => g as libc::gid_t,
|
|
None => {
|
|
return Err(Box::new(io::Error::new(
|
|
io::ErrorKind::Other,
|
|
"cannot get primary group",
|
|
)))
|
|
}
|
|
};
|
|
let mut buf: Vec<libc::gid_t> = vec![0; 1024];
|
|
let name = CString::new(name.as_bytes())?;
|
|
let mut ct: c_int = 1024;
|
|
unsafe {
|
|
let res = libc::getgrouplist(name.as_ptr(), gid, buf.as_mut_ptr(), &mut ct);
|
|
if res < 0 {
|
|
return Err(Box::new(io::Error::new(
|
|
io::ErrorKind::Other,
|
|
"too many groups",
|
|
)));
|
|
}
|
|
}
|
|
Ok(buf[0..ct as usize].to_vec())
|
|
}
|
|
|
|
/// Gets a list of group names for the current effective user
|
|
/// # Errors
|
|
/// Bubbles up errors from `get_gids`
|
|
/// Can error if a group name is not valid utf8
|
|
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);
|
|
if gr.is_null() {
|
|
id.to_string()
|
|
} else {
|
|
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)
|
|
}
|
|
|
|
/// Gets a list of group names for the given user name
|
|
/// # Errors
|
|
/// Bubbles up errors from `get_gids_for_name`
|
|
/// Can error if a group name is not valid utf8
|
|
pub fn get_group_names_for_name(name: &str) -> Result<Vec<String>, Box<dyn Error>> {
|
|
let gids = get_gids_for_name(name)?;
|
|
let mut names = vec![];
|
|
for id in gids {
|
|
let name = unsafe {
|
|
let gr = libc::getgrgid(id);
|
|
if gr.is_null() {
|
|
id.to_string()
|
|
} else {
|
|
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)
|
|
}
|