use super::node_creds;
use btfproto::local_fs::AuthzContext;
use btlib::{crypto::CredsPriv, AuthzAttrs, BlockError, BlockMeta, BlockPath};
pub struct TestCase {
attrs: AuthzAttrs,
meta: BlockMeta,
from: BlockPath,
}
impl TestCase {
pub const BLOCK_UID: u32 = 1000;
pub const BLOCK_GID: u32 = 1000;
pub fn new(ctx_uid: u32, ctx_gid: u32, mode: u32) -> TestCase {
let mut meta = BlockMeta::new(node_creds()).expect("failed to create block metadata");
meta.mut_body()
.access_secrets(|secrets| {
secrets.uid = Self::BLOCK_UID;
secrets.gid = Self::BLOCK_GID;
secrets.mode = mode;
Ok(())
})
.expect("failed to update secrets");
let attrs = AuthzAttrs {
uid: ctx_uid,
gid: ctx_gid,
supp_gids: Vec::new(),
};
let from = node_creds()
.writecap()
.ok_or(BlockError::MissingWritecap)
.unwrap()
.bind_path();
TestCase { attrs, meta, from }
}
pub fn context(&self) -> AuthzContext<'_> {
AuthzContext {
from: &self.from,
attrs: &self.attrs,
meta: &self.meta,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use btfproto::local_fs::{Authorizer, ModeAuthorizer};
#[test]
fn cant_read_when_no_bits_set() {
let case = TestCase::new(TestCase::BLOCK_UID, TestCase::BLOCK_GID, 0);
let result = ModeAuthorizer {}.can_read(&case.context());
assert!(result.is_err())
}
#[test]
fn cant_write_when_no_bits_set() {
let case = TestCase::new(TestCase::BLOCK_UID, TestCase::BLOCK_GID, 0);
let result = ModeAuthorizer {}.can_write(&case.context());
assert!(result.is_err())
}
#[test]
fn cant_exec_when_no_bits_set() {
let case = TestCase::new(TestCase::BLOCK_UID, TestCase::BLOCK_GID, 0);
let result = ModeAuthorizer {}.can_exec(&case.context());
assert!(result.is_err())
}
#[test]
fn user_can_read_when_bit_set() {
let case = TestCase::new(TestCase::BLOCK_UID, TestCase::BLOCK_GID, libc::S_IRUSR);
let result = ModeAuthorizer {}.can_read(&case.context());
assert!(result.is_ok())
}
#[test]
fn user_can_write_when_bit_set() {
let case = TestCase::new(TestCase::BLOCK_UID, TestCase::BLOCK_GID, libc::S_IWUSR);
let result = ModeAuthorizer {}.can_write(&case.context());
assert!(result.is_ok())
}
#[test]
fn user_can_exec_when_bit_set() {
let case = TestCase::new(TestCase::BLOCK_UID, TestCase::BLOCK_GID, libc::S_IXUSR);
let result = ModeAuthorizer {}.can_exec(&case.context());
assert!(result.is_ok())
}
#[test]
fn group_can_read_when_bit_set() {
let case = TestCase::new(TestCase::BLOCK_UID, TestCase::BLOCK_GID, libc::S_IRGRP);
let result = ModeAuthorizer {}.can_read(&case.context());
assert!(result.is_ok())
}
#[test]
fn group_can_write_when_bit_set() {
let case = TestCase::new(TestCase::BLOCK_UID, TestCase::BLOCK_GID, libc::S_IWGRP);
let result = ModeAuthorizer {}.can_write(&case.context());
assert!(result.is_ok())
}
#[test]
fn group_can_exec_when_bit_set() {
let case = TestCase::new(TestCase::BLOCK_UID, TestCase::BLOCK_GID, libc::S_IXGRP);
let result = ModeAuthorizer {}.can_exec(&case.context());
assert!(result.is_ok())
}
#[test]
fn other_can_read_when_bit_set() {
let case = TestCase::new(TestCase::BLOCK_UID, TestCase::BLOCK_GID, libc::S_IROTH);
let result = ModeAuthorizer {}.can_read(&case.context());
assert!(result.is_ok())
}
#[test]
fn other_can_write_when_bit_set() {
let case = TestCase::new(TestCase::BLOCK_UID, TestCase::BLOCK_GID, libc::S_IWOTH);
let result = ModeAuthorizer {}.can_write(&case.context());
assert!(result.is_ok())
}
#[test]
fn other_can_exec_when_bit_set() {
let case = TestCase::new(TestCase::BLOCK_UID, TestCase::BLOCK_GID, libc::S_IXOTH);
let result = ModeAuthorizer {}.can_exec(&case.context());
assert!(result.is_ok())
}
#[test]
fn other_cant_write_even_if_user_can() {
let case = TestCase::new(
TestCase::BLOCK_UID + 1,
TestCase::BLOCK_GID + 1,
libc::S_IWUSR,
);
let result = ModeAuthorizer {}.can_write(&case.context());
assert!(result.is_err())
}
#[test]
fn other_cant_write_even_if_group_can() {
let case = TestCase::new(
TestCase::BLOCK_UID + 1,
TestCase::BLOCK_GID + 1,
libc::S_IWGRP,
);
let result = ModeAuthorizer {}.can_write(&case.context());
assert!(result.is_err())
}
#[test]
fn user_allowed_read_when_only_other_bit_set() {
let case = TestCase::new(TestCase::BLOCK_UID, TestCase::BLOCK_GID, libc::S_IROTH);
let result = ModeAuthorizer {}.can_read(&case.context());
assert!(result.is_ok())
}
#[test]
fn root_always_allowed() {
let case = TestCase::new(0, 0, 0);
let ctx = case.context();
let authorizer = ModeAuthorizer {};
assert!(authorizer.can_read(&ctx).is_ok());
assert!(authorizer.can_write(&ctx).is_ok());
assert!(authorizer.can_exec(&ctx).is_ok());
}
}