use crate::internals::win32 as internals;
mod win {
pub(super) use windows::Win32::Security::Authorization::SE_KERNEL_OBJECT;
pub use windows::Win32::System::Threading::PROCESS_ACCESS_RIGHTS;
pub(super) use windows::Win32::Security::TOKEN_QUERY;
}
pub use internals::SidRef;
pub use win::PROCESS_ACCESS_RIGHTS as ProcessAccessRights;
pub struct Acl(internals::AclBox);
impl Acl {
pub fn set_process_dacl_protected(&self) -> anyhow::Result<()> {
unsafe {
self.0
.set_protected(internals::get_process_handle(), win::SE_KERNEL_OBJECT)
}
}
}
pub struct TokenUser(internals::TokenUserBox);
impl TokenUser {
#[must_use]
pub fn sid<'a>(&'a self) -> SidRef<'a> {
self.0.sid()
}
pub fn process_user() -> anyhow::Result<Self> {
let process_tok = unsafe {
internals::AccessToken::open_process_token(
internals::get_process_handle(),
win::TOKEN_QUERY,
)
}?;
let user = process_tok.get_token_user()?;
Ok(Self(user))
}
}
mod acl_construction {
use super::*;
pub struct AclPartial(internals::AclBox);
impl AclPartial {
fn declare_final(self) -> Acl {
Acl(self.0)
}
}
pub trait AclConstruction {
fn realize_with_size<F: FnOnce(&mut internals::AclSize)>(
self,
f: F,
) -> anyhow::Result<AclPartial>;
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
pub struct EmptyAcl;
impl EmptyAcl {
#[must_use]
pub fn new() -> Self {
EmptyAcl
}
pub fn create(self) -> anyhow::Result<Acl> {
let acl = self.realize_with_size(|_s| {})?;
Ok(acl.declare_final())
}
}
impl AclConstruction for EmptyAcl {
fn realize_with_size<F: FnOnce(&mut internals::AclSize)>(
self,
f: F,
) -> anyhow::Result<AclPartial> {
let mut size = internals::AclSize::new();
f(&mut size);
let acl = size.allocate()?;
Ok(AclPartial(acl))
}
}
pub struct AddAllowAceAcl<'a, C: AclConstruction> {
constructor: C,
access_mask: ProcessAccessRights,
sid: SidRef<'a>,
}
impl<'a, C: AclConstruction> AddAllowAceAcl<'a, C> {
pub fn new(constructor: C, access_mask: ProcessAccessRights, sid: SidRef<'a>) -> Self {
AddAllowAceAcl {
constructor,
access_mask,
sid,
}
}
pub fn create(self) -> anyhow::Result<Acl> {
let acl = self.realize_with_size(|_s| {})?;
Ok(acl.declare_final())
}
}
impl<'a, C: AclConstruction> AclConstruction for AddAllowAceAcl<'a, C> {
fn realize_with_size<F: FnOnce(&mut internals::AclSize)>(
self,
f: F,
) -> anyhow::Result<AclPartial> {
let mut acl = self.constructor.realize_with_size(|size| {
size.add_allowed_ace(self.sid.len());
f(size);
})?;
unsafe { acl.0.add_allowed_ace(self.access_mask, self.sid) }?;
Ok(acl)
}
}
pub struct AddDenyAceAcl<'a, C: AclConstruction> {
constructor: C,
access_mask: ProcessAccessRights,
sid: SidRef<'a>,
}
impl<'a, C: AclConstruction> AddDenyAceAcl<'a, C> {
pub fn new(constructor: C, access_mask: ProcessAccessRights, sid: SidRef<'a>) -> Self {
AddDenyAceAcl {
constructor,
access_mask,
sid,
}
}
pub fn create(self) -> anyhow::Result<Acl> {
let acl = self.realize_with_size(|_s| {})?;
Ok(acl.declare_final())
}
}
impl<'a, C: AclConstruction> AclConstruction for AddDenyAceAcl<'a, C> {
fn realize_with_size<F: FnOnce(&mut internals::AclSize)>(
self,
f: F,
) -> anyhow::Result<AclPartial> {
let mut acl = self.constructor.realize_with_size(|size| {
size.add_denied_ace(self.sid.len());
f(size);
})?;
unsafe { acl.0.add_denied_ace(self.access_mask, self.sid) }?;
Ok(acl)
}
}
}
pub use acl_construction::{AddAllowAceAcl, AddDenyAceAcl, EmptyAcl};
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn create_empty_acl() {
let acl_constructor = EmptyAcl::new();
let acl = acl_constructor.create().expect("could not create ACL");
}
#[test]
fn create_allow_ace_acl() {
use windows::Win32::System::Threading::PROCESS_TERMINATE;
let user = TokenUser::process_user().expect("could not get process token user");
let sid = user.sid();
let acl_constructor = EmptyAcl::new();
let acl_constructor = AddAllowAceAcl::new(acl_constructor, PROCESS_TERMINATE, sid);
let acl = acl_constructor.create().expect("could not create ACL");
}
#[test]
fn create_deny_ace_acl() {
use windows::Win32::System::Threading::PROCESS_CREATE_PROCESS;
let user = TokenUser::process_user().expect("could not get process token user");
let sid = user.sid();
let acl_constructor = EmptyAcl::new();
let acl_constructor = AddDenyAceAcl::new(acl_constructor, PROCESS_CREATE_PROCESS, sid);
let acl = acl_constructor.create().expect("could not create ACL");
}
}