inside 0.1.0

sandboxer for processes
Documentation
use landlock::{
    ABI, Access, AccessFs, AccessNet, AddRulesError, BitFlags, CreateRulesetError,
    HandleAccessesError, NetPort, PathBeneath, PathFd, Ruleset, RulesetAttr, RulesetCreated,
    RulesetCreatedAttr, RulesetError, path_beneath_rules,
};

use crate::{FilePermissions, NetworkPermissions};

pub struct InsideRuleset {
    abi: ABI,
    ruleset: RulesetCreated,
}

impl InsideRuleset {
    pub fn try_new(abi: ABI) -> Result<Self, NewInsideRulesetError> {
        match Ruleset::default().handle_access(AccessFs::from_all(abi)) {
            Ok(ruleset) => match ruleset.handle_access(AccessNet::from_all(abi)) {
                Ok(ruleset) => match ruleset.create() {
                    Ok(ruleset) => Ok(InsideRuleset { abi, ruleset }),
                    Err(RulesetError::CreateRuleset(e)) => Err(e.into()),
                    Err(_) => unreachable!(),
                },
                Err(RulesetError::HandleAccesses(e)) => Err(e.into()),
                Err(_) => unreachable!(),
            },
            Err(RulesetError::HandleAccesses(e)) => Err(e.into()),
            Err(_) => unreachable!(),
        }
    }
    pub fn allow_file(
        mut self,
        path: AllowPath,
        permissions: FilePermissions,
    ) -> Result<Self, AddRulesError> {
        let access_fs = if let Some(access_fs) = self.access_fs(permissions) {
            access_fs
        } else {
            return Ok(self);
        };
        let ruleset = self
            .ruleset
            .add_rule(PathBeneath::new(path.0, access_fs))
            .map_err(|e| match e {
                RulesetError::AddRules(e) => e,
                _ => unreachable!(),
            })?;
        self.ruleset = ruleset;
        Ok(self)
    }
    pub fn allow_files<T: AsRef<std::path::Path>>(
        mut self,
        paths: impl Iterator<Item = T>,
        permissions: FilePermissions,
    ) -> Result<Self, AddRulesError> {
        let access_fs = if let Some(access_fs) = self.access_fs(permissions) {
            access_fs
        } else {
            return Ok(self);
        };
        self.ruleset = self
            .ruleset
            .add_rules(path_beneath_rules(paths, access_fs))
            .map_err(|e| match e {
                RulesetError::AddRules(e) => e,
                _ => unreachable!(),
            })?;
        Ok(self)
    }
    pub fn allow_port(
        mut self,
        port: u16,
        network_permissions: NetworkPermissions,
    ) -> Result<Self, AddRulesError> {
        let access_net = if let Some(network_permissions) = self.access_net(network_permissions) {
            network_permissions
        } else {
            return Ok(self);
        };
        self.ruleset = self
            .ruleset
            .add_rule(NetPort::new(port, access_net))
            .map_err(|e| match e {
                RulesetError::AddRules(e) => e,
                _ => unreachable!(),
            })?;
        Ok(self)
    }
    pub fn restrict(self) -> Result<landlock::RestrictionStatus, RulesetError> {
        self.ruleset.restrict_self()
    }
    fn access_fs(&self, file_permissions: FilePermissions) -> Option<BitFlags<AccessFs, u64>> {
        let access_fs = match file_permissions {
            FilePermissions::NONE => {
                return None;
            }
            FilePermissions::READ => AccessFs::from_read(self.abi),
            FilePermissions::WRITE => AccessFs::from_write(self.abi),
            FilePermissions::EXECUTE => AccessFs::Execute.into(),
            FilePermissions::READ_WRITE => AccessFs::from_all(self.abi),
            FilePermissions::READ_EXECUTE => AccessFs::from_read(self.abi) | AccessFs::Execute,
            FilePermissions::WRITE_EXECUTE => AccessFs::from_write(self.abi) | AccessFs::Execute,
            FilePermissions::ALL => AccessFs::from_all(self.abi) | AccessFs::Execute,
            _ => unreachable!(),
        };
        Some(access_fs)
    }
    fn access_net(
        &self,
        network_permissions: NetworkPermissions,
    ) -> Option<BitFlags<AccessNet, u64>> {
        let access_net = match network_permissions {
            NetworkPermissions::NONE => return None,
            NetworkPermissions::CONNECT_TCP => AccessNet::ConnectTcp.into(),
            NetworkPermissions::BIND_TCP => AccessNet::BindTcp.into(),
            NetworkPermissions::ALL => AccessNet::from_all(self.abi),
            _ => unreachable!(),
        };
        Some(access_net)
    }
}

#[derive(thiserror::Error, Debug)]
pub enum NewInsideRulesetError {
    #[error(transparent)]
    HandleAccess(#[from] HandleAccessesError),
    #[error(transparent)]
    CreateRuleset(#[from] CreateRulesetError),
}

#[derive(Debug)]
pub struct AllowPath(PathFd);
impl AllowPath {
    pub fn try_new(path: impl AsRef<std::path::Path>) -> Result<Self, landlock::PathFdError> {
        let path = PathFd::new(path)?;
        Ok(AllowPath(path))
    }
}