/* * PROJECT: Filesystem Filter Manager * LICENSE: GPL - See COPYING in the top level directory * FILE: drivers/filters/fltmgr/Messaging.c * PURPOSE: Contains the routines to handle the comms layer * PROGRAMMERS: Ged Murphy (gedmurphy@reactos.org) */ /* INCLUDES ******************************************************************/ #include "fltmgr.h" #include "fltmgrint.h" #define NDEBUG #include /* DATA *********************************************************************/ UNICODE_STRING CommsDeviceName = RTL_CONSTANT_STRING(L"\\FileSystem\\Filters\\FltMgrMsg"); PDEVICE_OBJECT CommsDeviceObject; POBJECT_TYPE ServerPortObjectType; POBJECT_TYPE ClientPortObjectType; static BOOLEAN FltpDisconnectPort( _In_ PFLT_PORT_OBJECT PortObject ); /* EXPORTED FUNCTIONS ******************************************************/ _Must_inspect_result_ _IRQL_requires_max_(PASSIVE_LEVEL) NTSTATUS FLTAPI FltCreateCommunicationPort(_In_ PFLT_FILTER Filter, _Outptr_ PFLT_PORT *ServerPort, _In_ POBJECT_ATTRIBUTES ObjectAttributes, _In_opt_ PVOID ServerPortCookie, _In_ PFLT_CONNECT_NOTIFY ConnectNotifyCallback, _In_ PFLT_DISCONNECT_NOTIFY DisconnectNotifyCallback, _In_opt_ PFLT_MESSAGE_NOTIFY MessageNotifyCallback, _In_ LONG MaxConnections) { PFLT_SERVER_PORT_OBJECT PortObject; NTSTATUS Status; /* The caller must allow at least one connection */ if (MaxConnections == 0) { return STATUS_INVALID_PARAMETER; } /* The request must be for a kernel handle */ if (!(ObjectAttributes->Attributes & OBJ_KERNEL_HANDLE)) { return STATUS_INVALID_PARAMETER; } /* * Get rundown protection on the target to stop the owner * from unloading whilst this port object is open. It gets * removed in the FltpServerPortClose callback */ Status = FltObjectReference(Filter); if (!NT_SUCCESS(Status)) { return Status; } /* Create our new server port object */ Status = ObCreateObject(0, ServerPortObjectType, ObjectAttributes, KernelMode, NULL, sizeof(FLT_SERVER_PORT_OBJECT), 0, 0, (PVOID *)&PortObject); if (NT_SUCCESS(Status)) { /* Zero out the struct */ RtlZeroMemory(PortObject, sizeof(FLT_SERVER_PORT_OBJECT)); /* Increment the ref count on the target filter */ FltpObjectPointerReference((PFLT_OBJECT)Filter); /* Setup the filter port object */ PortObject->Filter = Filter; PortObject->ConnectNotify = ConnectNotifyCallback; PortObject->DisconnectNotify = DisconnectNotifyCallback; PortObject->MessageNotify = MessageNotifyCallback; PortObject->Cookie = ServerPortCookie; PortObject->MaxConnections = MaxConnections; /* Insert the object */ Status = ObInsertObject(PortObject, NULL, STANDARD_RIGHTS_ALL | FILE_READ_DATA, 0, NULL, (PHANDLE)ServerPort); if (NT_SUCCESS(Status)) { /* Lock the connection list */ ExAcquireFastMutex(&Filter->ConnectionList.mLock); /* Add the new port object to the connection list and increment the count */ InsertTailList(&Filter->ConnectionList.mList, &PortObject->FilterLink); Filter->ConnectionList.mCount++; /* Unlock the connection list*/ ExReleaseFastMutex(&Filter->ConnectionList.mLock); } } if (!NT_SUCCESS(Status)) { /* Allow the filter to be cleaned up */ FltObjectDereference(Filter); } return Status; } _IRQL_requires_max_(PASSIVE_LEVEL) VOID FLTAPI FltCloseCommunicationPort(_In_ PFLT_PORT ServerPort) { /* Just close the handle to initiate the cleanup callbacks */ ZwClose(ServerPort); } _IRQL_requires_max_(PASSIVE_LEVEL) VOID FLTAPI FltCloseClientPort(_In_ PFLT_FILTER Filter, _Inout_ PFLT_PORT *ClientPort) { PFLT_PORT Port; /* Protect against the handle being used whilst we're closing it */ FltAcquirePushLockShared(&Filter->PortLock); /* Store the port handle while we have the lock held */ Port = *ClientPort; if (*ClientPort) { /* Set the hadle to null */ *ClientPort = NULL; } /* Unlock the port */ FltReleasePushLock(&Filter->PortLock); if (Port) { /* Close the safe handle */ ZwClose(Port); } } _Must_inspect_result_ _IRQL_requires_max_(APC_LEVEL) NTSTATUS FLTAPI FltSendMessage(_In_ PFLT_FILTER Filter, _In_ PFLT_PORT *ClientPort, _In_reads_bytes_(SenderBufferLength) PVOID SenderBuffer, _In_ ULONG SenderBufferLength, _Out_writes_bytes_opt_(*ReplyLength) PVOID ReplyBuffer, _Inout_opt_ PULONG ReplyLength, _In_opt_ PLARGE_INTEGER Timeout) { UNREFERENCED_PARAMETER(Filter); UNREFERENCED_PARAMETER(ClientPort); UNREFERENCED_PARAMETER(SenderBuffer); UNREFERENCED_PARAMETER(SenderBufferLength); UNREFERENCED_PARAMETER(ReplyBuffer); UNREFERENCED_PARAMETER(ReplyLength); UNREFERENCED_PARAMETER(Timeout); return STATUS_NOT_IMPLEMENTED; } /* INTERNAL FUNCTIONS ******************************************************/ VOID NTAPI FltpServerPortClose(_In_opt_ PEPROCESS Process, _In_ PVOID Object, _In_ ACCESS_MASK GrantedAccess, _In_ ULONG ProcessHandleCount, _In_ ULONG SystemHandleCount) { PFLT_SERVER_PORT_OBJECT PortObject; PFAST_MUTEX Lock; /* Cast the object to a server port object */ PortObject = (PFLT_SERVER_PORT_OBJECT)Object; /* Lock the connection list */ Lock = &PortObject->Filter->ConnectionList.mLock; ExAcquireFastMutex(Lock); /* Remove the server port object from the list */ RemoveEntryList(&PortObject->FilterLink); /* Unlock the connection list */ ExReleaseFastMutex(Lock); /* Remove the rundown protection we added to stop the owner from tearing us down */ FltObjectDereference(PortObject->Filter); } VOID NTAPI FltpServerPortDelete(PVOID Object) { /* Decrement the filter count we added in the create routine */ PFLT_SERVER_PORT_OBJECT PortObject = (PFLT_SERVER_PORT_OBJECT)Object; FltpObjectPointerDereference((PFLT_OBJECT)PortObject->Filter); } VOID NTAPI FltpClientPortClose(_In_opt_ PEPROCESS Process, _In_ PVOID Object, _In_ ACCESS_MASK GrantedAccess, _In_ ULONG ProcessHandleCount, _In_ ULONG SystemHandleCount) { PFLT_PORT_OBJECT PortObject = (PFLT_PORT_OBJECT)Object; if (FltpDisconnectPort(PortObject)) { InterlockedDecrement(&PortObject->ServerPort->NumberOfConnections); } } BOOLEAN FltpDisconnectPort(_In_ PFLT_PORT_OBJECT PortObject) { BOOLEAN Disconnected = FALSE; /* Lock the port object while we disconnect it */ ExAcquireFastMutex(&PortObject->Lock); /* Make sure we have a valid connection */ if (PortObject->Disconnected == FALSE) { /* Let any waiters know we're dusconnecing */ KeSetEvent(&PortObject->DisconnectEvent, 0, 0); // cleanup everything in the message queue (PortObject->MsgQ.Csq) /* Set the disconnected state to true */ PortObject->Disconnected = TRUE; Disconnected = TRUE; } /* Unlock and exit*/ ExReleaseFastMutex(&PortObject->Lock); return Disconnected; } VOID NTAPI FltpClientPortDelete(PVOID Object) { PFLT_PORT_OBJECT PortObject = (PFLT_PORT_OBJECT)Object; ObfDereferenceObject(PortObject->ServerPort); } NTSTATUS FltpSetupCommunicationObjects(_In_ PDRIVER_OBJECT DriverObject) { OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; UNICODE_STRING SymLinkName; UNICODE_STRING Name; NTSTATUS Status; GENERIC_MAPPING Mapping = { STANDARD_RIGHTS_READ, STANDARD_RIGHTS_WRITE, STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE, FLT_PORT_ALL_ACCESS }; /* Create the server comms object type */ RtlZeroMemory(&ObjectTypeInitializer, sizeof(OBJECT_TYPE_INITIALIZER)); RtlInitUnicodeString(&Name, L"FilterConnectionPort"); ObjectTypeInitializer.Length = sizeof(OBJECT_TYPE_INITIALIZER); ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK; ObjectTypeInitializer.GenericMapping = Mapping; ObjectTypeInitializer.PoolType = NonPagedPool; ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(FLT_SERVER_PORT_OBJECT); ObjectTypeInitializer.ValidAccessMask = GENERIC_ALL; ObjectTypeInitializer.CloseProcedure = FltpServerPortClose; ObjectTypeInitializer.DeleteProcedure = FltpServerPortDelete; Status = ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &ServerPortObjectType); if (!NT_SUCCESS(Status)) return Status; /* Create the client comms object type */ RtlZeroMemory(&ObjectTypeInitializer, sizeof(OBJECT_TYPE_INITIALIZER)); RtlInitUnicodeString(&Name, L"FilterCommunicationPort"); ObjectTypeInitializer.Length = sizeof(OBJECT_TYPE_INITIALIZER); ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK; ObjectTypeInitializer.GenericMapping = Mapping; ObjectTypeInitializer.PoolType = NonPagedPool; ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(FLT_PORT_OBJECT); ObjectTypeInitializer.ValidAccessMask = GENERIC_ALL; ObjectTypeInitializer.CloseProcedure = FltpClientPortClose; ObjectTypeInitializer.DeleteProcedure = FltpClientPortDelete; Status = ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &ClientPortObjectType); if (!NT_SUCCESS(Status)) { goto Quit; } /* Create the device object */ Status = IoCreateDevice(DriverObject, 0, &CommsDeviceName, FILE_DEVICE_WPD, 0, 0, &CommsDeviceObject); if (NT_SUCCESS(Status)) { /* Setup a symbolic link for the device */ RtlInitUnicodeString(&SymLinkName, L"\\DosDevices\\FltMgrMsg"); Status = IoCreateSymbolicLink(&SymLinkName, &CommsDeviceName); } Quit: if (!NT_SUCCESS(Status)) { /* Something went wrong, undo */ if (CommsDeviceObject) { IoDeleteDevice(CommsDeviceObject); CommsDeviceObject = NULL; } if (ClientPortObjectType) { ObMakeTemporaryObject(ClientPortObjectType); ObfDereferenceObject(ClientPortObjectType); ClientPortObjectType = NULL; } if (ServerPortObjectType) { ObMakeTemporaryObject(ServerPortObjectType); ObfDereferenceObject(ServerPortObjectType); ServerPortObjectType = NULL; } } return Status; } /* PRIVATE FUNCTIONS ******************************************************/