use super::error::{ParseError, ValidateError};
use super::extensible_bitmap::ExtensibleBitmap;
use super::parser::ParseStrategy;
use super::{
array_type, array_type_validate_deref_both, array_type_validate_deref_data,
array_type_validate_deref_metadata_data_vec, array_type_validate_deref_none_data_vec, Array,
CategoryId, ClassId, Counted, Parse, ParseSlice, RoleId, SensitivityId, TypeId, UserId,
Validate, ValidateArray,
};
use anyhow::Context as _;
use std::fmt::Debug;
use std::num::NonZeroU32;
use std::ops::Deref;
use zerocopy::{little_endian as le, FromBytes, Immutable, KnownLayout, Unaligned};
const CONSTRAINT_TYPE_HAS_EXTENSIBLE_BITMAP_AND_TYPE_SET: u32 = 5;
#[allow(dead_code)]
pub(super) const TYPE_PROPERTIES_TYPE: u32 = 1;
pub(super) const TYPE_PROPERTIES_ALIAS: u32 = 0;
pub(super) const TYPE_PROPERTIES_ATTRIBUTE: u32 = 0;
#[derive(Debug, PartialEq)]
pub(super) struct SymbolList<PS: ParseStrategy, T>(Array<PS, PS::Output<Metadata>, Vec<T>>);
impl<PS: ParseStrategy, T> Deref for SymbolList<PS, T> {
type Target = Array<PS, PS::Output<Metadata>, Vec<T>>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<PS: ParseStrategy, T> Parse<PS> for SymbolList<PS, T>
where
Array<PS, PS::Output<Metadata>, Vec<T>>: Parse<PS>,
{
type Error = <Array<PS, PS::Output<Metadata>, Vec<T>> as Parse<PS>>::Error;
fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
let (array, tail) = Array::<PS, PS::Output<Metadata>, Vec<T>>::parse(bytes)?;
Ok((Self(array), tail))
}
}
impl<PS: ParseStrategy, T> Validate for SymbolList<PS, T>
where
[T]: Validate,
{
type Error = anyhow::Error;
fn validate(&self) -> Result<(), Self::Error> {
PS::deref(&self.metadata).validate().map_err(Into::<anyhow::Error>::into)?;
self.data.as_slice().validate().map_err(Into::<anyhow::Error>::into)?;
Ok(())
}
}
#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
#[repr(C, packed)]
pub(super) struct Metadata {
primary_names_count: le::U32,
count: le::U32,
}
impl Metadata {
pub fn primary_names_count(&self) -> u32 {
self.primary_names_count.get()
}
}
impl Counted for Metadata {
fn count(&self) -> u32 {
self.count.get()
}
}
impl Validate for Metadata {
type Error = anyhow::Error;
fn validate(&self) -> Result<(), Self::Error> {
Ok(())
}
}
impl<PS: ParseStrategy> Validate for [CommonSymbol<PS>] {
type Error = <CommonSymbol<PS> as Validate>::Error;
fn validate(&self) -> Result<(), Self::Error> {
Ok(())
}
}
array_type!(CommonSymbol, PS, CommonSymbolMetadata<PS>, Permissions<PS>);
array_type_validate_deref_none_data_vec!(CommonSymbol);
impl<PS: ParseStrategy> CommonSymbol<PS> {
pub fn permissions(&self) -> &Permissions<PS> {
&self.data
}
}
pub(super) type CommonSymbols<PS> = Vec<CommonSymbol<PS>>;
impl<PS: ParseStrategy> CommonSymbol<PS> {
pub fn name_bytes(&self) -> &[u8] {
PS::deref_slice(&self.metadata.data)
}
}
impl<PS: ParseStrategy> Counted for CommonSymbol<PS>
where
CommonSymbolMetadata<PS>: Parse<PS> + Validate,
Array<PS, PS::Output<CommonSymbolStaticMetadata>, PS::Slice<u8>>: Parse<PS>,
Array<PS, PS::Output<PermissionMetadata>, PS::Slice<u8>>: Parse<PS>,
Array<PS, CommonSymbolMetadata<PS>, Vec<Permission<PS>>>: Parse<PS>,
Vec<Permission<PS>>: ParseSlice<PS>,
{
fn count(&self) -> u32 {
self.metadata.count()
}
}
impl<PS: ParseStrategy> ValidateArray<CommonSymbolMetadata<PS>, Permission<PS>>
for CommonSymbol<PS>
{
type Error = anyhow::Error;
fn validate_array<'a>(
_metadata: &'a CommonSymbolMetadata<PS>,
_data: &'a [Permission<PS>],
) -> Result<(), Self::Error> {
Ok(())
}
}
array_type!(CommonSymbolMetadata, PS, PS::Output<CommonSymbolStaticMetadata>, PS::Slice<u8>);
array_type_validate_deref_both!(CommonSymbolMetadata);
impl<PS: ParseStrategy> Counted for CommonSymbolMetadata<PS> {
fn count(&self) -> u32 {
PS::deref(&self.metadata).count.get()
}
}
impl<PS: ParseStrategy> ValidateArray<CommonSymbolStaticMetadata, u8> for CommonSymbolMetadata<PS> {
type Error = anyhow::Error;
fn validate_array<'a>(
_metadata: &'a CommonSymbolStaticMetadata,
_data: &'a [u8],
) -> Result<(), Self::Error> {
Ok(())
}
}
#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
#[repr(C, packed)]
pub(super) struct CommonSymbolStaticMetadata {
length: le::U32,
id: le::U32,
primary_names_count: le::U32,
count: le::U32,
}
impl Validate for CommonSymbolStaticMetadata {
type Error = anyhow::Error;
fn validate(&self) -> Result<(), Self::Error> {
Ok(())
}
}
impl Counted for CommonSymbolStaticMetadata {
fn count(&self) -> u32 {
self.length.get()
}
}
pub(super) type Permissions<PS> = Vec<Permission<PS>>;
impl<PS: ParseStrategy> Validate for Permissions<PS> {
type Error = anyhow::Error;
fn validate(&self) -> Result<(), Self::Error> {
Ok(())
}
}
array_type!(Permission, PS, PS::Output<PermissionMetadata>, PS::Slice<u8>);
array_type_validate_deref_both!(Permission);
impl<PS: ParseStrategy> Permission<PS> {
pub fn name_bytes(&self) -> &[u8] {
PS::deref_slice(&self.data)
}
pub fn id(&self) -> u32 {
PS::deref(&self.metadata).id.get()
}
}
impl<PS: ParseStrategy> ValidateArray<PermissionMetadata, u8> for Permission<PS> {
type Error = anyhow::Error;
fn validate_array<'a>(
_metadata: &'a PermissionMetadata,
_data: &'a [u8],
) -> Result<(), Self::Error> {
Ok(())
}
}
#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
#[repr(C, packed)]
pub(super) struct PermissionMetadata {
length: le::U32,
id: le::U32,
}
impl Counted for PermissionMetadata {
fn count(&self) -> u32 {
self.length.get()
}
}
impl Validate for PermissionMetadata {
type Error = anyhow::Error;
fn validate(&self) -> Result<(), Self::Error> {
Ok(())
}
}
pub(super) type ConstraintsList<PS> = Vec<PermissionAndConstraints<PS>>;
impl<PS: ParseStrategy> Validate for ConstraintsList<PS> {
type Error = anyhow::Error;
fn validate(&self) -> Result<(), Self::Error> {
Ok(())
}
}
#[derive(Debug, PartialEq)]
pub(super) struct PermissionAndConstraints<PS: ParseStrategy>
where
ConstraintList<PS>: Debug + PartialEq,
{
permission_bitset: PS::Output<le::U32>,
constraints: ConstraintList<PS>,
}
impl<PS: ParseStrategy> Parse<PS> for PermissionAndConstraints<PS>
where
ConstraintList<PS>: Debug + PartialEq + Parse<PS>,
{
type Error = anyhow::Error;
fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
let tail = bytes;
let num_bytes = tail.len();
let (permission_bitset, tail) = PS::parse::<le::U32>(tail).ok_or_else(|| {
Into::<anyhow::Error>::into(ParseError::MissingData {
type_name: "PermissionBitset",
type_size: std::mem::size_of::<le::U32>(),
num_bytes,
})
})?;
let (constraints, tail) = ConstraintList::parse(tail)
.map_err(|error| error.into() as anyhow::Error)
.context("parsing constraint list in constraints list")?;
Ok((Self { permission_bitset, constraints }, tail))
}
}
array_type!(ConstraintList, PS, PS::Output<ConstraintCount>, Constraints<PS>);
array_type_validate_deref_metadata_data_vec!(ConstraintList);
impl<PS: ParseStrategy> ValidateArray<ConstraintCount, Constraint<PS>> for ConstraintList<PS> {
type Error = anyhow::Error;
fn validate_array<'a>(
_metadata: &'a ConstraintCount,
_data: &'a [Constraint<PS>],
) -> Result<(), Self::Error> {
Ok(())
}
}
#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
#[repr(C, packed)]
pub(super) struct ConstraintCount(le::U32);
impl Counted for ConstraintCount {
fn count(&self) -> u32 {
self.0.get()
}
}
impl Validate for ConstraintCount {
type Error = anyhow::Error;
fn validate(&self) -> Result<(), Self::Error> {
Ok(())
}
}
impl<PS: ParseStrategy> Validate for Constraints<PS> {
type Error = anyhow::Error;
fn validate(&self) -> Result<(), Self::Error> {
Ok(())
}
}
#[derive(Debug, PartialEq)]
pub(super) struct Constraint<PS: ParseStrategy> {
metadata: PS::Output<ConstraintMetadata>,
names: Option<ExtensibleBitmap<PS>>,
names_type_set: Option<TypeSet<PS>>,
}
pub(super) type Constraints<PS> = Vec<Constraint<PS>>;
impl<PS: ParseStrategy> Parse<PS> for Constraint<PS>
where
ExtensibleBitmap<PS>: Parse<PS>,
{
type Error = anyhow::Error;
fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
let tail = bytes;
let (metadata, tail) =
PS::parse::<ConstraintMetadata>(tail).context("parsing constraint metadata")?;
let (names, names_type_set, tail) = match PS::deref(&metadata).constraint_type.get() {
CONSTRAINT_TYPE_HAS_EXTENSIBLE_BITMAP_AND_TYPE_SET => {
let (names, tail) = ExtensibleBitmap::parse(tail)
.map_err(Into::<anyhow::Error>::into)
.context("parsing constraint names")?;
let (names_type_set, tail) =
TypeSet::parse(tail).context("parsing constraint names type set")?;
(Some(names), Some(names_type_set), tail)
}
_ => (None, None, tail),
};
Ok((Self { metadata, names, names_type_set }, tail))
}
}
#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
#[repr(C, packed)]
pub(super) struct ConstraintMetadata {
constraint_type: le::U32,
attribute: le::U32,
operands: le::U32,
}
impl Validate for ConstraintMetadata {
type Error = anyhow::Error;
fn validate(&self) -> Result<(), Self::Error> {
Ok(())
}
}
#[derive(Debug, PartialEq)]
pub(super) struct TypeSet<PS: ParseStrategy> {
types: ExtensibleBitmap<PS>,
negative_set: ExtensibleBitmap<PS>,
flags: PS::Output<le::U32>,
}
impl<PS: ParseStrategy> Parse<PS> for TypeSet<PS>
where
ExtensibleBitmap<PS>: Parse<PS>,
{
type Error = anyhow::Error;
fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
let tail = bytes;
let (types, tail) = ExtensibleBitmap::parse(tail)
.map_err(Into::<anyhow::Error>::into)
.context("parsing type set types")?;
let (negative_set, tail) = ExtensibleBitmap::parse(tail)
.map_err(Into::<anyhow::Error>::into)
.context("parsing type set negative set")?;
let num_bytes = tail.len();
let (flags, tail) = PS::parse::<le::U32>(tail).ok_or_else(|| {
Into::<anyhow::Error>::into(ParseError::MissingData {
type_name: "TypeSetFlags",
type_size: std::mem::size_of::<le::U32>(),
num_bytes,
})
})?;
Ok((Self { types, negative_set, flags }, tail))
}
}
pub(super) fn find_class_by_name<'a, PS: ParseStrategy>(
classes: &'a Classes<PS>,
name: &str,
) -> Option<&'a Class<PS>> {
find_class_by_name_bytes(classes, name.as_bytes())
}
fn find_class_by_name_bytes<'a, PS: ParseStrategy>(
classes: &'a Classes<PS>,
name_bytes: &[u8],
) -> Option<&'a Class<PS>> {
for cls in classes.into_iter() {
if cls.name_bytes() == name_bytes {
return Some(cls);
}
}
None
}
#[allow(dead_code)]
pub(super) fn find_common_symbol_by_name<'a, PS: ParseStrategy>(
common_symbols: &'a CommonSymbols<PS>,
name: &str,
) -> Option<&'a CommonSymbol<PS>> {
find_common_symbol_by_name_bytes(common_symbols, name.as_bytes())
}
pub(super) fn find_common_symbol_by_name_bytes<'a, PS: ParseStrategy>(
common_symbols: &'a CommonSymbols<PS>,
name_bytes: &[u8],
) -> Option<&'a CommonSymbol<PS>> {
for common_symbol in common_symbols.into_iter() {
if common_symbol.name_bytes() == name_bytes {
return Some(common_symbol);
}
}
None
}
pub(super) fn find_class_permission_by_name<'a, PS: ParseStrategy>(
common_symbols: &'a CommonSymbols<PS>,
class: &'a Class<PS>,
name: &'a str,
) -> Option<&'a Permission<PS>> {
let name_bytes = name.as_bytes();
if let Some(permission) = find_own_class_permission_by_name_bytes(class, name_bytes) {
Some(permission)
} else if let Some(common_symbol) =
find_common_symbol_by_name_bytes(common_symbols, class.common_name_bytes())
{
find_common_permission_by_name_bytes(common_symbol, name_bytes)
} else {
None
}
}
fn find_own_class_permission_by_name_bytes<'a, PS: ParseStrategy>(
class: &'a Class<PS>,
name_bytes: &'a [u8],
) -> Option<&'a Permission<PS>> {
let own_permissions: &Permissions<PS> = &class.constraints.metadata.data;
find_own_permission_by_name_bytes(own_permissions, name_bytes)
}
fn find_common_permission_by_name_bytes<'a, PS: ParseStrategy>(
common_symbol: &'a CommonSymbol<PS>,
name_bytes: &'a [u8],
) -> Option<&'a Permission<PS>> {
let own_permissions: &Permissions<PS> = &common_symbol.data;
find_own_permission_by_name_bytes(own_permissions, name_bytes)
}
fn find_own_permission_by_name_bytes<'a, PS: ParseStrategy>(
own_permissions: &'a Permissions<PS>,
name_bytes: &'a [u8],
) -> Option<&'a Permission<PS>> {
for permission in own_permissions {
if permission.name_bytes() == name_bytes {
return Some(permission);
}
}
None
}
impl<PS: ParseStrategy> Validate for [Class<PS>] {
type Error = anyhow::Error;
fn validate(&self) -> Result<(), Self::Error> {
for class in self {
class.defaults().validate().context("class defaults")?;
}
Ok(())
}
}
#[derive(Debug, PartialEq)]
pub(super) struct Class<PS: ParseStrategy> {
constraints: ClassConstraints<PS>,
validate_transitions: ClassValidateTransitions<PS>,
defaults: PS::Output<ClassDefaults>,
}
pub(super) type Classes<PS> = Vec<Class<PS>>;
impl<PS: ParseStrategy> Class<PS> {
pub fn common_name_bytes(&self) -> &[u8] {
let class_common_key: &ClassCommonKey<PS> = &self.constraints.metadata.metadata;
PS::deref_slice(&class_common_key.data)
}
pub fn name_bytes(&self) -> &[u8] {
let class_key: &ClassKey<PS> = &self.constraints.metadata.metadata.metadata;
PS::deref_slice(&class_key.data)
}
pub fn id(&self) -> ClassId {
let class_metadata: &ClassMetadata =
&PS::deref(&self.constraints.metadata.metadata.metadata.metadata);
ClassId(NonZeroU32::new(class_metadata.id.get()).unwrap())
}
#[allow(dead_code)]
pub fn has_common(&self) -> bool {
self.common_name_bytes().len() != 0
}
pub fn permissions(&self) -> &Permissions<PS> {
&self.constraints.metadata.data
}
pub fn defaults(&self) -> &ClassDefaults {
PS::deref(&self.defaults)
}
}
impl<PS: ParseStrategy> Parse<PS> for Class<PS>
where
ClassConstraints<PS>: Parse<PS>,
ClassValidateTransitions<PS>: Parse<PS>,
{
type Error = anyhow::Error;
fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
let tail = bytes;
let (constraints, tail) = ClassConstraints::parse(tail)
.map_err(Into::<anyhow::Error>::into)
.context("parsing class constraints")?;
let (validate_transitions, tail) = ClassValidateTransitions::parse(tail)
.map_err(Into::<anyhow::Error>::into)
.context("parsing class validate transitions")?;
let (defaults, tail) =
PS::parse::<ClassDefaults>(tail).context("parsing class defaults")?;
Ok((Self { constraints, validate_transitions, defaults }, tail))
}
}
#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
#[repr(C, packed)]
pub(super) struct ClassDefaults {
default_user: le::U32,
default_role: le::U32,
default_range: le::U32,
default_type: le::U32,
}
impl ClassDefaults {
pub fn user(&self) -> ClassDefault {
self.default_user.get().into()
}
pub fn role(&self) -> ClassDefault {
self.default_role.get().into()
}
pub fn range(&self) -> ClassDefaultRange {
self.default_range.get().into()
}
pub fn type_(&self) -> ClassDefault {
self.default_type.get().into()
}
}
impl Validate for ClassDefaults {
type Error = anyhow::Error;
fn validate(&self) -> Result<(), Self::Error> {
ClassDefault::validate(self.default_user.get()).context("default user")?;
ClassDefault::validate(self.default_role.get()).context("default role")?;
ClassDefault::validate(self.default_type.get()).context("default type")?;
ClassDefaultRange::validate(self.default_range.get()).context("default range")?;
Ok(())
}
}
#[derive(PartialEq)]
pub(super) enum ClassDefault {
Unspecified,
Source,
Target,
}
impl ClassDefault {
pub(super) const DEFAULT_UNSPECIFIED: u32 = 0;
pub(super) const DEFAULT_SOURCE: u32 = 1;
pub(super) const DEFAULT_TARGET: u32 = 2;
fn validate(value: u32) -> Result<(), ValidateError> {
match value {
Self::DEFAULT_UNSPECIFIED | Self::DEFAULT_SOURCE | Self::DEFAULT_TARGET => Ok(()),
value => Err(ValidateError::InvalidClassDefault { value }),
}
}
}
impl From<u32> for ClassDefault {
fn from(value: u32) -> Self {
match value {
Self::DEFAULT_UNSPECIFIED => Self::Unspecified,
Self::DEFAULT_SOURCE => Self::Source,
Self::DEFAULT_TARGET => Self::Target,
v => panic!(
"invalid SELinux class default; expected {}, {}, or {}, but got {}",
Self::DEFAULT_UNSPECIFIED,
Self::DEFAULT_SOURCE,
Self::DEFAULT_TARGET,
v
),
}
}
}
#[derive(PartialEq)]
pub(super) enum ClassDefaultRange {
Unspecified,
SourceLow,
SourceHigh,
SourceLowHigh,
TargetLow,
TargetHigh,
TargetLowHigh,
}
impl ClassDefaultRange {
pub(super) const DEFAULT_UNSPECIFIED: u32 = 0;
pub(super) const DEFAULT_SOURCE_LOW: u32 = 1;
pub(super) const DEFAULT_SOURCE_HIGH: u32 = 2;
pub(super) const DEFAULT_SOURCE_LOW_HIGH: u32 = 3;
pub(super) const DEFAULT_TARGET_LOW: u32 = 4;
pub(super) const DEFAULT_TARGET_HIGH: u32 = 5;
pub(super) const DEFAULT_TARGET_LOW_HIGH: u32 = 6;
pub(super) const DEFAULT_UNKNOWN_USED_VALUE: u32 = 7;
fn validate(value: u32) -> Result<(), ValidateError> {
match value {
Self::DEFAULT_UNSPECIFIED
| Self::DEFAULT_SOURCE_LOW
| Self::DEFAULT_SOURCE_HIGH
| Self::DEFAULT_SOURCE_LOW_HIGH
| Self::DEFAULT_TARGET_LOW
| Self::DEFAULT_TARGET_HIGH
| Self::DEFAULT_TARGET_LOW_HIGH
| Self::DEFAULT_UNKNOWN_USED_VALUE => Ok(()),
value => Err(ValidateError::InvalidClassDefaultRange { value }),
}
}
}
impl From<u32> for ClassDefaultRange {
fn from(value: u32) -> Self {
match value {
Self::DEFAULT_UNSPECIFIED => Self::Unspecified,
Self::DEFAULT_SOURCE_LOW => Self::SourceLow,
Self::DEFAULT_SOURCE_HIGH => Self::SourceHigh,
Self::DEFAULT_SOURCE_LOW_HIGH => Self::SourceLowHigh,
Self::DEFAULT_TARGET_LOW => Self::TargetLow,
Self::DEFAULT_TARGET_HIGH => Self::TargetHigh,
Self::DEFAULT_TARGET_LOW_HIGH => Self::TargetLowHigh,
v => panic!(
"invalid SELinux MLS range default; expected one of {:?}, but got {}",
[
Self::DEFAULT_UNSPECIFIED,
Self::DEFAULT_SOURCE_LOW,
Self::DEFAULT_SOURCE_HIGH,
Self::DEFAULT_SOURCE_LOW_HIGH,
Self::DEFAULT_TARGET_LOW,
Self::DEFAULT_TARGET_HIGH,
Self::DEFAULT_TARGET_LOW_HIGH,
],
v
),
}
}
}
array_type!(
ClassValidateTransitions,
PS,
PS::Output<ClassValidateTransitionsCount>,
Constraints<PS>
);
array_type_validate_deref_metadata_data_vec!(ClassValidateTransitions);
impl<PS: ParseStrategy> ValidateArray<ClassValidateTransitionsCount, Constraint<PS>>
for ClassValidateTransitions<PS>
{
type Error = anyhow::Error;
fn validate_array<'a>(
_metadata: &'a ClassValidateTransitionsCount,
_data: &'a [Constraint<PS>],
) -> Result<(), Self::Error> {
Ok(())
}
}
#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
#[repr(C, packed)]
pub(super) struct ClassValidateTransitionsCount(le::U32);
impl Counted for ClassValidateTransitionsCount {
fn count(&self) -> u32 {
self.0.get()
}
}
impl Validate for ClassValidateTransitionsCount {
type Error = anyhow::Error;
fn validate(&self) -> Result<(), Self::Error> {
Ok(())
}
}
array_type!(ClassConstraints, PS, ClassPermissions<PS>, ConstraintsList<PS>);
array_type_validate_deref_none_data_vec!(ClassConstraints);
impl<PS: ParseStrategy> ValidateArray<ClassPermissions<PS>, PermissionAndConstraints<PS>>
for ClassConstraints<PS>
{
type Error = anyhow::Error;
fn validate_array<'a>(
_metadata: &'a ClassPermissions<PS>,
_data: &'a [PermissionAndConstraints<PS>],
) -> Result<(), Self::Error> {
Ok(())
}
}
array_type!(ClassPermissions, PS, ClassCommonKey<PS>, Permissions<PS>);
array_type_validate_deref_none_data_vec!(ClassPermissions);
impl<PS: ParseStrategy> ValidateArray<ClassCommonKey<PS>, Permission<PS>> for ClassPermissions<PS> {
type Error = anyhow::Error;
fn validate_array<'a>(
_metadata: &'a ClassCommonKey<PS>,
_data: &'a [Permission<PS>],
) -> Result<(), Self::Error> {
Ok(())
}
}
impl<PS: ParseStrategy> Counted for ClassPermissions<PS>
where
ClassCommonKey<PS>: Parse<PS>,
Array<PS, ClassKey<PS>, PS::Slice<u8>>: Parse<PS>,
Array<PS, PS::Output<ClassMetadata>, PS::Slice<u8>>: Parse<PS>,
ClassKey<PS>: Parse<PS>,
Vec<Permission<PS>>: ParseSlice<PS>,
Array<PS, PS::Output<PermissionMetadata>, PS::Slice<u8>>: Parse<PS>,
Array<PS, ClassCommonKey<PS>, Vec<Permission<PS>>>: Parse<PS>,
{
fn count(&self) -> u32 {
PS::deref(&self.metadata.metadata.metadata).constraint_count.get()
}
}
array_type!(ClassCommonKey, PS, ClassKey<PS>, PS::Slice<u8>);
array_type_validate_deref_data!(ClassCommonKey);
impl<PS: ParseStrategy> ValidateArray<ClassKey<PS>, u8> for ClassCommonKey<PS> {
type Error = anyhow::Error;
fn validate_array<'a>(_metadata: &'a ClassKey<PS>, _data: &'a [u8]) -> Result<(), Self::Error> {
Ok(())
}
}
impl<PS: ParseStrategy> Counted for ClassCommonKey<PS>
where
Array<PS, ClassKey<PS>, PS::Slice<u8>>: Parse<PS>,
Array<PS, PS::Output<ClassMetadata>, PS::Slice<u8>>: Parse<PS>,
ClassKey<PS>: Parse<PS>,
{
fn count(&self) -> u32 {
PS::deref(&self.metadata.metadata).elements_count.get()
}
}
array_type!(ClassKey, PS, PS::Output<ClassMetadata>, PS::Slice<u8>);
array_type_validate_deref_both!(ClassKey);
impl<PS: ParseStrategy> ValidateArray<ClassMetadata, u8> for ClassKey<PS> {
type Error = anyhow::Error;
fn validate_array<'a>(
_metadata: &'a ClassMetadata,
_data: &'a [u8],
) -> Result<(), Self::Error> {
Ok(())
}
}
impl<PS: ParseStrategy> Counted for ClassKey<PS>
where
Array<PS, PS::Output<ClassMetadata>, PS::Slice<u8>>: Parse<PS>,
{
fn count(&self) -> u32 {
PS::deref(&self.metadata).common_key_length.get()
}
}
#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
#[repr(C, packed)]
pub(super) struct ClassMetadata {
key_length: le::U32,
common_key_length: le::U32,
id: le::U32,
primary_names_count: le::U32,
elements_count: le::U32,
constraint_count: le::U32,
}
impl Counted for ClassMetadata {
fn count(&self) -> u32 {
self.key_length.get()
}
}
impl Validate for ClassMetadata {
type Error = anyhow::Error;
fn validate(&self) -> Result<(), Self::Error> {
if self.id.get() == 0 {
return Err(ValidateError::NonOptionalIdIsZero.into());
} else {
Ok(())
}
}
}
impl<PS: ParseStrategy> Validate for [Role<PS>] {
type Error = anyhow::Error;
fn validate(&self) -> Result<(), Self::Error> {
Ok(())
}
}
#[derive(Debug, PartialEq)]
pub(super) struct Role<PS: ParseStrategy> {
metadata: RoleMetadata<PS>,
role_dominates: ExtensibleBitmap<PS>,
role_types: ExtensibleBitmap<PS>,
}
impl<PS: ParseStrategy> Role<PS> {
pub(super) fn id(&self) -> RoleId {
RoleId(NonZeroU32::new(PS::deref(&self.metadata.metadata).id.get()).unwrap())
}
pub(super) fn name_bytes(&self) -> &[u8] {
PS::deref_slice(&self.metadata.data)
}
}
impl<PS: ParseStrategy> Parse<PS> for Role<PS>
where
RoleMetadata<PS>: Parse<PS>,
ExtensibleBitmap<PS>: Parse<PS>,
{
type Error = anyhow::Error;
fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
let tail = bytes;
let (metadata, tail) = RoleMetadata::parse(tail)
.map_err(Into::<anyhow::Error>::into)
.context("parsing role metadata")?;
let (role_dominates, tail) = ExtensibleBitmap::parse(tail)
.map_err(Into::<anyhow::Error>::into)
.context("parsing role dominates")?;
let (role_types, tail) = ExtensibleBitmap::parse(tail)
.map_err(Into::<anyhow::Error>::into)
.context("parsing role types")?;
Ok((Self { metadata, role_dominates, role_types }, tail))
}
}
array_type!(RoleMetadata, PS, PS::Output<RoleStaticMetadata>, PS::Slice<u8>);
array_type_validate_deref_both!(RoleMetadata);
impl<PS: ParseStrategy> ValidateArray<RoleStaticMetadata, u8> for RoleMetadata<PS> {
type Error = anyhow::Error;
fn validate_array<'a>(
_metadata: &'a RoleStaticMetadata,
_data: &'a [u8],
) -> Result<(), Self::Error> {
Ok(())
}
}
#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
#[repr(C, packed)]
pub(super) struct RoleStaticMetadata {
length: le::U32,
id: le::U32,
bounds: le::U32,
}
impl Counted for RoleStaticMetadata {
fn count(&self) -> u32 {
self.length.get()
}
}
impl Validate for RoleStaticMetadata {
type Error = anyhow::Error;
fn validate(&self) -> Result<(), Self::Error> {
Ok(())
}
}
#[allow(dead_code)]
pub(super) fn type_has_attribute<'a, PS: ParseStrategy>(
ty: &'a Type<PS>,
attr: &'a Type<PS>,
attribute_maps: &Vec<ExtensibleBitmap<PS>>,
) -> bool {
let type_id = PS::deref(&ty.metadata).id.get();
let type_index = type_id - 1;
let attribute_id = PS::deref(&attr.metadata).id.get();
let attribute_index = attribute_id - 1;
attribute_maps[type_index as usize].is_set(attribute_index)
}
impl<PS: ParseStrategy> Validate for [Type<PS>] {
type Error = anyhow::Error;
fn validate(&self) -> Result<(), Self::Error> {
Ok(())
}
}
array_type!(Type, PS, PS::Output<TypeMetadata>, PS::Slice<u8>);
array_type_validate_deref_both!(Type);
impl<PS: ParseStrategy> Type<PS> {
pub fn name_bytes(&self) -> &[u8] {
PS::deref_slice(&self.data)
}
pub fn id(&self) -> TypeId {
TypeId(NonZeroU32::new(PS::deref(&self.metadata).id.get()).unwrap())
}
pub fn bounded_by(&self) -> Option<TypeId> {
NonZeroU32::new(PS::deref(&self.metadata).bounds.get()).map(|id| TypeId(id))
}
#[allow(dead_code)]
pub fn is_type(&self) -> bool {
PS::deref(&self.metadata).properties.get() == TYPE_PROPERTIES_TYPE
}
#[allow(dead_code)]
pub fn is_alias(&self) -> bool {
PS::deref(&self.metadata).properties.get() == TYPE_PROPERTIES_ALIAS
}
#[allow(dead_code)]
pub fn is_attribute(&self) -> bool {
PS::deref(&self.metadata).properties.get() == TYPE_PROPERTIES_ATTRIBUTE
}
}
impl<PS: ParseStrategy> ValidateArray<TypeMetadata, u8> for Type<PS> {
type Error = anyhow::Error;
fn validate_array<'a>(_metadata: &'a TypeMetadata, _data: &'a [u8]) -> Result<(), Self::Error> {
Ok(())
}
}
#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
#[repr(C, packed)]
pub(super) struct TypeMetadata {
length: le::U32,
id: le::U32,
properties: le::U32,
bounds: le::U32,
}
impl Counted for TypeMetadata {
fn count(&self) -> u32 {
self.length.get()
}
}
impl Validate for TypeMetadata {
type Error = anyhow::Error;
fn validate(&self) -> Result<(), Self::Error> {
Ok(())
}
}
impl<PS: ParseStrategy> Validate for [User<PS>] {
type Error = anyhow::Error;
fn validate(&self) -> Result<(), Self::Error> {
Ok(())
}
}
#[derive(Debug, PartialEq)]
pub(super) struct User<PS: ParseStrategy> {
user_data: UserData<PS>,
roles: ExtensibleBitmap<PS>,
expanded_range: MlsRange<PS>,
default_level: MlsLevel<PS>,
}
impl<PS: ParseStrategy> User<PS> {
pub(super) fn id(&self) -> UserId {
UserId(NonZeroU32::new(PS::deref(&self.user_data.metadata).id.get()).unwrap())
}
pub(super) fn name_bytes(&self) -> &[u8] {
PS::deref_slice(&self.user_data.data)
}
pub(super) fn roles(&self) -> &ExtensibleBitmap<PS> {
&self.roles
}
pub(super) fn mls_range(&self) -> &MlsRange<PS> {
&self.expanded_range
}
}
impl<PS: ParseStrategy> Parse<PS> for User<PS>
where
UserData<PS>: Parse<PS>,
ExtensibleBitmap<PS>: Parse<PS>,
{
type Error = anyhow::Error;
fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
let tail = bytes;
let (user_data, tail) = UserData::parse(tail)
.map_err(Into::<anyhow::Error>::into)
.context("parsing user data")?;
let (roles, tail) = ExtensibleBitmap::parse(tail)
.map_err(Into::<anyhow::Error>::into)
.context("parsing user roles")?;
let (expanded_range, tail) =
MlsRange::parse(tail).context("parsing user expanded range")?;
let (default_level, tail) = MlsLevel::parse(tail).context("parsing user default level")?;
Ok((Self { user_data, roles, expanded_range, default_level }, tail))
}
}
array_type!(UserData, PS, PS::Output<UserMetadata>, PS::Slice<u8>);
array_type_validate_deref_both!(UserData);
impl<PS: ParseStrategy> ValidateArray<UserMetadata, u8> for UserData<PS> {
type Error = anyhow::Error;
fn validate_array<'a>(_metadata: &'a UserMetadata, _data: &'a [u8]) -> Result<(), Self::Error> {
Ok(())
}
}
#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
#[repr(C, packed)]
pub(super) struct UserMetadata {
length: le::U32,
id: le::U32,
bounds: le::U32,
}
impl Counted for UserMetadata {
fn count(&self) -> u32 {
self.length.get()
}
}
impl Validate for UserMetadata {
type Error = anyhow::Error;
fn validate(&self) -> Result<(), Self::Error> {
Ok(())
}
}
#[derive(Debug, PartialEq)]
pub(super) struct MlsLevel<PS: ParseStrategy> {
sensitivity: PS::Output<le::U32>,
categories: ExtensibleBitmap<PS>,
}
impl<PS: ParseStrategy> MlsLevel<PS> {
pub fn sensitivity(&self) -> SensitivityId {
SensitivityId(NonZeroU32::new(PS::deref(&self.sensitivity).get()).unwrap())
}
pub fn categories(&self) -> &ExtensibleBitmap<PS> {
&self.categories
}
}
impl<PS: ParseStrategy> Parse<PS> for MlsLevel<PS>
where
ExtensibleBitmap<PS>: Parse<PS>,
{
type Error = anyhow::Error;
fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
let tail = bytes;
let num_bytes = tail.len();
let (sensitivity, tail) = PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
type_name: "MlsLevelSensitivity",
type_size: std::mem::size_of::<le::U32>(),
num_bytes,
})?;
let (categories, tail) = ExtensibleBitmap::parse(tail)
.map_err(Into::<anyhow::Error>::into)
.context("parsing mls level categories")?;
Ok((Self { sensitivity, categories }, tail))
}
}
#[derive(Debug, PartialEq)]
pub(super) struct MlsRange<PS: ParseStrategy> {
count: PS::Output<le::U32>,
low: MlsLevel<PS>,
high: Option<MlsLevel<PS>>,
}
impl<PS: ParseStrategy> MlsRange<PS> {
pub fn low(&self) -> &MlsLevel<PS> {
&self.low
}
pub fn high(&self) -> &Option<MlsLevel<PS>> {
&self.high
}
}
impl<PS: ParseStrategy> Parse<PS> for MlsRange<PS>
where
ExtensibleBitmap<PS>: Parse<PS>,
{
type Error = anyhow::Error;
fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
let tail = bytes;
let num_bytes = tail.len();
let (count, tail) = PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
type_name: "MlsLevelCount",
type_size: std::mem::size_of::<le::U32>(),
num_bytes,
})?;
let num_bytes = tail.len();
let (sensitivity_low, tail) =
PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
type_name: "MlsLevelSensitivityLow",
type_size: std::mem::size_of::<le::U32>(),
num_bytes,
})?;
let (low_categories, high_level, tail) = if PS::deref(&count).get() > 1 {
let num_bytes = tail.len();
let (sensitivity_high, tail) =
PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
type_name: "MlsLevelSensitivityHigh",
type_size: std::mem::size_of::<le::U32>(),
num_bytes,
})?;
let (low_categories, tail) = ExtensibleBitmap::parse(tail)
.map_err(Into::<anyhow::Error>::into)
.context("parsing mls range low categories")?;
let (high_categories, tail) = ExtensibleBitmap::parse(tail)
.map_err(Into::<anyhow::Error>::into)
.context("parsing mls range high categories")?;
(
low_categories,
Some(MlsLevel { sensitivity: sensitivity_high, categories: high_categories }),
tail,
)
} else {
let (low_categories, tail) = ExtensibleBitmap::parse(tail)
.map_err(Into::<anyhow::Error>::into)
.context("parsing mls range low categories")?;
(low_categories, None, tail)
};
Ok((
Self {
count,
low: MlsLevel { sensitivity: sensitivity_low, categories: low_categories },
high: high_level,
},
tail,
))
}
}
impl<PS: ParseStrategy> Validate for [ConditionalBoolean<PS>] {
type Error = anyhow::Error;
fn validate(&self) -> Result<(), Self::Error> {
Ok(())
}
}
array_type!(ConditionalBoolean, PS, PS::Output<ConditionalBooleanMetadata>, PS::Slice<u8>);
array_type_validate_deref_both!(ConditionalBoolean);
impl<PS: ParseStrategy> ValidateArray<ConditionalBooleanMetadata, u8> for ConditionalBoolean<PS> {
type Error = anyhow::Error;
fn validate_array<'a>(
_metadata: &'a ConditionalBooleanMetadata,
_data: &'a [u8],
) -> Result<(), Self::Error> {
Ok(())
}
}
#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
#[repr(C, packed)]
pub(super) struct ConditionalBooleanMetadata {
id: le::U32,
active: le::U32,
length: le::U32,
}
impl ConditionalBooleanMetadata {
pub(super) fn active(&self) -> bool {
self.active != le::U32::ZERO
}
}
impl Counted for ConditionalBooleanMetadata {
fn count(&self) -> u32 {
self.length.get()
}
}
impl Validate for ConditionalBooleanMetadata {
type Error = anyhow::Error;
fn validate(&self) -> Result<(), Self::Error> {
Ok(())
}
}
impl<PS: ParseStrategy> Validate for [Sensitivity<PS>] {
type Error = anyhow::Error;
fn validate(&self) -> Result<(), Self::Error> {
Ok(())
}
}
#[derive(Debug, PartialEq)]
pub(super) struct Sensitivity<PS: ParseStrategy> {
metadata: SensitivityMetadata<PS>,
level: MlsLevel<PS>,
}
impl<PS: ParseStrategy> Sensitivity<PS> {
pub fn id(&self) -> SensitivityId {
SensitivityId(NonZeroU32::new(PS::deref(&self.level.sensitivity).get()).unwrap())
}
pub fn name_bytes(&self) -> &[u8] {
PS::deref_slice(&self.metadata.data)
}
}
impl<PS: ParseStrategy> Parse<PS> for Sensitivity<PS>
where
SensitivityMetadata<PS>: Parse<PS>,
MlsLevel<PS>: Parse<PS>,
{
type Error = anyhow::Error;
fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
let tail = bytes;
let (metadata, tail) = SensitivityMetadata::parse(tail)
.map_err(Into::<anyhow::Error>::into)
.context("parsing sensitivity metadata")?;
let (level, tail) = MlsLevel::parse(tail)
.map_err(Into::<anyhow::Error>::into)
.context("parsing sensitivity mls level")?;
Ok((Self { metadata, level }, tail))
}
}
impl<PS: ParseStrategy> Validate for Sensitivity<PS> {
type Error = anyhow::Error;
fn validate(&self) -> Result<(), Self::Error> {
NonZeroU32::new(PS::deref(&self.level.sensitivity).get())
.ok_or(ValidateError::NonOptionalIdIsZero)?;
Ok(())
}
}
array_type!(SensitivityMetadata, PS, PS::Output<SensitivityStaticMetadata>, PS::Slice<u8>);
array_type_validate_deref_both!(SensitivityMetadata);
impl<PS: ParseStrategy> ValidateArray<SensitivityStaticMetadata, u8> for SensitivityMetadata<PS> {
type Error = anyhow::Error;
fn validate_array<'a>(
_metadata: &'a SensitivityStaticMetadata,
_data: &'a [u8],
) -> Result<(), Self::Error> {
Ok(())
}
}
#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
#[repr(C, packed)]
pub(super) struct SensitivityStaticMetadata {
length: le::U32,
is_alias: le::U32,
}
impl Counted for SensitivityStaticMetadata {
fn count(&self) -> u32 {
self.length.get()
}
}
impl Validate for SensitivityStaticMetadata {
type Error = anyhow::Error;
fn validate(&self) -> Result<(), Self::Error> {
Ok(())
}
}
impl<PS: ParseStrategy> Validate for [Category<PS>] {
type Error = anyhow::Error;
fn validate(&self) -> Result<(), Self::Error> {
Ok(())
}
}
array_type!(Category, PS, PS::Output<CategoryMetadata>, PS::Slice<u8>);
array_type_validate_deref_both!(Category);
impl<PS: ParseStrategy> Category<PS> {
pub fn id(&self) -> CategoryId {
CategoryId(NonZeroU32::new(PS::deref(&self.metadata).id.get()).unwrap())
}
pub fn name_bytes(&self) -> &[u8] {
PS::deref_slice(&self.data)
}
}
impl<PS: ParseStrategy> ValidateArray<CategoryMetadata, u8> for Category<PS> {
type Error = anyhow::Error;
fn validate_array<'a>(
_metadata: &'a CategoryMetadata,
_data: &'a [u8],
) -> Result<(), Self::Error> {
Ok(())
}
}
#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
#[repr(C, packed)]
pub(super) struct CategoryMetadata {
length: le::U32,
id: le::U32,
is_alias: le::U32,
}
impl Counted for CategoryMetadata {
fn count(&self) -> u32 {
self.length.get()
}
}
impl Validate for CategoryMetadata {
type Error = anyhow::Error;
fn validate(&self) -> Result<(), Self::Error> {
NonZeroU32::new(self.id.get()).ok_or(ValidateError::NonOptionalIdIsZero)?;
Ok(())
}
}