sddl 0.1.4

a library to parse and analyse SDDL Strings
Documentation
use lalrpop_util::lalrpop_mod;
lalrpop_mod!(pub (crate) parser, "/security_descriptor/parser.rs");

use std::{fmt::Display, io::Cursor};

use binrw::{binread, BinReaderExt, FilePtr};
use getset::Getters;
use serde::Serialize;

use crate::*;
/// <https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/2918391b-75b9-4eeb-83f0-7fdc04a5c6c9>
#[binread]
#[derive(Eq, PartialEq, Getters, Serialize)]
#[getset(get = "pub")]
pub struct SecurityDescriptor {
    #[serde(skip)]
    sd_offset: Offset,

    #[br(assert(revision == 1))]
    #[bw(assert(*revision == 1))]
    revision: u8,

    #[getset(skip)]
    #[br(temp)]
    #[serde(skip)]
    _reserved1: u8,

    flags: ControlFlags,

    #[serde(skip)]
    #[br(little,temp,
        offset=sd_offset.0,
        if(! flags.as_ref().contains(ControlFlag::OwnerDefaulted)))
        ]
    owner_ref: Option<FilePtr<u32, Sid>>,

    #[serde(skip)]
    #[br(little,temp,
        offset=sd_offset.0,
        if(! flags.as_ref().contains(ControlFlag::GroupDefaulted)))
        ]
    group_ref: Option<FilePtr<u32, Sid>>,

    #[serde(skip)]
    #[br(little,temp,
        offset=sd_offset.0,
        if(flags.as_ref().contains(ControlFlag::SystemAclPresent)),
        args{inner: (flags, acl::Type::SACL)})
        ]
    sacl_ref: Option<FilePtr<u32, Acl>>,

    #[serde(skip)]
    #[br(temp, if(! flags.as_ref().contains(ControlFlag::SystemAclPresent), 0))]
    _sacl_ref: u32,

    #[serde(skip)]
    #[br(little,temp,
        offset=sd_offset.0,
        if(flags.as_ref().contains(ControlFlag::DiscretionaryAclPresent)),
        args{inner: (flags, acl::Type::DACL)})
        ]
    dacl_ref: Option<FilePtr<u32, Acl>>,

    #[serde(skip)]
    #[br(temp, if(! flags.as_ref().contains(ControlFlag::DiscretionaryAclPresent), 0))]
    _dacl_ref: u32,

    #[br(calc=owner_ref.as_ref().map(|d| d.value.clone()))]
    owner: Option<Sid>,

    #[br(calc=group_ref.as_ref().map(|d| d.value.clone()))]
    group: Option<Sid>,

    #[br(calc=dacl_ref.as_ref().map(|d| d.value.clone()))]
    dacl: Option<Acl>,

    #[br(calc=sacl_ref.as_ref().map(|d| d.value.clone()))]
    sacl: Option<Acl>,
}

impl SecurityDescriptor {
    /// parses a binary security descriptor
    ///
    /// ```rust
    /// use sddl::{ControlFlags, SecurityDescriptor, Acl};
    ///
    /// let binary_data = [0x01, 0x00, 0x14, 0xb0, 0x90, 0x00, 0x00,
    ///     0x00, 0xa0, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,
    ///     0x00, 0x02, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x80, 0x14,
    ///     0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
    ///     0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x60, 0x00, 0x04, 0x00, 0x00,
    ///     0x00, 0x00, 0x03, 0x18, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x01, 0x02, 0x00,
    ///     0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00,
    ///     0x00, 0x00, 0x03, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x02, 0x00,
    ///     0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x20, 0x02, 0x00,
    ///     0x00, 0x00, 0x03, 0x14, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x01, 0x00,
    ///     0x00, 0x00, 0x00, 0x00, 0x05, 0x12, 0x00, 0x00, 0x00, 0x00, 0x03, 0x14,
    ///     0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
    ///     0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
    ///     0x05, 0x20, 0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00,
    ///     0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x20, 0x02, 0x00,
    ///     0x00];
    /// let security_descriptor = SecurityDescriptor::from_bytes(&binary_data).unwrap();
    ///
    pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
        let mut cursor = Cursor::new(bytes);
        Ok(cursor.read_le()?)
    }

    pub fn new(
        owner: Option<Sid>,
        group: Option<Sid>,
        dacl: Option<Acl>,
        sacl: Option<Acl>,
    ) -> Self {
        let mut flags = ControlFlags::EMPTY;
        if owner.is_some() {
            flags |= ControlFlag::OwnerDefaulted
        }
        if group.is_some() {
            flags |= ControlFlag::GroupDefaulted
        }
        if let Some(dacl) = &dacl {
            flags |= *dacl.control_flags() | ControlFlag::DiscretionaryAclPresent;
        }
        if let Some(sacl) = &sacl {
            flags |= *sacl.control_flags() | ControlFlag::SystemAclPresent;
        }
        Self {
            sd_offset: Offset(0),
            revision: 1,
            flags,
            owner,
            group,
            sacl,
            dacl,
        }
    }

    pub fn acl_flags_as_sddl_string(
        &self,
        acl_flags: &[(control_flags::ControlFlag, &str)],
    ) -> String {
        acl_flags
            .iter()
            .filter(|(f, _)| self.flags().as_ref().contains(*f))
            .map(|(_, s)| *s)
            .collect::<Vec<&str>>()
            .join("")
    }

    pub fn from_sddl(value: &str, domain_rid: Option<&[u32]>) -> Result<Self, Error> {
        Ok(
            crate::security_descriptor::parser::SecurityDescriptorParser::new()
                .parse(domain_rid, value)?,
        )
    }
}

const DACL_FLAGS: [(control_flags::ControlFlag, &str); 3] = [
    (ControlFlag::DiscretionaryAclProtected, SDDL_PROTECTED),
    (
        ControlFlag::DiscretionaryAclAutoInheritRequired,
        SDDL_AUTO_INHERIT_REQ,
    ),
    (
        ControlFlag::DiscretionaryAclAutoInherited,
        SDDL_AUTO_INHERITED,
    ),
];

const SACL_FLAGS: [(control_flags::ControlFlag, &str); 3] = [
    (ControlFlag::SystemAclProtected, SDDL_PROTECTED),
    (
        ControlFlag::SystemAclAutoInheritRequired,
        SDDL_AUTO_INHERIT_REQ,
    ),
    (ControlFlag::SystemAclAutoInherited, SDDL_AUTO_INHERITED),
];

impl Display for SecurityDescriptor {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        if let Some(owner) = self.owner() {
            write!(f, "{SDDL_OWNER}{SDDL_DELIMINATOR}{owner}")?;
        }
        if let Some(group) = self.group() {
            write!(f, "{SDDL_GROUP}{SDDL_DELIMINATOR}{group}")?;
        }
        if let Some(dacl) = self.dacl() {
            let flags = self.acl_flags_as_sddl_string(&DACL_FLAGS);
            write!(f, "{SDDL_DACL}{SDDL_DELIMINATOR}{flags}")?;
            dacl.fmt(f)?;
        }
        if let Some(sacl) = self.sacl() {
            let flags = self.acl_flags_as_sddl_string(&SACL_FLAGS);
            write!(f, "{SDDL_DACL}{SDDL_DELIMINATOR}{flags}")?;
            sacl.fmt(f)?;
        }
        Ok(())
    }
}

impl TryFrom<&[u8]> for SecurityDescriptor {
    type Error = Error;

    fn try_from(value: &[u8]) -> Result<SecurityDescriptor, Self::Error> {
        Self::from_bytes(value)
    }
}