Skip to main content

windows_erg/security/
acl.rs

1//! ACL and ACE model types.
2
3use super::Sid;
4
5/// Access mask wrapper.
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
7pub struct AccessMask(u32);
8
9impl AccessMask {
10    /// No access rights.
11    pub const NONE: AccessMask = AccessMask(0);
12
13    /// Create a mask from raw bits.
14    pub const fn from_bits(bits: u32) -> Self {
15        AccessMask(bits)
16    }
17
18    /// Return underlying raw bits.
19    pub const fn bits(self) -> u32 {
20        self.0
21    }
22
23    /// Returns true when all bits in `other` are set.
24    pub const fn contains(self, other: AccessMask) -> bool {
25        (self.0 & other.0) == other.0
26    }
27}
28
29impl std::ops::BitOr for AccessMask {
30    type Output = Self;
31
32    fn bitor(self, rhs: Self) -> Self::Output {
33        AccessMask(self.0 | rhs.0)
34    }
35}
36
37impl std::ops::BitOrAssign for AccessMask {
38    fn bitor_assign(&mut self, rhs: Self) {
39        self.0 |= rhs.0;
40    }
41}
42
43impl std::ops::BitAnd for AccessMask {
44    type Output = Self;
45
46    fn bitand(self, rhs: Self) -> Self::Output {
47        AccessMask(self.0 & rhs.0)
48    }
49}
50
51impl std::ops::BitAndAssign for AccessMask {
52    fn bitand_assign(&mut self, rhs: Self) {
53        self.0 &= rhs.0;
54    }
55}
56
57impl std::ops::Not for AccessMask {
58    type Output = Self;
59
60    fn not(self) -> Self::Output {
61        AccessMask(!self.0)
62    }
63}
64
65/// ACE type.
66#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
67pub enum AceType {
68    /// Allows access bits.
69    Allow,
70    /// Denies access bits.
71    Deny,
72}
73
74/// ACE inheritance flags.
75#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
76pub struct InheritanceFlags {
77    /// Child objects inherit this ACE.
78    pub object_inherit: bool,
79    /// Child containers inherit this ACE.
80    pub container_inherit: bool,
81    /// ACE does not apply to current object.
82    pub inherit_only: bool,
83    /// Inheritance is not propagated further.
84    pub no_propagate_inherit: bool,
85}
86
87/// Access control entry.
88#[derive(Debug, Clone, PartialEq, Eq)]
89pub struct Ace {
90    /// Trustee SID.
91    pub trustee: Sid,
92    /// Allow or deny.
93    pub ace_type: AceType,
94    /// Rights for this ACE.
95    pub access_mask: AccessMask,
96    /// Inheritance behavior.
97    pub inheritance: InheritanceFlags,
98    /// True when inherited from parent.
99    pub inherited: bool,
100}
101
102impl Ace {
103    /// Create a new ACE.
104    pub fn new(trustee: Sid, ace_type: AceType, access_mask: AccessMask) -> Self {
105        Self {
106            trustee,
107            ace_type,
108            access_mask,
109            inheritance: InheritanceFlags::default(),
110            inherited: false,
111        }
112    }
113
114    /// Mark ACE as inherited or explicit.
115    pub fn inherited(mut self, inherited: bool) -> Self {
116        self.inherited = inherited;
117        self
118    }
119
120    /// Set inheritance flags.
121    pub fn with_inheritance(mut self, inheritance: InheritanceFlags) -> Self {
122        self.inheritance = inheritance;
123        self
124    }
125}
126
127/// Discretionary access control list.
128#[derive(Debug, Clone, Default, PartialEq, Eq)]
129pub struct Dacl {
130    entries: Vec<Ace>,
131}
132
133impl Dacl {
134    /// Create an empty DACL.
135    pub fn new() -> Self {
136        Self {
137            entries: Vec::new(),
138        }
139    }
140
141    /// Create a DACL from entries.
142    pub fn from_entries(entries: Vec<Ace>) -> Self {
143        Self { entries }
144    }
145
146    /// Return entries.
147    pub fn entries(&self) -> &[Ace] {
148        &self.entries
149    }
150
151    /// Return mutable entries.
152    pub fn entries_mut(&mut self) -> &mut Vec<Ace> {
153        &mut self.entries
154    }
155
156    /// Canonicalize ACE ordering.
157    ///
158    /// Order is explicit deny, explicit allow, inherited deny, inherited allow.
159    pub fn canonicalize(&mut self) {
160        self.entries.sort_by_key(|ace| {
161            let inherited_rank = if ace.inherited { 1u8 } else { 0u8 };
162            let type_rank = match ace.ace_type {
163                AceType::Deny => 0u8,
164                AceType::Allow => 1u8,
165            };
166            (inherited_rank, type_rank)
167        });
168    }
169}
170
171#[cfg(test)]
172mod tests {
173    use super::{AccessMask, Ace, AceType, Dacl};
174    use crate::security::Sid;
175
176    #[test]
177    fn canonicalize_places_explicit_deny_first() {
178        let user = Sid::parse("S-1-5-32-545").expect("valid sid");
179
180        let mut dacl = Dacl::from_entries(vec![
181            Ace::new(user.clone(), AceType::Allow, AccessMask::from_bits(0x2)),
182            Ace::new(user.clone(), AceType::Deny, AccessMask::from_bits(0x1)),
183            Ace::new(user.clone(), AceType::Allow, AccessMask::from_bits(0x4)).inherited(true),
184        ]);
185
186        dacl.canonicalize();
187
188        assert_eq!(dacl.entries()[0].ace_type, AceType::Deny);
189        assert!(!dacl.entries()[0].inherited);
190    }
191}