use std::ffi::c_void;
use std::ptr;
use windows_sys::Win32::Foundation::{FALSE, GENERIC_ALL, TRUE};
use windows_sys::Win32::Security::{
ACL, ACL_REVISION, AddAccessAllowedAce, CreateWellKnownSid, InitializeAcl,
InitializeSecurityDescriptor, MakeSelfRelativeSD, SECURITY_ATTRIBUTES, SECURITY_DESCRIPTOR,
SECURITY_MAX_SID_SIZE, SetSecurityDescriptorDacl, SetSecurityDescriptorGroup,
SetSecurityDescriptorOwner, WinWorldSid,
};
use super::{
AclState, SELF_RELATIVE_ALIGNMENT, SecurityAttributes, SecurityCaptureFailure,
SecurityDescriptor,
};
use crate::buffer::AlignedBuffer;
const SECURITY_DESCRIPTOR_REVISION: u32 = 1;
const ACL_ALIGNMENT: usize = align_of::<u32>();
const EMPTY_ACL_BYTES: u32 = 8;
const ONE_ACE_ACL_BYTES: u32 = 256;
pub(crate) struct Absolute {
descriptor: Box<SECURITY_DESCRIPTOR>,
_sid: AlignedBuffer,
_acl: Option<AlignedBuffer>,
}
impl Absolute {
fn without_dacl() -> Self {
let mut sid = world_sid();
let mut descriptor = new_descriptor();
set_owner_and_group(&mut descriptor, &mut sid);
Self {
descriptor,
_sid: sid,
_acl: None,
}
}
fn with_null_dacl() -> Self {
let mut absolute = Self::without_dacl();
let set = unsafe {
SetSecurityDescriptorDacl(
descriptor_ptr(&mut absolute.descriptor),
TRUE,
ptr::null_mut(),
FALSE,
)
};
assert_ne!(set, FALSE, "set a NULL DACL");
absolute
}
fn with_empty_dacl() -> Self {
let mut absolute = Self::without_dacl();
let mut acl = new_acl(EMPTY_ACL_BYTES);
let set = unsafe {
SetSecurityDescriptorDacl(
descriptor_ptr(&mut absolute.descriptor),
TRUE,
acl.as_mut_ptr().cast::<ACL>(),
FALSE,
)
};
assert_ne!(set, FALSE, "set an empty DACL");
absolute._acl = Some(acl);
absolute
}
pub(crate) fn with_populated_dacl() -> Self {
let mut absolute = Self::without_dacl();
let mut acl = new_acl(ONE_ACE_ACL_BYTES);
let mut sid = world_sid();
let added = unsafe {
AddAccessAllowedAce(
acl.as_mut_ptr().cast::<ACL>(),
ACL_REVISION,
GENERIC_ALL,
sid.as_mut_ptr().cast::<c_void>(),
)
};
assert_ne!(added, FALSE, "add an access-allowed ACE");
let set = unsafe {
SetSecurityDescriptorDacl(
descriptor_ptr(&mut absolute.descriptor),
TRUE,
acl.as_mut_ptr().cast::<ACL>(),
FALSE,
)
};
assert_ne!(set, FALSE, "set a populated DACL");
absolute._acl = Some(acl);
absolute
}
pub(crate) fn as_ptr(&self) -> *const c_void {
ptr::from_ref(self.descriptor.as_ref()).cast::<c_void>()
}
fn to_self_relative(&self) -> AlignedBuffer {
let mut length: u32 = 0;
let sized = unsafe {
MakeSelfRelativeSD(self.as_ptr().cast_mut(), ptr::null_mut(), &raw mut length)
};
assert_eq!(sized, FALSE, "the sizing call is expected to fail");
let mut blob = AlignedBuffer::zeroed(length as usize, SELF_RELATIVE_ALIGNMENT);
let converted = unsafe {
MakeSelfRelativeSD(
self.as_ptr().cast_mut(),
blob.as_mut_ptr().cast::<c_void>(),
&raw mut length,
)
};
assert_ne!(converted, FALSE, "convert to self-relative form");
blob
}
}
fn descriptor_ptr(descriptor: &mut SECURITY_DESCRIPTOR) -> *mut c_void {
ptr::from_mut(descriptor).cast::<c_void>()
}
fn new_descriptor() -> Box<SECURITY_DESCRIPTOR> {
let mut descriptor = Box::new(unsafe { std::mem::zeroed::<SECURITY_DESCRIPTOR>() });
let initialised = unsafe {
InitializeSecurityDescriptor(
descriptor_ptr(&mut descriptor),
SECURITY_DESCRIPTOR_REVISION,
)
};
assert_ne!(initialised, FALSE, "initialise an absolute descriptor");
descriptor
}
fn set_owner_and_group(descriptor: &mut SECURITY_DESCRIPTOR, sid: &mut AlignedBuffer) {
let owner = unsafe {
SetSecurityDescriptorOwner(
descriptor_ptr(descriptor),
sid.as_mut_ptr().cast::<c_void>(),
FALSE,
)
};
assert_ne!(owner, FALSE, "set the owner");
let group = unsafe {
SetSecurityDescriptorGroup(
descriptor_ptr(descriptor),
sid.as_mut_ptr().cast::<c_void>(),
FALSE,
)
};
assert_ne!(group, FALSE, "set the group");
}
fn new_acl(bytes: u32) -> AlignedBuffer {
let mut acl = AlignedBuffer::zeroed(bytes as usize, ACL_ALIGNMENT);
let initialised = unsafe { InitializeAcl(acl.as_mut_ptr().cast::<ACL>(), bytes, ACL_REVISION) };
assert_ne!(initialised, FALSE, "initialise an ACL");
acl
}
fn world_sid() -> AlignedBuffer {
let mut sid = AlignedBuffer::zeroed(SECURITY_MAX_SID_SIZE as usize, 8);
let mut length = SECURITY_MAX_SID_SIZE;
let created = unsafe {
CreateWellKnownSid(
WinWorldSid,
ptr::null_mut(),
sid.as_mut_ptr().cast::<c_void>(),
&raw mut length,
)
};
assert_ne!(created, FALSE, "create the World SID");
sid
}
fn capture(absolute: &Absolute) -> SecurityDescriptor {
unsafe { SecurityDescriptor::capture(absolute.as_ptr()) }.expect("capture the descriptor")
}
#[test]
fn an_absolute_descriptor_without_a_dacl_captures_as_absent() {
let absolute = Absolute::without_dacl();
let captured = capture(&absolute);
assert_eq!(captured.dacl().expect("read the DACL"), AclState::Absent);
}
#[test]
fn an_absolute_descriptor_with_a_null_dacl_captures_as_null() {
let absolute = Absolute::with_null_dacl();
let captured = capture(&absolute);
assert_eq!(captured.dacl().expect("read the DACL"), AclState::Null);
}
#[test]
fn an_absolute_descriptor_with_an_empty_dacl_captures_as_empty() {
let absolute = Absolute::with_empty_dacl();
let captured = capture(&absolute);
assert_eq!(captured.dacl().expect("read the DACL"), AclState::Empty);
}
#[test]
fn the_three_dacl_outcomes_stay_distinct() {
let absent = capture(&Absolute::without_dacl())
.dacl()
.expect("read the DACL");
let null = capture(&Absolute::with_null_dacl())
.dacl()
.expect("read the DACL");
let empty = capture(&Absolute::with_empty_dacl())
.dacl()
.expect("read the DACL");
assert_ne!(absent, null);
assert_ne!(absent, empty);
assert_ne!(
null, empty,
"a NULL DACL allows all; an empty DACL allows none"
);
}
#[test]
fn an_absolute_descriptor_with_a_populated_dacl_reports_its_entry_count() {
let absolute = Absolute::with_populated_dacl();
let captured = capture(&absolute);
assert_eq!(
captured.dacl().expect("read the DACL"),
AclState::Populated(1)
);
}
#[test]
fn a_descriptor_without_a_sacl_captures_as_absent() {
let absolute = Absolute::with_populated_dacl();
let captured = capture(&absolute);
assert_eq!(captured.sacl().expect("read the SACL"), AclState::Absent);
}
#[test]
fn a_captured_descriptor_is_dword_aligned() {
let captured = capture(&Absolute::with_populated_dacl());
assert_eq!(
captured.as_ptr() as usize % SELF_RELATIVE_ALIGNMENT,
0,
"a self-relative descriptor must be DWORD-aligned, which a boxed byte \
slice would not guarantee"
);
assert!(!captured.is_empty());
assert_eq!(captured.len(), captured.as_bytes().len());
}
#[test]
fn a_self_relative_descriptor_is_captured_byte_for_byte() {
let absolute = Absolute::with_populated_dacl();
let self_relative = absolute.to_self_relative();
let captured = unsafe { SecurityDescriptor::capture(self_relative.as_ptr().cast::<c_void>()) }
.expect("capture a self-relative descriptor");
assert_eq!(captured.as_bytes(), self_relative.as_slice());
assert_eq!(
captured.dacl().expect("read the DACL"),
AclState::Populated(1)
);
}
#[test]
fn the_capture_survives_the_caller_dropping_everything_it_was_built_from() {
let captured = {
let absolute = Absolute::with_populated_dacl();
capture(&absolute)
};
assert_eq!(
captured.dacl().expect("read the DACL"),
AclState::Populated(1)
);
assert_eq!(captured.sacl().expect("read the SACL"), AclState::Absent);
}
#[test]
fn a_malformed_descriptor_is_refused_at_capture() {
let zeroed = AlignedBuffer::zeroed(size_of::<SECURITY_DESCRIPTOR>(), SELF_RELATIVE_ALIGNMENT);
let error = unsafe { SecurityDescriptor::capture(zeroed.as_ptr().cast::<c_void>()) }
.expect_err("a zeroed descriptor has revision 0 and cannot be valid");
assert_eq!(error.failure(), SecurityCaptureFailure::InvalidDescriptor);
assert!(
error.to_string().contains("IsValidSecurityDescriptor"),
"unexpected message: {error}"
);
}
#[test]
fn a_clone_equals_its_original_and_is_independent() {
let captured = capture(&Absolute::with_populated_dacl());
let clone = captured.clone();
assert_eq!(clone, captured);
assert_ne!(clone.as_ptr(), captured.as_ptr());
drop(captured);
assert_eq!(clone.dacl().expect("read the DACL"), AclState::Populated(1));
}
#[test]
fn descriptors_differing_in_their_dacl_are_not_equal() {
let null = capture(&Absolute::with_null_dacl());
let empty = capture(&Absolute::with_empty_dacl());
assert_ne!(null, empty);
}
#[test]
fn null_attributes_are_the_caller_declining_rather_than_an_error() {
let captured = unsafe { SecurityAttributes::capture(ptr::null()) }
.expect("a null lpSecurityAttributes is not a failure");
assert!(
captured.is_none(),
"no attributes at all differs from attributes carrying no descriptor"
);
}
#[test]
fn attributes_with_no_descriptor_keep_the_inheritance_choice() {
let raw = SECURITY_ATTRIBUTES {
nLength: size_of::<SECURITY_ATTRIBUTES>() as u32,
lpSecurityDescriptor: ptr::null_mut(),
bInheritHandle: TRUE,
};
let captured = unsafe { SecurityAttributes::capture(&raw) }
.expect("capture attributes")
.expect("the attributes were supplied");
assert!(captured.descriptor().is_none());
assert!(captured.inherit_handle());
}
#[test]
fn attributes_with_a_descriptor_capture_both_parts() {
let absolute = Absolute::with_populated_dacl();
let raw = SECURITY_ATTRIBUTES {
nLength: size_of::<SECURITY_ATTRIBUTES>() as u32,
lpSecurityDescriptor: absolute.as_ptr().cast_mut(),
bInheritHandle: FALSE,
};
let captured = unsafe { SecurityAttributes::capture(&raw) }
.expect("capture attributes")
.expect("the attributes were supplied");
assert!(!captured.inherit_handle());
assert_eq!(
captured
.descriptor()
.expect("a descriptor was supplied")
.dacl()
.expect("read the DACL"),
AclState::Populated(1)
);
}
#[test]
fn to_raw_rebuilds_the_win32_struct_from_the_capture() {
let absolute = Absolute::with_populated_dacl();
let captured = SecurityAttributes::new(Some(capture(&absolute)), true);
let raw = captured.to_raw();
assert_eq!(raw.nLength as usize, size_of::<SECURITY_ATTRIBUTES>());
assert_eq!(raw.bInheritHandle, TRUE);
assert_eq!(
raw.lpSecurityDescriptor.cast_const(),
captured
.descriptor()
.expect("a descriptor was supplied")
.as_ptr()
);
}
#[test]
fn to_raw_reports_a_null_descriptor_when_none_was_captured() {
let captured = SecurityAttributes::new(None, false);
let raw = captured.to_raw();
assert!(raw.lpSecurityDescriptor.is_null());
assert_eq!(raw.bInheritHandle, FALSE);
}
#[test]
fn a_capture_moves_and_shares_across_threads() {
const fn assert_send<T: Send>() {}
const fn assert_sync<T: Sync>() {}
assert_send::<SecurityDescriptor>();
assert_sync::<SecurityDescriptor>();
assert_send::<SecurityAttributes>();
assert_sync::<SecurityAttributes>();
let captured = SecurityAttributes::new(Some(capture(&Absolute::with_populated_dacl())), true);
let observed = std::thread::spawn(move || {
captured
.descriptor()
.expect("a descriptor was supplied")
.dacl()
.expect("read the DACL")
})
.join()
.expect("the worker did not panic");
assert_eq!(observed, AclState::Populated(1));
}