diff --git a/src/security/ace.rs b/src/security/ace.rs index f541825..14a6916 100644 --- a/src/security/ace.rs +++ b/src/security/ace.rs @@ -53,7 +53,7 @@ impl Ace { } } -#[derive(FromPrimitive, ToPrimitive, Serialize, Debug, Clone)] +#[derive(FromPrimitive, ToPrimitive, Serialize, Debug, Clone, PartialEq)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[repr(u8)] pub enum AceType { @@ -134,18 +134,24 @@ impl AceBasic { #[derive(Serialize, Debug, Clone)] pub struct AceObject { pub access_rights: u32, - pub flags: u32, - pub object_type: Guid, - pub inherited_type: Guid, + pub flags: AceObjectFlags, + pub object_type: Option, + pub inherited_type: Option, pub sid: Sid, } impl AceObject { pub fn from_reader(mut reader: &mut R) -> Result { let access_rights = reader.read_u32::()?; - let flags = reader.read_u32::()?; - let object_type = Guid::from_reader(&mut reader)?; - let inherited_type = Guid::from_reader(&mut reader)?; + let flags = AceObjectFlags::from_bits_truncate(reader.read_u32::()?); + let mut object_type = None; + if flags.contains(AceObjectFlags::ACE_OBJECT_TYPE_PRESENT) { + object_type = Some(Guid::from_reader(&mut reader)?); + } + let mut inherited_type = None; + if flags.contains(AceObjectFlags::ACE_INHERITED_OBJECT_TYPE_PRESENT) { + inherited_type = Some(Guid::from_reader(&mut reader)?); + } let sid = Sid::from_reader(&mut reader)?; Ok(AceObject { @@ -238,3 +244,90 @@ bitflags! { } impl_serialize_for_bitflags! {FolderAccessFlags} + +bitflags! { + pub struct AceObjectFlags: u32 { + // Indicates whether the ObjectType and InheritedObjectType + // fields contain valid data + const ACE_OBJECT_TYPE_PRESENT = 0x00000001; + const ACE_INHERITED_OBJECT_TYPE_PRESENT = 0x00000002; + } +} + +impl_serialize_for_bitflags! {AceObjectFlags} + +#[cfg(test)] +mod tests { + use crate::guid::Guid; + use crate::security::ace::{Ace, AceData, AceType}; + use crate::security::sid::Sid; + use std::io::Cursor; + + #[test] + fn test_parses_basic_ace() { + let buffer: &[u8] = &[ + 0x00, 0x00, 0x14, 0x00, 0xff, 0x01, 0x0f, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x05, 0x12, 0x00, 0x00, 0x00, + ]; + let ace = Ace::from_reader(&mut Cursor::new(buffer)).unwrap(); + + assert_eq!(ace.ace_type, AceType::AccessAllowed); + assert_eq!(ace.ace_flags.bits, 0); + assert_eq!(ace.size, 20); + assert!(ace.ace_type.is_basic()); + + if let AceData::Basic(data) = ace.data { + assert_eq!(data.access_rights, 983551); + + let buffer_sid: &[u8] = &[ + 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x12, 0x00, 0x00, 0x00, + ]; + assert_eq!(data.sid, Sid::from_buffer(buffer_sid).unwrap()); + } else { + panic!("ACE content does not match ACE type"); + } + } + + #[test] + fn test_parses_object_ace() { + let buffer: &[u8] = &[ + 0x05, 0x12, 0x38, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0xd6, + 0x47, 0x5b, 0x90, 0x60, 0xb2, 0x40, 0x9f, 0x37, 0x2a, 0x4d, 0xe8, 0x8f, 0x30, 0x63, + 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0x3a, 0x31, + 0xdc, 0x2b, 0x2a, 0x09, 0x33, 0x6f, 0x41, 0x04, 0xa0, 0x51, 0x0e, 0x02, 0x00, 0x00, + ]; + + let ace = Ace::from_reader(&mut Cursor::new(buffer)).unwrap(); + + assert_eq!(ace.ace_type, AceType::AccessAllowedObject); + assert_eq!(ace.ace_flags.bits, 2); + assert_eq!(ace.size, 56); + assert!(ace.ace_type.is_object()); + + if let AceData::Object(data) = ace.data { + assert_eq!(data.access_rights, 48); + + if let Some(ace_guid) = data.object_type { + let buffer_guid: &[u8] = &[ + 0x0f, 0xd6, 0x47, 0x5b, 0x90, 0x60, 0xb2, 0x40, 0x9f, 0x37, 0x2a, 0x4d, 0xe8, + 0x8f, 0x30, 0x63, + ]; + assert_eq!(ace_guid, Guid::from_buffer(buffer_guid).unwrap()); + } else { + panic!("ACE contains an object type GUID"); + } + + if let Some(_) = data.inherited_type { + panic!("ACE does not contain object inherited type"); + } + + let buffer_sid: &[u8] = &[ + 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0x3a, 0x31, + 0xdc, 0x2b, 0x2a, 0x09, 0x33, 0x6f, 0x41, 0x04, 0xa0, 0x51, 0x0e, 0x02, 0x00, 0x00, + ]; + assert_eq!(data.sid, Sid::from_buffer(buffer_sid).unwrap()); + } else { + panic!("ACE content does not match ACE type"); + } + } +}