use std::borrow::Borrow;
use std::fmt::{self, Debug, Formatter};
use std::io;
use tracing::debug;
use crate::ntapi;
use crate::security::{BoxedSecurityDescriptor, SecurityDescriptor};
use crate::state::{BorrowedState, OwnedState, RawState};
use crate::state_name::{DataScope, StateLifetime, StateName};
use crate::type_id::{TypeId, GUID};
pub const MAXIMUM_STATE_SIZE: usize = 0x1000;
#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct UnspecifiedLifetime {
_private: (),
}
impl UnspecifiedLifetime {
const fn new() -> Self {
Self { _private: () }
}
}
impl Debug for UnspecifiedLifetime {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("UnspecifiedLifetime").finish()
}
}
#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct UnspecifiedScope {
_private: (),
}
impl UnspecifiedScope {
const fn new() -> Self {
Self { _private: () }
}
}
impl Debug for UnspecifiedScope {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("UnspecifiedScope").finish()
}
}
#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct UnspecifiedSecurityDescriptor {
_private: (),
}
impl UnspecifiedSecurityDescriptor {
const fn new() -> Self {
Self { _private: () }
}
}
impl Debug for UnspecifiedSecurityDescriptor {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("UnspecifiedSecurityDescriptor").finish()
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum CreatableStateLifetime {
Permanent {
persist_data: bool,
},
Persistent,
Temporary,
}
impl CreatableStateLifetime {
const fn persist_data(self) -> bool {
matches!(self, Self::Permanent { persist_data: true })
}
}
impl From<CreatableStateLifetime> for StateLifetime {
fn from(lifetime: CreatableStateLifetime) -> Self {
match lifetime {
CreatableStateLifetime::Permanent { .. } => StateLifetime::Permanent,
CreatableStateLifetime::Persistent => StateLifetime::Persistent,
CreatableStateLifetime::Temporary => StateLifetime::Temporary,
}
}
}
pub trait TryIntoSecurityDescriptor: private::Sealed {
type IntoSecurityDescriptor: Borrow<SecurityDescriptor>;
fn try_into_security_descriptor(self) -> io::Result<Self::IntoSecurityDescriptor>;
}
impl<SD> TryIntoSecurityDescriptor for SD
where
SD: Borrow<SecurityDescriptor>,
{
type IntoSecurityDescriptor = Self;
fn try_into_security_descriptor(self) -> io::Result<Self> {
Ok(self)
}
}
impl TryIntoSecurityDescriptor for UnspecifiedSecurityDescriptor {
type IntoSecurityDescriptor = BoxedSecurityDescriptor;
fn try_into_security_descriptor(self) -> io::Result<BoxedSecurityDescriptor> {
BoxedSecurityDescriptor::create_everyone_generic_all()
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct StateCreation<L, S, SD> {
lifetime: L,
scope: S,
maximum_state_size: Option<usize>,
security_descriptor: SD,
type_id: TypeId,
}
impl Default for StateCreation<UnspecifiedLifetime, UnspecifiedScope, UnspecifiedSecurityDescriptor> {
fn default() -> Self {
Self::new()
}
}
impl StateCreation<UnspecifiedLifetime, UnspecifiedScope, UnspecifiedSecurityDescriptor> {
pub const fn new() -> Self {
Self {
lifetime: UnspecifiedLifetime::new(),
scope: UnspecifiedScope::new(),
maximum_state_size: None,
security_descriptor: UnspecifiedSecurityDescriptor::new(),
type_id: TypeId::none(),
}
}
}
impl<L, S, SD> StateCreation<L, S, SD> {
#[must_use]
pub fn lifetime(self, lifetime: CreatableStateLifetime) -> StateCreation<CreatableStateLifetime, S, SD> {
StateCreation {
lifetime,
scope: self.scope,
security_descriptor: self.security_descriptor,
maximum_state_size: self.maximum_state_size,
type_id: self.type_id,
}
}
#[must_use]
pub fn scope(self, scope: DataScope) -> StateCreation<L, DataScope, SD> {
StateCreation {
scope,
lifetime: self.lifetime,
maximum_state_size: self.maximum_state_size,
security_descriptor: self.security_descriptor,
type_id: self.type_id,
}
}
#[must_use]
pub fn maximum_state_size(self, maximum_state_size: usize) -> StateCreation<L, S, SD> {
StateCreation {
maximum_state_size: Some(maximum_state_size),
..self
}
}
#[must_use]
pub fn security_descriptor<NewSD>(self, security_descriptor: NewSD) -> StateCreation<L, S, NewSD>
where
NewSD: Borrow<SecurityDescriptor>,
{
StateCreation {
security_descriptor,
lifetime: self.lifetime,
maximum_state_size: self.maximum_state_size,
scope: self.scope,
type_id: self.type_id,
}
}
#[must_use]
pub fn type_id(self, type_id: impl Into<GUID>) -> StateCreation<L, S, SD> {
StateCreation {
type_id: type_id.into().into(),
..self
}
}
}
impl<SD> StateCreation<CreatableStateLifetime, DataScope, SD>
where
SD: TryIntoSecurityDescriptor,
{
pub fn create_owned<T>(self) -> io::Result<OwnedState<T>>
where
T: ?Sized,
{
self.create_raw().map(OwnedState::from_raw)
}
pub fn create_static<T>(self) -> io::Result<BorrowedState<'static, T>>
where
T: ?Sized,
{
self.create_raw().map(BorrowedState::from_raw)
}
fn create_raw<T>(self) -> io::Result<RawState<T>>
where
T: ?Sized,
{
RawState::create(
self.lifetime.into(),
self.scope,
self.lifetime.persist_data(),
self.type_id,
self.maximum_state_size.unwrap_or(MAXIMUM_STATE_SIZE),
self.security_descriptor.try_into_security_descriptor()?,
)
}
}
impl<T> OwnedState<T>
where
T: ?Sized,
{
pub fn create_temporary() -> io::Result<Self> {
StateCreation::new()
.lifetime(CreatableStateLifetime::Temporary)
.scope(DataScope::Machine)
.create_owned()
}
pub fn delete(self) -> io::Result<()> {
self.into_raw().delete()
}
}
impl<T> BorrowedState<'static, T>
where
T: ?Sized,
{
pub fn create_temporary() -> io::Result<Self> {
StateCreation::new()
.lifetime(CreatableStateLifetime::Temporary)
.scope(DataScope::Machine)
.create_static()
}
}
impl<T> BorrowedState<'_, T>
where
T: ?Sized,
{
pub fn delete(self) -> io::Result<()> {
self.raw.delete()
}
}
impl<T> RawState<T>
where
T: ?Sized,
{
fn create(
name_lifetime: StateLifetime,
data_scope: DataScope,
persist_data: bool,
type_id: TypeId,
maximum_state_size: usize,
security_descriptor: impl Borrow<SecurityDescriptor>,
) -> io::Result<Self> {
let mut opaque_value = 0;
let name_lifetime = name_lifetime as u32;
let data_scope = data_scope as u32;
let persist_data: u8 = persist_data.into();
let maximum_state_size = maximum_state_size as u32;
let result = unsafe {
ntapi::NtCreateWnfStateName(
&mut opaque_value,
name_lifetime,
data_scope,
persist_data,
type_id.as_ptr(),
maximum_state_size,
security_descriptor.borrow().as_ptr(),
)
};
if result.is_ok() {
let state_name = StateName::from_opaque_value(opaque_value);
debug!(
target: ntapi::TRACING_TARGET,
?result,
input.name_lifetime = name_lifetime,
input.data_scope = data_scope,
input.persist_data = persist_data,
input.type_id = %type_id,
input.maximum_state_size = maximum_state_size,
output.state_name = %state_name,
"NtCreateWnfStateName",
);
Ok(Self::from_state_name_and_type_id(state_name, type_id))
} else {
debug!(
target: ntapi::TRACING_TARGET,
?result,
input.name_lifetime = name_lifetime,
input.data_scope = data_scope,
input.persist_data = persist_data,
input.type_id = %type_id,
input.maximum_state_size = maximum_state_size,
"NtCreateWnfStateName",
);
Err(io::Error::from_raw_os_error(result.0))
}
}
pub(crate) fn delete(self) -> io::Result<()> {
let result = unsafe { ntapi::NtDeleteWnfStateName(&self.state_name.opaque_value()) };
debug!(
target: ntapi::TRACING_TARGET,
?result,
input.state_name = %self.state_name,
"NtDeleteWnfStateName",
);
result.ok()?;
Ok(())
}
}
mod private {
use super::*;
pub trait Sealed {}
impl<SD> Sealed for SD where SD: Borrow<SecurityDescriptor> {}
impl Sealed for UnspecifiedSecurityDescriptor {}
}