smb_dtyp/security/
ace.rs

1//! MS-DTYP 2.4.4: ACE
2
3use binrw::io::TakeSeekExt;
4use binrw::prelude::*;
5use modular_bitfield::prelude::*;
6
7use crate::{binrw_util::prelude::*, guid::Guid};
8
9use super::SID;
10
11/// Macro for defining a bitfield for an access mask.
12///
13/// In windows, the upper word of access mask dword is always a set of common fields.
14/// Therefore, implementing this macro helps saving bunch of code for different access masks.
15///
16/// It's input is the name of the struct to generate, and in {}, the list of fields to add
17/// before the common fields. include support for `#[skip]` fields, without visibility (all fields are public).
18#[macro_export]
19macro_rules! access_mask {
20    (
21        $vis:vis struct $name:ident {
22        $(
23            $(#[$field_meta:meta])*
24            $field_name:ident : $field_ty:ty,
25        )*
26    }) => {
27
28    #[bitfield]
29    #[derive(BinWrite, BinRead, Debug, Default, Clone, Copy, PartialEq, Eq)]
30    #[bw(map = |&x| Self::into_bytes(x))]
31    #[br(map = Self::from_bytes)]
32        $vis struct $name {
33            // User fields
34            $(
35                $(#[$field_meta])*
36                pub $field_name : $field_ty,
37            )*
38
39            pub delete: bool,
40            pub read_control: bool,
41            pub write_dacl: bool,
42            pub write_owner: bool,
43
44            pub synchronize: bool,
45            #[skip]
46            __: B3,
47
48            pub access_system_security: bool,
49            pub maximum_allowed: bool,
50            #[skip]
51            __: B2,
52
53            pub generic_all: bool,
54            pub generic_execute: bool,
55            pub generic_write: bool,
56            pub generic_read: bool,
57        }
58    };
59
60}
61
62#[binrw::binrw]
63#[derive(Debug, PartialEq, Eq, Clone)]
64pub struct ACE {
65    #[bw(calc = value.get_type())]
66    pub ace_type: AceType,
67    pub ace_flags: AceFlags,
68    #[bw(calc = PosMarker::default())]
69    _ace_size: PosMarker<u16>,
70    #[br(args(ace_type))]
71    #[br(map_stream = |s| s.take_seek(_ace_size.value as u64 - Self::HEADER_SIZE))]
72    #[bw(write_with = PosMarker::write_size_plus, args(&_ace_size, Self::HEADER_SIZE))]
73    pub value: AceValue,
74}
75
76impl ACE {
77    const HEADER_SIZE: u64 = 4;
78
79    /// Returns the type of the ACE.
80    ///
81    /// Can also be accessed by [`ACE::value`][`ACE::value`][`.get_type()`][`AceValue::get_type()`].
82    #[inline]
83    pub fn ace_type(&self) -> AceType {
84        self.value.get_type()
85    }
86}
87
88macro_rules! make_ace_value {
89    (
90        $($type:ident($val:ident),)+
91    ) => {
92        paste::paste! {
93
94#[binrw::binrw]
95#[derive(Debug, PartialEq, Eq, Clone)]
96#[br(import(ace_type: AceType))]
97pub enum AceValue {
98    $(
99        #[br(pre_assert(matches!(ace_type, AceType::$type)))]
100        $type($val),
101    )+
102}
103
104impl AceValue {
105    pub fn get_type(&self) -> AceType {
106        match self {
107            $(
108                AceValue::$type(_) => AceType::$type,
109            )+
110        }
111    }
112
113    $(
114        pub fn [<unwrap_ $type:snake>](&self) -> &$val {
115            match self {
116                AceValue::$type(v) => v,
117                _ => panic!("Called unwrap_{} on a different AceValue variant", stringify!($type).to_lowercase()),
118            }
119        }
120
121        pub fn [<as_ $type:snake>](&self) -> Option<&$val> {
122            match self {
123                AceValue::$type(v) => Some(v),
124                _ => None,
125            }
126        }
127
128        pub fn [<as_mut_ $type:snake>](&mut self) -> Option<&mut $val> {
129            match self {
130                AceValue::$type(v) => Some(v),
131                _ => None,
132            }
133        }
134    )+
135}
136
137        }
138    };
139}
140
141make_ace_value! {
142    AccessAllowed(AccessAce),
143    AccessDenied(AccessAce),
144    SystemAudit(AccessAce),
145    AccessAllowedObject(AccessObjectAce),
146    AccessDeniedObject(AccessObjectAce),
147    SystemAuditObject(AccessObjectAce),
148    AccessAllowedCallback(AccessCallbackAce),
149    AccessDeniedCallback(AccessCallbackAce),
150    AccessAllowedCallbackObject(AccessObjectCallbackAce),
151    AccessDeniedCallbackObject(AccessObjectCallbackAce),
152    SystemAuditCallback(AccessCallbackAce),
153    SystemAuditCallbackObject(AccessObjectCallbackAce),
154    SystemMandatoryLabel(SystemMandatoryLabelAce),
155    SystemResourceAttribute(SystemResourceAttributeAce),
156    SystemScopedPolicyId(AccessAce),
157}
158
159impl AceValue {
160    /// Returns true if the ACE is an "access allowed" type.
161    pub fn is_access_allowed(&self) -> bool {
162        matches!(
163            self.get_type(),
164            AceType::AccessAllowed
165                | AceType::AccessAllowedObject
166                | AceType::AccessAllowedCallback
167                | AceType::AccessAllowedCallbackObject
168        )
169    }
170
171    /// Returns true if the ACE is an "access denied" type.
172    pub fn is_access_denied(&self) -> bool {
173        matches!(
174            self.get_type(),
175            AceType::AccessDenied
176                | AceType::AccessDeniedObject
177                | AceType::AccessDeniedCallback
178                | AceType::AccessDeniedCallbackObject
179        )
180    }
181}
182
183#[binrw::binrw]
184#[derive(Debug, PartialEq, Eq, Clone)]
185pub struct AccessAce {
186    pub access_mask: AccessMask,
187    pub sid: SID,
188}
189
190access_mask! {
191pub struct AccessMask {
192    common: B16,
193}}
194
195access_mask! {
196pub struct ObjectAccessMask {
197    crate_child: bool,
198    delete_child: bool,
199    #[skip]
200    __: bool,
201    ds_self: bool,
202
203    read_prop: bool,
204    write_prop: bool,
205    #[skip]
206    __: B2,
207
208    control_access: bool,
209    #[skip]
210    __: B7,
211}}
212
213access_mask! {
214pub struct MandatoryLabelAccessMask {
215    no_write_up: bool,
216    no_read_up: bool,
217    no_execute_up: bool,
218    #[skip]
219    __: B13,
220}}
221
222#[binrw::binrw]
223#[derive(Debug, PartialEq, Eq, Clone)]
224pub struct AccessObjectAce {
225    pub access_mask: ObjectAccessMask,
226    #[bw(calc = ObjectAceFlags::new().with_object_type_present(object_type.is_some()).with_inherited_object_type_present(inherited_object_type.is_some()))]
227    pub flags: ObjectAceFlags,
228    #[br(if(flags.object_type_present()))]
229    pub object_type: Option<Guid>,
230    #[br(if(flags.inherited_object_type_present()))]
231    pub inherited_object_type: Option<Guid>,
232    pub sid: SID,
233}
234
235#[bitfield]
236#[derive(BinWrite, BinRead, Debug, Default, Clone, Copy, PartialEq, Eq)]
237#[bw(map = |&x| Self::into_bytes(x))]
238#[br(map = Self::from_bytes)]
239pub struct ObjectAceFlags {
240    pub object_type_present: bool,
241    pub inherited_object_type_present: bool,
242    #[skip]
243    __: B30,
244}
245
246#[binrw::binrw]
247#[derive(Debug, PartialEq, Eq, Clone)]
248pub struct AccessCallbackAce {
249    pub access_mask: AccessMask,
250    pub sid: SID,
251    #[br(parse_with = binrw::helpers::until_eof)]
252    pub application_data: Vec<u8>,
253}
254
255#[binrw::binrw]
256#[derive(Debug, PartialEq, Eq, Clone)]
257pub struct AccessObjectCallbackAce {
258    pub access_mask: ObjectAccessMask,
259    #[bw(calc = ObjectAceFlags::new().with_object_type_present(object_type.is_some()).with_inherited_object_type_present(inherited_object_type.is_some()))]
260    pub flags: ObjectAceFlags,
261    #[br(if(flags.object_type_present()))]
262    pub object_type: Option<Guid>,
263    #[br(if(flags.inherited_object_type_present()))]
264    pub inherited_object_type: Option<Guid>,
265    pub sid: SID,
266    #[br(parse_with = binrw::helpers::until_eof)]
267    pub application_data: Vec<u8>,
268}
269
270#[binrw::binrw]
271#[derive(Debug, PartialEq, Eq, Clone)]
272pub struct SystemMandatoryLabelAce {
273    pub mask: MandatoryLabelAccessMask,
274    pub sid: SID,
275}
276#[binrw::binrw]
277#[derive(Debug, PartialEq, Eq, Clone)]
278pub struct SystemResourceAttributeAce {
279    pub mask: AccessMask,
280    pub sid: SID,
281    pub attribute_data: ClaimSecurityAttributeRelativeV1,
282}
283
284#[binrw::binrw]
285#[derive(Debug, PartialEq, Eq, Clone)]
286pub struct ClaimSecurityAttributeRelativeV1 {
287    #[bw(calc = PosMarker::default())]
288    _name: PosMarker<u32>, // TODO: Figure out what this is.
289    pub value_type: ClaimSecurityAttributeType,
290    #[bw(calc = 0)]
291    #[br(assert(reserved == 0))]
292    reserved: u16,
293    pub flags: FciClaimSecurityAttributes,
294    value_count: u32,
295    #[br(parse_with = binrw::helpers::until_eof)]
296    pub value: Vec<u8>, // TODO: Use concrete types
297}
298
299#[binrw::binrw]
300#[derive(Debug, PartialEq, Eq, Clone, Copy)]
301#[brw(repr(u16))]
302pub enum ClaimSecurityAttributeType {
303    None = 0,
304    Int64 = 1,
305    Uint64 = 2,
306    String = 3,
307    SID = 4,
308    Boolean = 5,
309    OctetString = 6,
310}
311
312#[bitfield]
313#[derive(BinWrite, BinRead, Debug, Default, Clone, Copy, PartialEq, Eq)]
314#[bw(map = |&x| Self::into_bytes(x))]
315#[br(map = Self::from_bytes)]
316pub struct FciClaimSecurityAttributes {
317    pub non_inheritable: bool,
318    pub value_case_sensitive: bool,
319    pub use_for_deny_only: bool,
320    pub disabled_by_default: bool,
321
322    pub disabled: bool,
323    pub mandatory: bool,
324    #[skip]
325    __: B2,
326
327    pub manual: bool,
328    pub policy_derived: bool,
329    #[skip]
330    __: B6,
331}
332
333#[binrw::binrw]
334#[derive(Debug, PartialEq, Eq, Clone, Copy)]
335#[brw(repr(u8))]
336pub enum AceType {
337    AccessAllowed = 0,
338    AccessDenied = 1,
339    SystemAudit = 2,
340    SystemAlarm = 3,
341    AccessAllowedCompound = 4,
342    AccessAllowedObject = 5,
343    AccessDeniedObject = 6,
344    SystemAuditObject = 7,
345    SystemAlarmObject = 8,
346    AccessAllowedCallback = 9,
347    AccessDeniedCallback = 10,
348    AccessAllowedCallbackObject = 11,
349    AccessDeniedCallbackObject = 12,
350    SystemAuditCallback = 13,
351    SystemAlarmCallback = 14,
352    SystemAuditCallbackObject = 15,
353    SystemAlarmCallbackObject = 16,
354    SystemMandatoryLabel = 17,
355    SystemResourceAttribute = 18,
356    SystemScopedPolicyId = 19,
357}
358
359#[bitfield]
360#[derive(BinWrite, BinRead, Debug, Default, Clone, Copy, PartialEq, Eq)]
361#[bw(map = |&x| Self::into_bytes(x))]
362#[br(map = Self::from_bytes)]
363pub struct AceFlags {
364    pub object_inherit: bool,
365    pub container_inherit: bool,
366    pub no_propagate_inherit: bool,
367    pub inherit_only: bool,
368
369    pub inherited: bool,
370    #[skip]
371    __: bool,
372    pub successful_access: bool,
373    pub failed_access: bool,
374}