1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
//! Provide basic [capability-based security].
//!
//! The wrapper type [`WithCap`] associates a **capability** to an object, that
//! is a set of access rights. When accessing the object, we must explicitly
//! specify the access capability, and it must not violate the capability
//! associated with the object at initialization.
//!
//! # Examples
//!
//! ```
//! use capability::{Cap, WithCap};
//!
//! let data = WithCap::new(42, Cap::READ | Cap::WRITE);
//!
//! // Access with the correct capability.
//! assert_eq!(data.access(Cap::READ).unwrap(), &42);
//! assert_eq!(data.access(Cap::WRITE).unwrap(), &42);
//! assert_eq!(data.access(Cap::READ | Cap::WRITE).unwrap(), &42);
//!
//! // Access with the incorrect capability.
//! assert!(data.access(Cap::EXECUTE).is_err());
//! assert!(data.access(Cap::READ | Cap::EXECUTE).is_err());
//! ```
//!
//! [capability-based security]:
//! https://en.wikipedia.org/wiki/Capability-based_security
//!
#![no_std]
bitflags::bitflags! {
/// Capabilities (access rights).
#[derive(Default, Debug, Clone, Copy)]
pub struct Cap: u32 {
/// Readable access.
const READ = 1 << 0;
/// Writable access.
const WRITE = 1 << 1;
/// Executable access.
const EXECUTE = 1 << 2;
}
}
/// Error type for capability violation.
#[derive(Debug, Default, Eq, PartialEq)]
#[non_exhaustive]
pub struct CapError;
/// A wrapper that holds a type with a capability.
#[derive(Clone)]
pub struct WithCap<T> {
inner: T,
cap: Cap,
}
impl<T> WithCap<T> {
/// Create a new instance with the given capability.
pub fn new(inner: T, cap: Cap) -> Self {
Self { inner, cap }
}
/// Get the capability.
pub const fn cap(&self) -> Cap {
self.cap
}
/// Check if the inner data can be accessed with the given capability.
///
/// # Examples
///
/// ```
/// use capability::{Cap, WithCap};
///
/// let data = WithCap::new(42, Cap::READ);
///
/// assert!(data.can_access(Cap::READ));
/// assert!(!data.can_access(Cap::WRITE));
/// ```
pub const fn can_access(&self, cap: Cap) -> bool {
self.cap.contains(cap)
}
/// Access the inner value without capability check.
///
/// # Safety
///
/// Caller must ensure not to violate the capability.
pub unsafe fn access_unchecked(&self) -> &T {
&self.inner
}
/// Access the inner value with the given capability, or return `CapError`
/// if cannot access.
///
/// # Examples
///
/// ```
/// use capability::{Cap, CapError, WithCap};
///
/// let data = WithCap::new(42, Cap::READ);
///
/// assert_eq!(data.access(Cap::READ).unwrap(), &42);
/// assert_eq!(data.access(Cap::WRITE).err(), Some(CapError::default()));
/// ```
pub const fn access(&self, cap: Cap) -> Result<&T, CapError> {
if self.can_access(cap) {
Ok(&self.inner)
} else {
Err(CapError)
}
}
/// Access the inner value with the given capability, or return the given
/// `err` if cannot access.
///
/// # Examples
///
/// ```
/// use capability::{Cap, WithCap};
///
/// let data = WithCap::new(42, Cap::READ);
///
/// assert_eq!(data.access_or_err(Cap::READ, "cannot read").unwrap(), &42);
/// assert_eq!(data.access_or_err(Cap::WRITE, "cannot write").err(), Some("cannot write"));
/// ```
pub fn access_or_err<E>(&self, cap: Cap, err: E) -> Result<&T, E> {
if self.can_access(cap) {
Ok(&self.inner)
} else {
Err(err)
}
}
}
impl From<CapError> for axerrno::AxError {
#[inline]
fn from(_: CapError) -> Self {
Self::PermissionDenied
}
}