use std::ops::BitOr;
use std::ptr;
use std::slice;
use win_error_codes::Win32Error;
use windows_sys::Win32::Foundation::{ERROR_INVALID_PARAMETER, FALSE, LocalFree};
use windows_sys::Win32::Security::Authorization::{
ConvertSecurityDescriptorToStringSecurityDescriptorW,
ConvertStringSecurityDescriptorToSecurityDescriptorW, SDDL_REVISION_1,
};
use windows_sys::Win32::Security::{
DACL_SECURITY_INFORMATION, GROUP_SECURITY_INFORMATION, LABEL_SECURITY_INFORMATION,
OBJECT_SECURITY_INFORMATION, OWNER_SECURITY_INFORMATION, PSECURITY_DESCRIPTOR,
SACL_SECURITY_INFORMATION,
};
use wtf_string::Wtf16String;
use super::{SecurityCaptureError, SecurityCaptureFailure, SecurityDescriptor};
#[cfg(test)]
mod tests;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub struct SecurityInformation(OBJECT_SECURITY_INFORMATION);
impl SecurityInformation {
pub const NONE: Self = Self(0);
pub const OWNER: Self = Self(OWNER_SECURITY_INFORMATION);
pub const GROUP: Self = Self(GROUP_SECURITY_INFORMATION);
pub const DACL: Self = Self(DACL_SECURITY_INFORMATION);
pub const SACL: Self = Self(SACL_SECURITY_INFORMATION);
pub const LABEL: Self = Self(LABEL_SECURITY_INFORMATION);
#[must_use]
pub const fn from_bits(bits: OBJECT_SECURITY_INFORMATION) -> Self {
Self(bits)
}
#[must_use]
pub const fn bits(self) -> OBJECT_SECURITY_INFORMATION {
self.0
}
#[must_use]
pub const fn contains(self, other: Self) -> bool {
self.0 & other.0 == other.0
}
}
impl BitOr for SecurityInformation {
type Output = Self;
fn bitor(self, other: Self) -> Self {
Self(self.0 | other.0)
}
}
struct LocalAllocation(*mut core::ffi::c_void);
impl Drop for LocalAllocation {
fn drop(&mut self) {
if !self.0.is_null() {
unsafe { LocalFree(self.0) };
}
}
}
impl SecurityDescriptor {
pub fn from_sddl(sddl: &Wtf16String) -> Result<Self, SecurityCaptureError> {
if sddl.has_interior_nul() {
return Err(SecurityCaptureError::new(
SecurityCaptureFailure::InteriorNul,
Win32Error::from_code(ERROR_INVALID_PARAMETER).to_io_error(),
));
}
let mut raw: PSECURITY_DESCRIPTOR = ptr::null_mut();
let converted = unsafe {
ConvertStringSecurityDescriptorToSecurityDescriptorW(
sddl.as_terminated_ptr(),
SDDL_REVISION_1,
&raw mut raw,
ptr::null_mut(),
)
};
if converted == FALSE {
return Err(SecurityCaptureError::last_os(
SecurityCaptureFailure::InvalidSddl,
));
}
let allocation = LocalAllocation(raw);
let captured = unsafe { Self::capture(allocation.0) };
drop(allocation);
captured
}
pub fn to_sddl(
&self,
information: SecurityInformation,
) -> Result<Wtf16String, SecurityCaptureError> {
let mut text: *mut u16 = ptr::null_mut();
let converted = unsafe {
ConvertSecurityDescriptorToStringSecurityDescriptorW(
self.as_ptr().cast_mut(),
SDDL_REVISION_1,
information.bits(),
&raw mut text,
ptr::null_mut(),
)
};
if converted == FALSE {
return Err(SecurityCaptureError::last_os(
SecurityCaptureFailure::ToSddl,
));
}
let allocation = LocalAllocation(text.cast());
let mut count = 0_usize;
while unsafe { *text.add(count) } != 0 {
count += 1;
}
let units = unsafe { slice::from_raw_parts(text, count) };
let result = Wtf16String::from_units(units);
drop(allocation);
Ok(result)
}
}