Skip to main content

windows_permissions/structures/
acl.rs

1use crate::{constants, wrappers, Ace, Trustee};
2use std::fmt;
3use std::io;
4use winapi::shared::winerror::ERROR_INVALID_PARAMETER;
5use winapi::um::winnt::ACL;
6
7/// An entry in an access control list (ACL).
8#[repr(C)]
9pub struct Acl {
10    _opaque: [u8; 0],
11}
12
13impl Acl {
14    fn internal_type_reference(&self) -> &ACL {
15        unsafe { &*(self as *const _ as *const _) }
16    }
17
18    /// Determine what rights the given `Trustee` has under this ACL
19    ///
20    /// ```
21    /// use windows_permissions::{LocalBox, Trustee, Sid, SecurityDescriptor};
22    /// use windows_permissions::constants::AccessRights;
23    ///
24    /// // Allow a particular user FA (File All) and give all users FR (File Read)
25    /// let sd = "D:(A;;FA;;;S-1-5-20-12345)(A;;FR;;;WD)"
26    ///     .parse::<LocalBox<SecurityDescriptor>>().unwrap();
27    /// let acl = sd.dacl().unwrap();
28    ///
29    /// let sid1: LocalBox<Sid> = "S-1-5-20-12345".parse().unwrap();
30    /// let sid2: LocalBox<Sid> = "WD".parse().unwrap();
31    ///
32    /// let trustee1: Trustee = sid1.as_ref().into();
33    /// let trustee2: Trustee = sid2.as_ref().into();
34    ///
35    /// assert_eq!(acl.effective_rights(&trustee1).unwrap(), AccessRights::FileAllAccess);
36    /// assert_eq!(acl.effective_rights(&trustee2).unwrap(), AccessRights::FileGenericRead);
37    /// ```
38    pub fn effective_rights(&self, trustee: &Trustee) -> io::Result<constants::AccessRights> {
39        wrappers::GetEffectiveRightsFromAcl(self, trustee)
40    }
41
42    /// Determine the number of ACEs in this ACL
43    ///
44    /// ```
45    /// use windows_permissions::{LocalBox, SecurityDescriptor};
46    ///
47    /// let sd = "D:(A;;GA;;;S-1-5-20-12345)(A;;GR;;;WD)"
48    ///     .parse::<LocalBox<SecurityDescriptor>>().unwrap();
49    ///
50    /// assert_eq!(sd.dacl().unwrap().len(), 2);
51    /// ```
52    #[allow(clippy::len_without_is_empty)]
53    pub fn len(&self) -> u32 {
54        wrappers::GetAclInformationSize(self)
55            .expect("GetAclInformation failed on valid ACL")
56            .AceCount
57    }
58
59    /// Get an ACE by index
60    ///
61    /// Returns `None` if there are too few ACEs to satisfy the request.
62    ///
63    /// ```
64    /// use windows_permissions::{LocalBox, Sid, SecurityDescriptor};
65    /// use windows_permissions::constants::{AceType::*, AccessRights};
66    ///
67    /// let sd = "D:(A;;GA;;;S-1-5-20-12345)(A;;GR;;;WD)"
68    ///     .parse::<LocalBox<SecurityDescriptor>>().unwrap();
69    /// let acl = sd.dacl().unwrap();
70    ///
71    /// let sid1: LocalBox<Sid> = "S-1-5-20-12345".parse().unwrap();
72    /// let sid2: LocalBox<Sid> = "WD".parse().unwrap();
73    ///
74    /// assert_eq!(acl.get_ace(0).unwrap().ace_type(), ACCESS_ALLOWED_ACE_TYPE);
75    /// assert_eq!(acl.get_ace(0).unwrap().mask(), AccessRights::GenericAll);
76    /// assert_eq!(acl.get_ace(0).unwrap().sid(), Some(&*sid1));
77    ///
78    /// assert_eq!(acl.get_ace(1).unwrap().ace_type(), ACCESS_ALLOWED_ACE_TYPE);
79    /// assert_eq!(acl.get_ace(1).unwrap().mask(), AccessRights::GenericRead);
80    /// assert_eq!(acl.get_ace(1).unwrap().sid(), Some(&*sid2));
81    ///
82    /// assert!(acl.get_ace(2).is_none());
83    /// ```
84    pub fn get_ace(&self, index: u32) -> Option<&Ace> {
85        match wrappers::GetAce(self, index) {
86            Ok(ace) => Some(ace),
87            Err(ref e) if e.raw_os_error() == Some(ERROR_INVALID_PARAMETER as i32) => None,
88            other_err => {
89                other_err.expect("GetAce returned error on valid Ace");
90                unreachable!() // Because other_err will always fail the expect
91            }
92        }
93    }
94
95    /// Get the ACL's revision level
96    ///
97    /// ```
98    /// use windows_permissions::{LocalBox, SecurityDescriptor, Acl};
99    /// use windows_permissions::constants::AclRevision::*;
100    ///
101    /// let simple_acl_sd: LocalBox<SecurityDescriptor> = "D:(A;;;;;WD)".parse().unwrap();
102    /// let complex_acl_sd: LocalBox<SecurityDescriptor> = "D:(OA;;;294be2fb-d1ca-4aa2-aa06-ab98a8b5556d;;WD)".parse().unwrap();
103    ///
104    /// assert_eq!(simple_acl_sd.dacl().unwrap().revision_level(), ACL_REVISION);
105    /// assert_eq!(complex_acl_sd.dacl().unwrap().revision_level(), ACL_REVISION_DS);
106    /// ```
107    pub fn revision_level(&self) -> constants::AclRevision {
108        constants::AclRevision::from_raw(self.internal_type_reference().AclRevision)
109            .expect("Unknown revision level")
110    }
111}
112
113impl fmt::Debug for Acl {
114    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
115        let mut map = fmt.debug_map();
116        map.entry(&"len", &self.len());
117        map.finish()
118    }
119}
120
121#[cfg(test)]
122mod test {
123    use super::*;
124
125    use crate::constants::AceType;
126    use crate::{LocalBox, SecurityDescriptor};
127
128    #[test]
129    fn get_len() -> io::Result<()> {
130        let limit = 100;
131
132        for dacl_count in 0..limit {
133            let sacl_count = limit - dacl_count - 1;
134
135            // Looks like "D:(A;;;;;WD)(A;;;;;WD)(...)S:(AU;;;;;WD)(...)"
136            // A (SDDL_ACCESS_ALLOWED) isn't valid for SACLs, AU (SDDL_AUDIT) is valid
137            let mut sddl_string = String::new();
138            sddl_string.push_str("D:");
139            sddl_string.push_str(&"(A;;;;;WD)".repeat(dacl_count));
140            sddl_string.push_str("S:");
141            sddl_string.push_str(&"(AU;;;;;WD)".repeat(sacl_count));
142
143            let sd: LocalBox<SecurityDescriptor> = sddl_string.parse()?;
144
145            assert_eq!(sd.dacl().unwrap().len(), dacl_count as u32);
146            assert_eq!(sd.sacl().unwrap().len(), sacl_count as u32);
147        }
148
149        Ok(())
150    }
151
152    #[test]
153    fn get_from_sddl() -> io::Result<()> {
154        let mut sddl = "D:".to_string();
155        let limit = 10;
156
157        for i in 0..limit {
158            sddl.push_str(&format!("(A;;;;;S-1-5-{})", i));
159        }
160
161        let sd: LocalBox<SecurityDescriptor> = sddl.parse()?;
162        let dacl = sd.dacl().unwrap();
163
164        // Try to get each one
165        for i in 0..limit {
166            let ace = dacl.get_ace(i).unwrap();
167            assert_eq!(ace.ace_type(), AceType::ACCESS_ALLOWED_ACE_TYPE);
168        }
169
170        // Off the end
171        assert!(dacl.get_ace(limit).is_none());
172
173        Ok(())
174    }
175}