use std::{io, os::unix::fs::MetadataExt, path::Path};
use crate::utils::passwd::EtcPasswd;
const ETC_PASSWD_PATH: &str = "/etc/passwd";
pub fn current_user_uid() -> io::Result<u32> {
let username = std::env::var("USER")
.map_err(|err| io::Error::other(format!("USER environment variable not set: {err}")))?;
let etc_passwd =
EtcPasswd::new(ETC_PASSWD_PATH).map_err(|err| io::Error::other(format!("{err}")))?;
etc_passwd
.iter()
.find(|user| user.name == username)
.map(|user| user.id)
.ok_or_else(|| {
io::Error::other(format!("User '{username}' not found in {ETC_PASSWD_PATH}"))
})
}
pub fn validate_host_path(path: &Path, expected_uid: u32) -> io::Result<()> {
let metadata = std::fs::metadata(path).map_err(|err| {
io::Error::new(
err.kind(),
format!(
"Mount host path '{}' is not accessible: {err}",
path.display()
),
)
})?;
let owner_uid = metadata.uid();
if owner_uid != expected_uid {
return Err(io::Error::other(format!(
"Mount host path '{}' is owned by uid {owner_uid}, not the current user (uid {expected_uid}). \
Refusing to mount: SELinux relabeling (:z) and rootless userns mapping both assume the path is user-owned.",
path.display()
)));
}
Ok(())
}