genpac 0.1.0

Sandbox for Gentoo ebuild development using bubblewrap
// Copyright (C) 2023 Gokul Das B
// SPDX-License-Identifier: GPL-3.0-or-later
//! UID/GID mapping
//!
//! This module deals with managing and finally executing the mapping of UIDs and GIDs between the
//! sandbox user PID namespace and the root/host namespace.

use super::{ConfigOptions, Globals, LogStatus};
use anyhow::Result as AResult;
use serde::Deserialize;

/// UID/GID map format
///
/// This follows `newuidmap(1)` & `newgidmap(1)` format. The fields are in the order as follows:
/// 1. `uid`: Beginning of the range of UIDs/GIDs inside the chroot namespace
/// 2. `loweruid`: Beginning of the range of UIDs/GIDs outise the chroot (host) namespace
/// 3. `count`: Length of ranges (both inside and outside the chroot namespace)
pub type IDMapItem = (u64, u64, u64);
pub type IDMap = Vec<IDMapItem>;

#[derive(Deserialize, Default)]
pub(super) struct IDMaps {
    uid: IDMap,
    gid: IDMap,
}

impl<T: LogStatus> Globals<T, ConfigOptions> {
    /// Get UID and GID maps
    pub fn idmaps(&self) -> (&[IDMapItem], &[IDMapItem]) {
        let idmaps = &self.cfg.idmaps;
        (&idmaps.uid, &idmaps.gid)
    }

    /// Map UID or GID to final value
    fn remap_id(id: u64, idmap: &[IDMapItem], maptype: &str) -> AResult<u64> {
        for (upper, lower, count) in idmap {
            if (id >= *upper) && (id < (*upper + *count)) {
                return Ok(id + *lower - *upper);
            }
        }
        anyhow::bail!("Unable to find mapping for {maptype}: {id}");
    }

    /// Map UID to final value
    pub fn remap_uid(&self, uid: u64) -> AResult<u64> {
        let map = &self.cfg.idmaps.uid;
        Self::remap_id(uid, map, "UID")
    }

    /// Map GID to final value
    pub fn remap_gid(&self, gid: u64) -> AResult<u64> {
        let map = &self.cfg.idmaps.gid;
        Self::remap_id(gid, map, "GID")
    }
}