smb_dtyp/security/
ace.rs

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