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}