1use crate::constants::{AccessRights, AceFlags, AceType};
2use crate::Sid;
3use std::fmt;
4use std::mem;
5use std::ptr::NonNull;
6use winapi::um::winnt::ACE_HEADER;
7
8#[repr(C)]
14pub struct Ace {
15 header: ACE_HEADER,
16}
17
18impl Drop for Ace {
19 fn drop(&mut self) {
20 unreachable!("Ace should only be borrowed")
21 }
22}
23
24impl Ace {
25 pub unsafe fn ref_from_nonnull<'s>(ptr: NonNull<ACE_HEADER>) -> &'s Self {
33 mem::transmute(ptr)
34 }
35
36 pub fn ace_type(&self) -> AceType {
38 AceType::from_raw(self.header.AceType).expect("ACE had invalid header byte")
39 }
40
41 pub fn flags(&self) -> AceFlags {
43 debug_assert!(AceFlags::from_bits(self.header.AceFlags).is_some());
44 AceFlags::from_bits_truncate(self.header.AceFlags)
45 }
46
47 pub fn mask(&self) -> AccessRights {
49 use winapi::um::winnt::*;
50
51 macro_rules! mask_mapping {
52 ($slf:ident ; $($t:ident => $b:ty),*) => {{
53 match $slf.ace_type() {
54 $(
55 AceType::$t => AccessRights::from_bits_truncate(
56 (*(&$slf.header as *const _ as *mut $b)).Mask,
57 ),
58 )*
59 }
60 }}
61 }
62
63 unsafe {
64 mask_mapping! {self;
65 ACCESS_ALLOWED_ACE_TYPE => ACCESS_ALLOWED_ACE,
66 ACCESS_ALLOWED_CALLBACK_ACE_TYPE => ACCESS_ALLOWED_CALLBACK_ACE,
67 ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE => ACCESS_ALLOWED_CALLBACK_OBJECT_ACE,
68 ACCESS_ALLOWED_OBJECT_ACE_TYPE => ACCESS_ALLOWED_OBJECT_ACE,
69 ACCESS_DENIED_ACE_TYPE => ACCESS_DENIED_ACE,
70 ACCESS_DENIED_CALLBACK_ACE_TYPE => ACCESS_DENIED_ACE,
71 ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE => ACCESS_DENIED_CALLBACK_OBJECT_ACE,
72 ACCESS_DENIED_OBJECT_ACE_TYPE => ACCESS_DENIED_OBJECT_ACE,
73 SYSTEM_AUDIT_ACE_TYPE => SYSTEM_AUDIT_ACE,
74 SYSTEM_AUDIT_CALLBACK_ACE_TYPE => SYSTEM_AUDIT_CALLBACK_ACE,
75 SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE => SYSTEM_AUDIT_CALLBACK_ACE,
76 SYSTEM_AUDIT_OBJECT_ACE_TYPE => SYSTEM_AUDIT_OBJECT_ACE,
77 SYSTEM_MANDATORY_LABEL_ACE_TYPE => SYSTEM_MANDATORY_LABEL_ACE,
78 SYSTEM_RESOURCE_ATTRIBUTE_ACE_TYPE => SYSTEM_RESOURCE_ATTRIBUTE_ACE,
79 SYSTEM_SCOPED_POLICY_ID_ACE_TYPE => SYSTEM_SCOPED_POLICY_ID_ACE
80 }
81 }
82 }
83
84 pub fn sid(&self) -> Option<&Sid> {
86 use winapi::um::winnt::*;
87
88 macro_rules! get_sid {
89 ($slf:ident ; $ace_type:ty ; $sid_field:ident ) => {
90 Some(
91 &*(&(*(&$slf.header as *const ACE_HEADER as *const $ace_type)).$sid_field
92 as *const _ as *const Sid),
93 )
94 };
95 ($slf:ident ; $ace_type:ty) => {
96 get_sid!($slf ; $ace_type ; SidStart)
97 };
98 ($slf:ident ; $ace_type:ty ; $field_none:ident , $field_one:ident, $field_both:ident) => {{
99 let flags = (*(&$slf.header as *const ACE_HEADER as *const $ace_type)).Flags;
100 let obj_pres = flags & winapi::um::winnt::ACE_OBJECT_TYPE_PRESENT != 0;
101 let inh_pres = flags & winapi::um::winnt::ACE_INHERITED_OBJECT_TYPE_PRESENT != 0;
102 match (obj_pres, inh_pres) {
103 (false, false) => get_sid!($slf ; $ace_type ; $field_none),
104 (true, false) => get_sid!($slf ; $ace_type ; $field_one),
105 (false, true ) => get_sid!($slf ; $ace_type ; $field_one),
106 (true, true ) => get_sid!($slf ; $ace_type ; $field_both),
107 }}
108 };
109 }
110
111 unsafe {
112 match self.ace_type() {
113 AceType::ACCESS_ALLOWED_ACE_TYPE => get_sid!(self; ACCESS_ALLOWED_ACE),
114 AceType::ACCESS_ALLOWED_CALLBACK_ACE_TYPE => {
115 get_sid!(self; ACCESS_ALLOWED_CALLBACK_ACE)
116 }
117 AceType::ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE => {
118 get_sid!(self; ACCESS_ALLOWED_CALLBACK_OBJECT_ACE;
119 ObjectType, InheritedObjectType, SidStart)
120 }
121 AceType::ACCESS_ALLOWED_OBJECT_ACE_TYPE => {
122 get_sid!(self; ACCESS_ALLOWED_OBJECT_ACE;
123 ObjectType, InheritedObjectType, SidStart)
124 }
125 AceType::ACCESS_DENIED_ACE_TYPE => get_sid!(self; ACCESS_DENIED_ACE),
126 AceType::ACCESS_DENIED_CALLBACK_ACE_TYPE => get_sid!(self; ACCESS_DENIED_ACE),
127 AceType::ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE => {
128 get_sid!(self; ACCESS_DENIED_CALLBACK_OBJECT_ACE;
129 ObjectType, InheritedObjectType, SidStart)
130 }
131 AceType::ACCESS_DENIED_OBJECT_ACE_TYPE => get_sid!(self; ACCESS_DENIED_OBJECT_ACE;
132 ObjectType, InheritedObjectType, SidStart),
133 AceType::SYSTEM_AUDIT_ACE_TYPE => get_sid!(self; SYSTEM_AUDIT_ACE),
134 AceType::SYSTEM_AUDIT_CALLBACK_ACE_TYPE => {
135 get_sid!(self; SYSTEM_AUDIT_CALLBACK_ACE)
136 }
137 AceType::SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE => {
138 get_sid!(self; SYSTEM_AUDIT_CALLBACK_ACE; SidStart)
139 }
140 AceType::SYSTEM_AUDIT_OBJECT_ACE_TYPE => get_sid!(self; SYSTEM_AUDIT_OBJECT_ACE;
141 ObjectType, InheritedObjectType, SidStart),
142 AceType::SYSTEM_MANDATORY_LABEL_ACE_TYPE => {
143 get_sid!(self; SYSTEM_MANDATORY_LABEL_ACE)
144 }
145 AceType::SYSTEM_SCOPED_POLICY_ID_ACE_TYPE => {
146 get_sid!(self; SYSTEM_SCOPED_POLICY_ID_ACE)
147 }
148 AceType::SYSTEM_RESOURCE_ATTRIBUTE_ACE_TYPE => None, }
150 }
151 }
152}
153
154impl fmt::Debug for Ace {
155 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
156 let mut map = fmt.debug_map();
157 map.entry(&"ace_type", &self.ace_type());
158 map.entry(&"flags", &self.flags());
159 map.finish()
160 }
161}
162
163#[cfg(test)]
164mod test {
165 use super::*;
166 use crate::{wrappers, LocalBox, SecurityDescriptor};
167
168 enum DaclSacl {
169 Dacl,
170 Sacl,
171 }
172
173 use DaclSacl::{Dacl, Sacl};
174
175 #[test]
176 fn mandatory_label() {
177 let access_rights = [
178 ("NR", AccessRights::MandatoryLabelNoReadUp),
179 ("NW", AccessRights::MandatoryLabelNoWriteUp),
180 ("NX", AccessRights::MandatoryLabelNoExecuteUp),
181 ];
182
183 let test_setups = [
184 ("(ML;;", ";;;LW)", winapi::um::winnt::WinLowLabelSid),
185 ("(ML;;", ";;;ME)", winapi::um::winnt::WinMediumLabelSid),
186 ("(ML;;", ";;;HI)", winapi::um::winnt::WinHighLabelSid),
187 ];
188
189 for (sddl1, sddl2, sid_type) in test_setups.iter() {
190 for (mask_sddl, mask_value) in access_rights.iter() {
191 let sd: LocalBox<SecurityDescriptor> = format!("S:{}{}{}", sddl1, mask_sddl, sddl2)
192 .parse()
193 .unwrap();
194
195 let ace = sd.sacl().unwrap().get_ace(0).unwrap();
196
197 assert_eq!(ace.ace_type(), AceType::SYSTEM_MANDATORY_LABEL_ACE_TYPE);
198 assert_eq!(ace.mask(), *mask_value);
199 assert_eq!(
200 ace.sid().unwrap(),
201 &*wrappers::CreateWellKnownSid(*sid_type, None).unwrap()
202 );
203 }
204 }
205 }
206
207 #[test]
208 fn resource_attribute() {
209 let sd: LocalBox<SecurityDescriptor> =
211 r#"S:(RA;;;;;WD;("Secrecy",TU,0,3))"#.parse().unwrap();
212 let ace = sd.sacl().unwrap().get_ace(0).unwrap();
213
214 assert_eq!(ace.mask(), AccessRights::empty());
215 assert_eq!(ace.sid(), None);
216 }
217
218 #[test]
219 fn standard_ace() {
220 use crate::constants::AccessRights;
221 use crate::constants::AceType::*;
222
223 let access_rights = [
224 ("", AccessRights::empty()),
225 ("GA", AccessRights::GenericAll),
226 ("GR", AccessRights::GenericRead),
227 ("GW", AccessRights::GenericWrite),
228 ("GX", AccessRights::GenericExecute),
229 ("RC", AccessRights::ReadControl),
230 ("SD", AccessRights::Delete),
231 ("WD", AccessRights::WriteDac),
232 ("WO", AccessRights::WriteOwner),
233 ("FA", AccessRights::FileAllAccess),
234 ("FR", AccessRights::FileGenericRead),
235 ("FW", AccessRights::FileGenericWrite),
236 ("FX", AccessRights::FileGenericExecute),
237 ("KA", AccessRights::KeyAllAccess),
238 ("KR", AccessRights::KeyRead),
239 ("KW", AccessRights::KeyWrite),
240 ("KX", AccessRights::KeyExecute),
241 (
242 "GRGWRCSDWD",
243 AccessRights::GenericRead
244 | AccessRights::GenericWrite
245 | AccessRights::ReadControl
246 | AccessRights::Delete
247 | AccessRights::WriteDac,
248 ),
249 ];
250
251 let test_cases = [
265 ("(A;;", ";;;", ")", ACCESS_ALLOWED_ACE_TYPE, Dacl),
266 ("(D;;", ";;;", ")", ACCESS_DENIED_ACE_TYPE, Dacl),
267 ("(AU;;", ";;;", ")", SYSTEM_AUDIT_ACE_TYPE, Sacl),
268 (
269 "(XU;;",
270 ";;;",
271 ";(TRUE))",
272 SYSTEM_AUDIT_CALLBACK_ACE_TYPE,
273 Sacl,
274 ),
275 (
276 "(XA;;",
277 ";;;",
278 ";(TRUE))",
279 ACCESS_ALLOWED_CALLBACK_ACE_TYPE,
280 Dacl,
281 ),
282 (
283 "(XD;;",
284 ";;;",
285 ";(TRUE))",
286 ACCESS_DENIED_CALLBACK_ACE_TYPE,
287 Dacl,
288 ),
289 (
290 "(OA;;",
291 ";c434c045-9b91-4504-a2a0-aea9e781ec69;;",
292 ")",
293 ACCESS_ALLOWED_OBJECT_ACE_TYPE,
294 Dacl,
295 ),
296 (
297 "(OD;;",
298 ";c434c045-9b91-4504-a2a0-aea9e781ec69;;",
299 ")",
300 ACCESS_DENIED_OBJECT_ACE_TYPE,
301 Dacl,
302 ),
303 (
304 "(OU;;",
305 ";c434c045-9b91-4504-a2a0-aea9e781ec69;;",
306 ")",
307 SYSTEM_AUDIT_OBJECT_ACE_TYPE,
308 Sacl,
309 ),
310 (
311 "(ZA;;",
312 ";c434c045-9b91-4504-a2a0-aea9e781ec69;;",
313 ";(TRUE))",
314 ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE,
315 Dacl,
316 ),
317 ];
318
319 for (base_sddl_1, base_sddl_2, base_sddl_3, ace_type, which_acl) in test_cases.iter() {
320 for (access_rights_sddl, access_rights_value) in access_rights.iter() {
321 for (sid, _, _) in Sid::test_sids() {
322 let mut sddl_string = String::new();
323 sddl_string.push_str(base_sddl_1);
324 sddl_string.push_str(access_rights_sddl);
325 sddl_string.push_str(base_sddl_2);
326 sddl_string.push_str(&sid.to_string());
327 sddl_string.push_str(base_sddl_3);
328
329 dbg!(&sddl_string);
332
333 let sd: LocalBox<SecurityDescriptor> = match which_acl {
334 Dacl => format!("D:{}", sddl_string),
335 Sacl => format!("S:{}", sddl_string),
336 }
337 .parse()
338 .unwrap();
339
340 let acl = match which_acl {
341 Dacl => sd.dacl(),
342 Sacl => sd.sacl(),
343 }
344 .unwrap();
345
346 assert_eq!(acl.len(), 1);
347
348 let ace = acl.get_ace(0).unwrap();
349
350 assert_eq!(ace.ace_type(), *ace_type);
351 assert_eq!(ace.sid(), Some(&*sid));
352 assert_eq!(ace.mask(), *access_rights_value);
353 }
354 }
355 }
356 }
357
358 #[test]
359 fn get_flags_dacl() {
360 let test_cases = [
361 ("", AceFlags::empty(), Dacl),
362 ("", AceFlags::empty(), Sacl),
363 ("CI", AceFlags::ContainerInherit, Dacl),
364 ("OI", AceFlags::ObjectInherit, Dacl),
365 ("NP", AceFlags::NoPropagateInherit, Dacl),
366 ("IO", AceFlags::InheritOnly, Dacl),
367 ("ID", AceFlags::Inherited, Dacl),
368 ("SA", AceFlags::SuccessfulAccess, Sacl),
369 ("FA", AceFlags::FailedAccess, Sacl),
370 (
371 "CIOINPIOID",
372 AceFlags::ContainerInherit
373 | AceFlags::ObjectInherit
374 | AceFlags::NoPropagateInherit
375 | AceFlags::InheritOnly
376 | AceFlags::Inherited,
377 Dacl,
378 ),
379 (
380 "SAFA",
381 AceFlags::SuccessfulAccess | AceFlags::FailedAccess,
382 Sacl,
383 ),
384 ];
385
386 for (sddl, flag, which_acl) in test_cases.iter() {
387 eprintln!("Testing {} yields {:?}", sddl, flag);
388
389 let sd: LocalBox<SecurityDescriptor> = match which_acl {
390 Dacl => format!("D:(A;{};;;;WD)", sddl),
391 Sacl => format!("S:(AU;{};;;;WD)", sddl),
392 }
393 .parse()
394 .unwrap();
395
396 let acl = match which_acl {
397 Dacl => sd.dacl(),
398 Sacl => sd.sacl(),
399 }
400 .unwrap();
401
402 assert_eq!(acl.get_ace(0).unwrap().flags(), *flag);
403 }
404 }
405}