Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

456 lines
12 KiB

#include <stdio.h>
#include <stdlib.h>
#include <ntddk.h>
#include <wmistr.h>
#include <evntrace.h>
#include <wmikm.h>
#define TRACEKMP_NT_DEVICE_NAME L"\\Device\\TraceKmp"
#define TRACEKMP_MOF_FILE L"MofResourceName"
PDEVICE_OBJECT pTracekmpDeviceObject;
UNICODE_STRING KmpRegistryPath;
typedef struct _DEVICE_EXTENSION {
PDEVICE_OBJECT DeviceObject;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
//
// ETW Globals
//
// 1. A control guid to identify this driver to ETW. The enable/disable state
// of this Guid controls enable/disable state of tracing for this driver.
GUID ControlGuid = \
{0xce5b1120, 0x8ea9, 0x11d1, 0xa4, 0xec, 0x00, 0xa0, 0xc9, 0x06, 0x29, 0x10};
// 2. EventGuids to fire events with. Can have more than one EventGuid.
GUID TracekmpGuid = \
{0xbc8700cb, 0x120b, 0x4aad, 0xbf, 0xbf, 0x99, 0x6e, 0x57, 0x60, 0xcb, 0x85};
// 3. EtwLoggerHandle to use with IoWMIWriteEvent.
TRACEHANDLE EtwLoggerHandle = 0;
// 4. EtwTraceEnable to indicate whether or not tracing is currently on.
ULONG EtwTraceEnable = 0;
// 5. EtwTraceLevel to indicate the current Level of logging
ULONG EtwTraceLevel = 0;
// Note: EtwLoggerHandle, EtwTraceEnable and EtwTraceLevel are set through
// ENABLE_EVENTS irp.
//
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
);
NTSTATUS
EtwDispatch(
IN PDEVICE_OBJECT pDO,
IN PIRP Irp
);
NTSTATUS
EtwRegisterGuids(
IN PWMIREGINFO WmiRegInfo,
IN ULONG wmiRegInfoSize,
IN PULONG pReturnSize
);
VOID
TracekmpDriverUnload(
IN PDRIVER_OBJECT DriverObject
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text( INIT, DriverEntry )
#pragma alloc_text( PAGE, EtwDispatch )
#pragma alloc_text( PAGE, EtwRegisterGuids )
#pragma alloc_text( PAGE, TracekmpDriverUnload )
#endif // ALLOC_PRAGMA
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
This is the callback function when we call IoCreateDriver to create a
WMI Driver Object. In this function, we need to remember the
DriverObject.
Arguments:
DriverObject - pointer to the driver object
RegistryPath - pointer to a unicode string representing the path
to driver-specific key in the registry
Return Value:
STATUS_SUCCESS if successful
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS status = STATUS_SUCCESS;
UNICODE_STRING deviceName;
KmpRegistryPath.Length = 0;
KmpRegistryPath.MaximumLength = RegistryPath->Length;
KmpRegistryPath.Buffer = ExAllocatePool(PagedPool,
RegistryPath->Length+2);
RtlCopyUnicodeString(&KmpRegistryPath, RegistryPath);
DriverObject->DriverUnload = TracekmpDriverUnload;
//
// STEP 1. Wire a function to start fielding WMI IRPS
//
DriverObject->MajorFunction[ IRP_MJ_SYSTEM_CONTROL ] = EtwDispatch;
RtlInitUnicodeString( &deviceName, TRACEKMP_NT_DEVICE_NAME );
status = IoCreateDevice(
DriverObject,
sizeof( DEVICE_EXTENSION ),
&deviceName,
FILE_DEVICE_UNKNOWN,
0,
FALSE,
&pTracekmpDeviceObject);
if( !NT_SUCCESS( status )) {
return status;
}
pTracekmpDeviceObject->Flags |= DO_BUFFERED_IO;
//
// STEP 2. Register with ETW here
//
status = IoWMIRegistrationControl(pTracekmpDeviceObject,
WMIREG_ACTION_REGISTER);
if (!NT_SUCCESS(status))
{
KdPrint((
"TRACEKMP: IoWMIRegistrationControl failed with %x\n",
status
));
}
return STATUS_SUCCESS;
}
VOID
TracekmpDriverUnload(
IN PDRIVER_OBJECT DriverObject
)
/*++
Routine Description:
Unregister from ETW logging and Unload this driver
Arguments:
DriverObject - Supplies a pointer to the driver object
Return Value:
--*/
{
PDEVICE_OBJECT pDevObj;
NTSTATUS status;
ExFreePool(KmpRegistryPath.Buffer);
pDevObj = DriverObject->DeviceObject;
//
// STEP 3: Unregister with ETW.
//
if (pDevObj != NULL) {
status = IoWMIRegistrationControl(pDevObj, WMIREG_ACTION_DEREGISTER);
if (!NT_SUCCESS(status))
{
KdPrint((
"TracekmpDriverUnload: Failed to unregister for ETW support\n"
));
}
}
IoDeleteDevice( pDevObj );
}
//
// STEP 4: Wire the ETW Dispatch function.
//
NTSTATUS
EtwDispatch(
IN PDEVICE_OBJECT pDO,
IN PIRP Irp
)
/*++
Routine Description:
This is the dispatch routine for MJ_SYSTEM_CONTROL irps.
Arguments:
pDO - Pointer to the target device object.
Irp - Pointer to IRP
Return Value:
NTSTATUS - Completion status.
--*/
{
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
ULONG BufferSize = irpSp->Parameters.WMI.BufferSize;
PVOID Buffer = irpSp->Parameters.WMI.Buffer;
ULONG ReturnSize = 0;
NTSTATUS status = STATUS_SUCCESS;
UNREFERENCED_PARAMETER(pDO);
switch (irpSp->MinorFunction) {
case IRP_MN_REGINFO:
{
status = EtwRegisterGuids( (PWMIREGINFO) Buffer,
BufferSize,
&ReturnSize);
Irp->IoStatus.Information = ReturnSize;
Irp->IoStatus.Status = status;
IoCompleteRequest( Irp, IO_NO_INCREMENT );
return status;
}
case IRP_MN_ENABLE_EVENTS:
{
if ( (BufferSize < sizeof(WNODE_HEADER)) || (Buffer == NULL) ) {
status = STATUS_INVALID_PARAMETER;
}
else {
//
// The Buffer that came is a WNODE_HEADER. Now Validate the
// Wnode before using it.
//
PWNODE_HEADER Wnode = (PWNODE_HEADER)Buffer;
if ( (Wnode->BufferSize < sizeof(WNODE_HEADER)) ||
!IsEqualGUID(&Wnode->Guid, &ControlGuid) )
{
status = STATUS_INVALID_PARAMETER;
}
//
// and the LoggerHandle
// is in its HistoricalContext field.
// We can pick up the Enable Level and Flags by using
// the WmiGetLoggerEnableLevel and WmiGetLoggerEnableFlags calls
//
EtwLoggerHandle = Wnode->HistoricalContext;
EtwTraceLevel = (ULONG) WmiGetLoggerEnableLevel(
EtwLoggerHandle
);
//
// After picking up the LoggerHandle and EnableLevel we can
// set the flag EtwTraceEnable to true.
//
EtwTraceEnable = TRUE;
//
// Now this driver is enabled and ready to send traces to the
// EventTrace session specified by the EtwLoggerHandle.
//
// The commented code fragment below shows a typical example of
// sending an event to an Event Trace session. Insert this code
// fragment (and remove the comments) wherever you want to
// send traces to ETW from this driver.
//
// if (EtwTraceEnable) {
// EVENT_TRACE_HEADER Header;
// PEVENT_TRACE_HEADER Wnode;
// NTSTATUS status;
// Wnode = &Header;
// RtlZeroMemory(Wnode, sizeof(EVENT_TRACE_HEADER));
// Wnode->Size = sizeof(EVENT_TRACE_HEADER);
// Wnode->Flags |= WNODE_FLAG_TRACED_GUID;
// Wnode->Guid = TracekmpGuid;
// ((PWNODE_HEADER)Wnode)->HistoricalContext = EtwLoggerHandle;
// status = IoWMIWriteEvent((PVOID)Wnode);
// }
// STEP 6: Add IoWMIWriteEvent calls from various locations
// of the driver code to trace its operation.
//
}
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
IoCompleteRequest( Irp, IO_NO_INCREMENT );
return status;
}
case IRP_MN_DISABLE_EVENTS:
{
EtwTraceEnable = FALSE;
EtwTraceLevel = 0;
EtwLoggerHandle = 0;
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
IoCompleteRequest( Irp, IO_NO_INCREMENT );
return status;
}
default:
{
status = STATUS_INVALID_DEVICE_REQUEST;
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
IoCompleteRequest( Irp, IO_NO_INCREMENT );
return status;
}
}
return status;
}
//
// STEP 5: RegisterGuids function
//
NTSTATUS
EtwRegisterGuids(
IN PWMIREGINFO EtwRegInfo,
IN ULONG etwRegInfoSize,
IN PULONG pReturnSize
)
/*++
Routine Description:
This function handles ETW GUID registration.
Arguments:
EtwRegInfo
etwRegInfoSize,
pReturnSize
Return Value:
NTSTATUS - Completion status.
--*/
{
//
// Register a Control Guid as a Trace Guid.
//
ULONG SizeNeeded;
PWMIREGGUIDW EtwRegGuidPtr;
ULONG RegistryPathSize;
ULONG MofResourceSize;
PUCHAR ptmp;
//
// We either have a valid buffer to fill up or have at least
// enough room to return the SizeNeeded.
//
if ( (pReturnSize == NULL) ||
(EtwRegInfo == NULL) ||
(etwRegInfoSize < sizeof(ULONG)) ) {
return STATUS_INVALID_PARAMETER;
}
*pReturnSize = 0;
//
// Allocate WMIREGINFO for controlGuid
//
RegistryPathSize = KmpRegistryPath.Length +
sizeof(USHORT);
MofResourceSize = sizeof(TRACEKMP_MOF_FILE) -
sizeof(WCHAR) +
sizeof(USHORT);
SizeNeeded = sizeof(WMIREGINFOW) + sizeof(WMIREGGUIDW) +
RegistryPathSize +
MofResourceSize;
//
// If there is not sufficient space, return the size required as
// a ULONG and WMI will send another request with the right size buffer.
//
if (SizeNeeded > etwRegInfoSize) {
*((PULONG)EtwRegInfo) = SizeNeeded;
*pReturnSize = sizeof(ULONG);
return STATUS_BUFFER_TOO_SMALL;
}
RtlZeroMemory(EtwRegInfo, SizeNeeded);
EtwRegInfo->BufferSize = SizeNeeded;
EtwRegInfo->GuidCount = 1;
EtwRegInfo->RegistryPath = sizeof(WMIREGINFOW) + sizeof(WMIREGGUIDW);
EtwRegInfo->MofResourceName = EtwRegInfo->RegistryPath + RegistryPathSize;
EtwRegGuidPtr = &EtwRegInfo->WmiRegGuid[0];
EtwRegGuidPtr->Guid = ControlGuid;
EtwRegGuidPtr->Flags |= WMIREG_FLAG_TRACED_GUID;
EtwRegGuidPtr->Flags |= WMIREG_FLAG_TRACE_CONTROL_GUID;
EtwRegGuidPtr->InstanceCount = 0;
EtwRegGuidPtr->InstanceInfo = 0;
ptmp = (PUCHAR)&EtwRegInfo->WmiRegGuid[1];
*((PUSHORT)ptmp) = KmpRegistryPath.Length;
ptmp += sizeof(USHORT);
RtlCopyMemory(ptmp,
KmpRegistryPath.Buffer,
KmpRegistryPath.Length);
ptmp = (PUCHAR)EtwRegInfo + EtwRegInfo->MofResourceName;
*((PUSHORT)ptmp) = sizeof(TRACEKMP_MOF_FILE) - sizeof(WCHAR);
ptmp += sizeof(USHORT);
RtlCopyMemory(ptmp,
TRACEKMP_MOF_FILE,
sizeof(TRACEKMP_MOF_FILE) - sizeof(WCHAR)
);
*pReturnSize = SizeNeeded;
return STATUS_SUCCESS;
}