use std::os::windows::io::{AsRawHandle, BorrowedHandle};
use std::ptr;
use win_error_codes::Win32Error;
use windows_sys::Win32::Foundation::{ERROR_INVALID_DATA, ERROR_INVALID_PARAMETER, ERROR_SUCCESS};
use windows_sys::Win32::Security::Authorization::{
GetSecurityInfo, SE_DS_OBJECT, SE_DS_OBJECT_ALL, SE_FILE_OBJECT, SE_KERNEL_OBJECT, SE_LMSHARE,
SE_OBJECT_TYPE, SE_PRINTER, SE_PROVIDER_DEFINED_OBJECT, SE_REGISTRY_KEY,
SE_REGISTRY_WOW64_32KEY, SE_REGISTRY_WOW64_64KEY, SE_SERVICE, SE_UNKNOWN_OBJECT_TYPE,
SE_WINDOW_OBJECT, SE_WMIGUID_OBJECT,
};
use windows_sys::Win32::Security::PSECURITY_DESCRIPTOR;
use super::sddl::LocalAllocation;
use super::{
SecurityCaptureError, SecurityCaptureFailure, SecurityDescriptor, SecurityInformation,
};
#[cfg(test)]
mod tests;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct ObjectType(SE_OBJECT_TYPE);
impl ObjectType {
pub const UNKNOWN: Self = Self(SE_UNKNOWN_OBJECT_TYPE);
pub const FILE: Self = Self(SE_FILE_OBJECT);
pub const SERVICE: Self = Self(SE_SERVICE);
pub const PRINTER: Self = Self(SE_PRINTER);
pub const REGISTRY_KEY: Self = Self(SE_REGISTRY_KEY);
pub const LMSHARE: Self = Self(SE_LMSHARE);
pub const KERNEL_OBJECT: Self = Self(SE_KERNEL_OBJECT);
pub const WINDOW_OBJECT: Self = Self(SE_WINDOW_OBJECT);
pub const DS_OBJECT: Self = Self(SE_DS_OBJECT);
pub const DS_OBJECT_ALL: Self = Self(SE_DS_OBJECT_ALL);
pub const PROVIDER_DEFINED: Self = Self(SE_PROVIDER_DEFINED_OBJECT);
pub const WMIGUID: Self = Self(SE_WMIGUID_OBJECT);
pub const REGISTRY_WOW64_32KEY: Self = Self(SE_REGISTRY_WOW64_32KEY);
pub const REGISTRY_WOW64_64KEY: Self = Self(SE_REGISTRY_WOW64_64KEY);
#[must_use]
pub const fn from_raw(raw: SE_OBJECT_TYPE) -> Self {
Self(raw)
}
#[must_use]
pub const fn as_raw(self) -> SE_OBJECT_TYPE {
self.0
}
#[must_use]
pub const fn reads_any_handle(self) -> bool {
matches!(
self.0,
SE_FILE_OBJECT | SE_KERNEL_OBJECT | SE_WINDOW_OBJECT | SE_UNKNOWN_OBJECT_TYPE
)
}
}
pub fn get_security_info(
handle: BorrowedHandle<'_>,
object_type: ObjectType,
information: SecurityInformation,
) -> Result<SecurityDescriptor, SecurityCaptureError> {
if !object_type.reads_any_handle() {
return Err(SecurityCaptureError::new(
SecurityCaptureFailure::UnsupportedObjectType,
Win32Error::from_code(ERROR_INVALID_PARAMETER).to_io_error(),
));
}
unsafe { get_security_info_unchecked(handle, object_type, information) }
}
pub unsafe fn get_security_info_unchecked(
handle: BorrowedHandle<'_>,
object_type: ObjectType,
information: SecurityInformation,
) -> Result<SecurityDescriptor, SecurityCaptureError> {
let mut descriptor: PSECURITY_DESCRIPTOR = ptr::null_mut();
let status = unsafe {
GetSecurityInfo(
handle.as_raw_handle(),
object_type.as_raw(),
information.bits(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
&raw mut descriptor,
)
};
let allocation = LocalAllocation(descriptor);
if status != ERROR_SUCCESS {
return Err(SecurityCaptureError::new(
SecurityCaptureFailure::ReadSecurity,
Win32Error::from_code(status).to_io_error(),
));
}
if allocation.0.is_null() {
return Err(SecurityCaptureError::new(
SecurityCaptureFailure::ReadSecurity,
Win32Error::from_code(ERROR_INVALID_DATA).to_io_error(),
));
}
unsafe { SecurityDescriptor::capture(allocation.0) }
}