use {
super::LocalBox,
crate::{BoolExt, OrErrno, SubUsizeExt},
std::{ffi::c_void, io, ptr},
widestring::U16CStr,
windows_sys::Win32::{
Foundation::{LocalFree, BOOL, PSID},
Security::{
Authorization::{
ConvertSecurityDescriptorToStringSecurityDescriptorW,
ConvertStringSecurityDescriptorToSecurityDescriptorW, SDDL_REVISION_1,
},
FreeSid, GetSecurityDescriptorControl, SetSecurityDescriptorControl, ACL,
SECURITY_DESCRIPTOR_CONTROL,
},
},
};
pub(super) unsafe fn control_and_revision(
sd: *const c_void,
) -> io::Result<(SECURITY_DESCRIPTOR_CONTROL, u32)> {
let mut control = SECURITY_DESCRIPTOR_CONTROL::default();
let mut revision = 0;
unsafe { GetSecurityDescriptorControl(sd.cast_mut(), &mut control, &mut revision) }
.true_val_or_errno((control, revision))
}
pub(super) unsafe fn acl(
sd: *const c_void,
f: unsafe extern "system" fn(*mut c_void, *mut BOOL, *mut *mut ACL, *mut BOOL) -> BOOL,
) -> io::Result<Option<(*const ACL, bool)>> {
let mut exists = 0;
let mut pacl = ptr::null_mut();
let mut defaulted = 0;
unsafe { f(sd.cast_mut(), &mut exists, &mut pacl, &mut defaulted) }.true_or_errno(|| {
if exists != 0 {
Some((pacl.cast_const(), defaulted != 0))
} else {
None
}
})
}
pub(super) unsafe fn sid(
sd: *const c_void,
f: unsafe extern "system" fn(*mut c_void, *mut PSID, *mut BOOL) -> BOOL,
) -> io::Result<(*const c_void, bool)> {
let mut psid = ptr::null_mut();
let mut defaulted = 1;
unsafe { f(sd.cast_mut(), &mut psid, &mut defaulted) }
.true_or_errno(|| (psid.cast_const(), defaulted != 0))
}
pub(super) unsafe fn set_acl(
sd: *const c_void,
acl: Option<*mut ACL>,
defaulted: bool,
f: unsafe extern "system" fn(*mut c_void, BOOL, *const ACL, BOOL) -> BOOL,
) -> io::Result<()> {
let has_acl = acl.is_some().to_i32();
let acl = acl.unwrap_or(ptr::null_mut());
unsafe { f(sd.cast_mut(), has_acl, acl, defaulted.to_i32()) }.true_val_or_errno(())
}
pub(super) unsafe fn set_sid(
sd: *const c_void,
sid: *mut c_void,
defaulted: bool,
f: unsafe extern "system" fn(*mut c_void, PSID, BOOL) -> BOOL,
) -> io::Result<()> {
unsafe { f(sd.cast_mut(), sid, defaulted.to_i32()) }.true_val_or_errno(())
}
pub(super) unsafe fn set_control(
sd: *const c_void,
mask: SECURITY_DESCRIPTOR_CONTROL,
value: SECURITY_DESCRIPTOR_CONTROL,
) -> io::Result<()> {
unsafe { SetSecurityDescriptorControl(sd.cast_mut(), mask, value) }.true_val_or_errno(())
}
pub(super) unsafe fn unset_acl(
sd: *const c_void,
f: unsafe extern "system" fn(*mut c_void, BOOL, *const ACL, BOOL) -> BOOL,
) -> io::Result<()> {
unsafe { set_acl(sd, None, false, f) }
}
pub(super) unsafe fn unset_sid(
sd: *const c_void,
f: unsafe extern "system" fn(*mut c_void, PSID, BOOL) -> BOOL,
) -> io::Result<()> {
unsafe { set_sid(sd, ptr::null_mut(), false, f) }
}
pub(super) unsafe fn free_acl(acl: *mut ACL) -> io::Result<()> {
unsafe { LocalFree(acl.cast()) }.is_null().true_val_or_errno(())
}
pub(super) unsafe fn free_sid(sid: *mut c_void) -> io::Result<()> {
if sid.is_null() {
return Ok(());
}
if unsafe { FreeSid(sid) }.is_null() {
Ok(())
} else {
Err(io::Error::other("failed to deallocate SID"))
}
}
pub(super) unsafe fn serialize(
sd: *const c_void,
selector: u32,
) -> io::Result<(LocalBox<u16>, usize)> {
let mut localboxed_string = ptr::null_mut();
let mut buflen = 0;
unsafe {
ConvertSecurityDescriptorToStringSecurityDescriptorW(
sd.cast_mut(),
SDDL_REVISION_1,
selector,
&mut localboxed_string,
&mut buflen,
)
}
.true_val_or_errno(())?;
Ok((unsafe { LocalBox::from_raw(localboxed_string.cast()) }, buflen.to_usize()))
}
pub(super) fn deserialize(sdsf: &U16CStr) -> io::Result<LocalBox<c_void>> {
let mut srsd = ptr::null_mut();
let mut buflen = 0;
unsafe {
ConvertStringSecurityDescriptorToSecurityDescriptorW(
sdsf.as_ptr(),
SDDL_REVISION_1,
&mut srsd,
&mut buflen,
)
}
.true_val_or_errno(())?;
Ok(unsafe { LocalBox::from_raw(srsd) })
}