use core::mem::size_of;
use core::ptr::null_mut;
use vck_common::VckResult;
use wdk_sys::{
ntddk::{
IoCreateSymbolicLink, IoDeleteDevice, IoDeleteSymbolicLink, IoRegisterShutdownNotification,
IoUnregisterShutdownNotification,
},
BOOLEAN, DO_BUFFERED_IO, DO_DEVICE_INITIALIZING, DRIVER_OBJECT, FILE_DEVICE_SECURE_OPEN,
FILE_DEVICE_UNKNOWN, GUID, NTSTATUS, PCUNICODE_STRING, PDEVICE_OBJECT, ULONG, UNICODE_STRING,
};
use crate::nt::{ntstatus_to_result, UnicodeString};
use crate::registry::AttachedVolume;
extern "C" {
#[link_name = "WdmlibIoCreateDeviceSecure"]
fn IoCreateDeviceSecure(
driver_object: *mut DRIVER_OBJECT,
device_extension_size: ULONG,
device_name: *mut UNICODE_STRING,
device_type: ULONG,
device_characteristics: ULONG,
exclusive: BOOLEAN,
default_sddl_string: PCUNICODE_STRING,
device_class_guid: *const GUID,
device_object: *mut PDEVICE_OBJECT,
) -> NTSTATUS;
}
pub const DEVICE_NAME: &str = r"\Device\VolumeCryptKitSample";
pub const SYMLINK_NAME: &str = r"\DosDevices\VolumeCryptKitSample";
pub struct ControlDeviceSecurity<'a> {
pub sddl: &'a str,
pub class_guid: GUID,
}
pub const DEVICE_KIND_CONTROL: u32 = 0;
pub const DEVICE_KIND_FILTER: u32 = 1;
#[repr(C)]
pub struct DeviceExtension {
pub kind: u32,
pub lower_device: PDEVICE_OBJECT,
pub volume: *const AttachedVolume,
pub vthread: *mut crate::filter::volume_thread::VolumeThread,
}
impl DeviceExtension {
pub unsafe fn of<'a>(device: PDEVICE_OBJECT) -> &'a DeviceExtension {
&*((*device).DeviceExtension as *const DeviceExtension)
}
}
pub(crate) const DEVICE_EXTENSION_SIZE: u32 = size_of::<DeviceExtension>() as u32;
pub struct ControlDevice {
device_object: PDEVICE_OBJECT,
}
unsafe impl Send for ControlDevice {}
unsafe impl Sync for ControlDevice {}
impl ControlDevice {
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub fn create(
driver_object: *mut DRIVER_OBJECT,
security: &ControlDeviceSecurity<'_>,
) -> VckResult<Self> {
let device_name = UnicodeString::new(DEVICE_NAME);
let symlink_name = UnicodeString::new(SYMLINK_NAME);
let sddl = UnicodeString::new(security.sddl);
let mut device_object = null_mut();
ntstatus_to_result(
unsafe {
IoCreateDeviceSecure(
driver_object,
DEVICE_EXTENSION_SIZE,
device_name.as_ptr(),
FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN,
BOOLEAN::default(),
sddl.as_ptr() as PCUNICODE_STRING,
&security.class_guid as *const GUID,
&mut device_object,
)
},
"IoCreateDeviceSecure failed",
)?;
unsafe {
(*device_object).Flags |= DO_BUFFERED_IO;
let ext = (*device_object).DeviceExtension as *mut DeviceExtension;
(*ext).kind = DEVICE_KIND_CONTROL;
(*ext).lower_device = null_mut();
(*ext).volume = null_mut();
(*ext).vthread = null_mut();
}
if let Err(err) = ntstatus_to_result(
unsafe { IoCreateSymbolicLink(symlink_name.as_ptr(), device_name.as_ptr()) },
"IoCreateSymbolicLink failed",
) {
unsafe {
IoDeleteDevice(device_object);
}
return Err(err);
}
unsafe {
(*device_object).Flags &= !DO_DEVICE_INITIALIZING;
let _ = IoRegisterShutdownNotification(device_object);
}
Ok(Self { device_object })
}
pub fn device_object(&self) -> PDEVICE_OBJECT {
self.device_object
}
pub fn destroy(self) -> VckResult<()> {
let symlink_name = UnicodeString::new(SYMLINK_NAME);
unsafe {
IoUnregisterShutdownNotification(self.device_object);
}
ntstatus_to_result(
unsafe { IoDeleteSymbolicLink(symlink_name.as_ptr()) },
"IoDeleteSymbolicLink failed",
)?;
unsafe {
IoDeleteDevice(self.device_object);
}
Ok(())
}
}