fort/src/driver/fortdev.c

277 lines
8.1 KiB
C
Raw Normal View History

/* Fort Firewall Driver Device */
#include "../version/fort_version.h"
#include "fortdev.h"
#include "common/fortdef.h"
#include "fortcout.h"
static PFORT_DEVICE g_device = NULL;
FORT_API PFORT_DEVICE fort_device()
{
return g_device;
}
FORT_API void fort_device_set(PFORT_DEVICE device)
{
g_device = device;
}
static void fort_worker_reauth(void)
{
const FORT_CONF_FLAGS conf_flags = g_device->conf.conf_flags;
NTSTATUS status;
status = fort_callout_force_reauth(conf_flags, 0);
if (!NT_SUCCESS(status)) {
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, "FORT: Worker Reauth: Error: %x\n",
status);
}
}
FORT_API void fort_app_period_timer(void)
{
if (fort_conf_ref_period_update(&g_device->conf, FALSE, NULL)) {
fort_worker_queue(&g_device->worker, FORT_WORKER_REAUTH, &fort_worker_reauth);
}
}
FORT_API NTSTATUS fort_device_create(PDEVICE_OBJECT device, PIRP irp)
{
NTSTATUS status = STATUS_SUCCESS;
UNUSED(device);
/* Device opened */
if (fort_device_flag_set(&g_device->conf, FORT_DEVICE_IS_OPENED, TRUE)
& FORT_DEVICE_IS_OPENED) {
status = STATUS_SHARING_VIOLATION; /* Only one client may connect */
}
if (NT_SUCCESS(status)) {
/* Clear buffer */
fort_buffer_clear(&g_device->buffer);
}
fort_request_complete(irp, status);
return status;
}
FORT_API NTSTATUS fort_device_close(PDEVICE_OBJECT device, PIRP irp)
{
UNUSED(device);
fort_request_complete(irp, STATUS_SUCCESS);
return STATUS_SUCCESS;
}
FORT_API NTSTATUS fort_device_cleanup(PDEVICE_OBJECT device, PIRP irp)
{
UNUSED(device);
/* Device closed */
fort_device_flag_set(
&g_device->conf, (FORT_DEVICE_IS_OPENED | FORT_DEVICE_IS_VALIDATED), FALSE);
/* Clear conf */
{
const FORT_CONF_FLAGS old_conf_flags = fort_conf_ref_set(&g_device->conf, NULL);
fort_conf_zones_set(&g_device->conf, NULL);
fort_callout_force_reauth(old_conf_flags, FORT_DEFER_FLUSH_ALL);
}
/* Clear buffer */
fort_buffer_clear(&g_device->buffer);
fort_request_complete(irp, STATUS_SUCCESS);
return STATUS_SUCCESS;
}
static void fort_device_cancel_pending(PDEVICE_OBJECT device, PIRP irp)
{
ULONG_PTR info;
NTSTATUS status;
UNUSED(device);
status = fort_buffer_cancel_pending(&g_device->buffer, irp, &info);
IoReleaseCancelSpinLock(irp->CancelIrql); /* before IoCompleteRequest()! */
fort_request_complete_info(irp, status, info);
}
FORT_API NTSTATUS fort_device_control(PDEVICE_OBJECT device, PIRP irp)
{
ULONG_PTR info = 0;
NTSTATUS status = STATUS_UNSUCCESSFUL;
UNUSED(device);
const PIO_STACK_LOCATION irp_stack = IoGetCurrentIrpStackLocation(irp);
const ULONG control_code = irp_stack->Parameters.DeviceIoControl.IoControlCode;
if (control_code != (ULONG) FORT_IOCTL_VALIDATE
&& !fort_device_flag(&g_device->conf, FORT_DEVICE_IS_VALIDATED))
goto end;
switch (control_code) {
case FORT_IOCTL_VALIDATE: {
const PFORT_CONF_VERSION conf_ver = irp->AssociatedIrp.SystemBuffer;
const ULONG len = irp_stack->Parameters.DeviceIoControl.InputBufferLength;
if (len == sizeof(FORT_CONF_VERSION)) {
if (conf_ver->driver_version == DRIVER_VERSION) {
fort_device_flag_set(&g_device->conf, FORT_DEVICE_IS_VALIDATED, TRUE);
status = STATUS_SUCCESS;
}
}
break;
}
case FORT_IOCTL_SETCONF: {
const PFORT_CONF_IO conf_io = irp->AssociatedIrp.SystemBuffer;
const ULONG len = irp_stack->Parameters.DeviceIoControl.InputBufferLength;
if (len > sizeof(FORT_CONF_IO)) {
const PFORT_CONF conf = &conf_io->conf;
PFORT_CONF_REF conf_ref = fort_conf_ref_new(conf, len - FORT_CONF_IO_CONF_OFF);
if (conf_ref == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
} else {
PFORT_STAT stat = &g_device->stat;
const FORT_CONF_FLAGS old_conf_flags = fort_conf_ref_set(&g_device->conf, conf_ref);
const UINT32 defer_flush_bits =
(stat->conf_group.limit_2bits ^ conf_io->conf_group.limit_2bits);
fort_stat_conf_update(stat, conf_io);
status = fort_callout_force_reauth(old_conf_flags, defer_flush_bits);
}
}
break;
}
case FORT_IOCTL_SETFLAGS: {
const PFORT_CONF_FLAGS conf_flags = irp->AssociatedIrp.SystemBuffer;
const ULONG len = irp_stack->Parameters.DeviceIoControl.InputBufferLength;
if (len == sizeof(FORT_CONF_FLAGS)) {
const FORT_CONF_FLAGS old_conf_flags =
fort_conf_ref_flags_set(&g_device->conf, conf_flags);
const UINT32 defer_flush_bits =
(old_conf_flags.group_bits != conf_flags->group_bits ? FORT_DEFER_FLUSH_ALL
: 0);
status = fort_callout_force_reauth(old_conf_flags, defer_flush_bits);
}
break;
}
case FORT_IOCTL_GETLOG: {
PVOID out = irp->AssociatedIrp.SystemBuffer;
const ULONG out_len = irp_stack->Parameters.DeviceIoControl.OutputBufferLength;
if (out_len < FORT_BUFFER_SIZE) {
status = STATUS_BUFFER_TOO_SMALL;
} else {
status = fort_buffer_xmove(&g_device->buffer, irp, out, out_len, &info);
if (status == STATUS_PENDING) {
KIRQL cirq;
IoMarkIrpPending(irp);
IoAcquireCancelSpinLock(&cirq);
IoSetCancelRoutine(irp, fort_device_cancel_pending);
IoReleaseCancelSpinLock(cirq);
return STATUS_PENDING;
}
}
break;
}
case FORT_IOCTL_ADDAPP:
case FORT_IOCTL_DELAPP: {
const PFORT_APP_ENTRY app_entry = irp->AssociatedIrp.SystemBuffer;
const ULONG len = irp_stack->Parameters.DeviceIoControl.InputBufferLength;
if (len > sizeof(FORT_APP_ENTRY) && len >= (sizeof(FORT_APP_ENTRY) + app_entry->path_len)) {
PFORT_CONF_REF conf_ref = fort_conf_ref_take(&g_device->conf);
if (conf_ref == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
} else {
if (control_code == (ULONG) FORT_IOCTL_ADDAPP) {
status = fort_conf_ref_exe_add_entry(conf_ref, app_entry, FALSE);
} else {
fort_conf_ref_exe_del_entry(conf_ref, app_entry);
status = STATUS_SUCCESS;
}
fort_conf_ref_put(&g_device->conf, conf_ref);
if (NT_SUCCESS(status)) {
fort_worker_reauth();
}
}
}
break;
}
case FORT_IOCTL_SETZONES: {
const PFORT_CONF_ZONES zones = irp->AssociatedIrp.SystemBuffer;
const ULONG len = irp_stack->Parameters.DeviceIoControl.InputBufferLength;
if (len >= FORT_CONF_ZONES_DATA_OFF) {
PFORT_CONF_ZONES conf_zones = fort_conf_zones_new(zones, len);
if (conf_zones == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
} else {
fort_conf_zones_set(&g_device->conf, conf_zones);
fort_worker_reauth();
status = STATUS_SUCCESS;
}
}
break;
}
case FORT_IOCTL_SETZONEFLAG: {
const PFORT_CONF_ZONE_FLAG zone_flag = irp->AssociatedIrp.SystemBuffer;
const ULONG len = irp_stack->Parameters.DeviceIoControl.InputBufferLength;
if (len == sizeof(FORT_CONF_ZONE_FLAG)) {
fort_conf_zone_flag_set(&g_device->conf, zone_flag);
fort_worker_reauth();
status = STATUS_SUCCESS;
}
break;
}
default:
break;
}
end:
if (!NT_SUCCESS(status) && status != FORT_STATUS_USER_ERROR) {
DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, "FORT: Device Control: Error: %x\n",
status);
}
fort_request_complete_info(irp, status, info);
return status;
}