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

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <ntddk.h>
  4. #include <wmistr.h>
  5. #include <evntrace.h>
  6. #include <wmikm.h>
  7. #define TRACEKMP_NT_DEVICE_NAME L"\\Device\\TraceKmp"
  8. #define TRACEKMP_MOF_FILE L"MofResourceName"
  9. PDEVICE_OBJECT pTracekmpDeviceObject;
  10. UNICODE_STRING KmpRegistryPath;
  11. typedef struct _DEVICE_EXTENSION {
  12. PDEVICE_OBJECT DeviceObject;
  13. } DEVICE_EXTENSION, *PDEVICE_EXTENSION;
  14. //
  15. // ETW Globals
  16. //
  17. // 1. A control guid to identify this driver to ETW. The enable/disable state
  18. // of this Guid controls enable/disable state of tracing for this driver.
  19. GUID ControlGuid = \
  20. {0xce5b1120, 0x8ea9, 0x11d1, 0xa4, 0xec, 0x00, 0xa0, 0xc9, 0x06, 0x29, 0x10};
  21. // 2. EventGuids to fire events with. Can have more than one EventGuid.
  22. GUID TracekmpGuid = \
  23. {0xbc8700cb, 0x120b, 0x4aad, 0xbf, 0xbf, 0x99, 0x6e, 0x57, 0x60, 0xcb, 0x85};
  24. // 3. EtwLoggerHandle to use with IoWMIWriteEvent.
  25. TRACEHANDLE EtwLoggerHandle = 0;
  26. // 4. EtwTraceEnable to indicate whether or not tracing is currently on.
  27. ULONG EtwTraceEnable = 0;
  28. // 5. EtwTraceLevel to indicate the current Level of logging
  29. ULONG EtwTraceLevel = 0;
  30. // Note: EtwLoggerHandle, EtwTraceEnable and EtwTraceLevel are set through
  31. // ENABLE_EVENTS irp.
  32. //
  33. NTSTATUS
  34. DriverEntry(
  35. IN PDRIVER_OBJECT DriverObject,
  36. IN PUNICODE_STRING RegistryPath
  37. );
  38. NTSTATUS
  39. EtwDispatch(
  40. IN PDEVICE_OBJECT pDO,
  41. IN PIRP Irp
  42. );
  43. NTSTATUS
  44. EtwRegisterGuids(
  45. IN PWMIREGINFO WmiRegInfo,
  46. IN ULONG wmiRegInfoSize,
  47. IN PULONG pReturnSize
  48. );
  49. VOID
  50. TracekmpDriverUnload(
  51. IN PDRIVER_OBJECT DriverObject
  52. );
  53. #ifdef ALLOC_PRAGMA
  54. #pragma alloc_text( INIT, DriverEntry )
  55. #pragma alloc_text( PAGE, EtwDispatch )
  56. #pragma alloc_text( PAGE, EtwRegisterGuids )
  57. #pragma alloc_text( PAGE, TracekmpDriverUnload )
  58. #endif // ALLOC_PRAGMA
  59. NTSTATUS
  60. DriverEntry(
  61. IN PDRIVER_OBJECT DriverObject,
  62. IN PUNICODE_STRING RegistryPath
  63. )
  64. /*++
  65. Routine Description:
  66. This is the callback function when we call IoCreateDriver to create a
  67. WMI Driver Object. In this function, we need to remember the
  68. DriverObject.
  69. Arguments:
  70. DriverObject - pointer to the driver object
  71. RegistryPath - pointer to a unicode string representing the path
  72. to driver-specific key in the registry
  73. Return Value:
  74. STATUS_SUCCESS if successful
  75. STATUS_UNSUCCESSFUL otherwise
  76. --*/
  77. {
  78. NTSTATUS status = STATUS_SUCCESS;
  79. UNICODE_STRING deviceName;
  80. KmpRegistryPath.Length = 0;
  81. KmpRegistryPath.MaximumLength = RegistryPath->Length;
  82. KmpRegistryPath.Buffer = ExAllocatePool(PagedPool,
  83. RegistryPath->Length+2);
  84. RtlCopyUnicodeString(&KmpRegistryPath, RegistryPath);
  85. DriverObject->DriverUnload = TracekmpDriverUnload;
  86. //
  87. // STEP 1. Wire a function to start fielding WMI IRPS
  88. //
  89. DriverObject->MajorFunction[ IRP_MJ_SYSTEM_CONTROL ] = EtwDispatch;
  90. RtlInitUnicodeString( &deviceName, TRACEKMP_NT_DEVICE_NAME );
  91. status = IoCreateDevice(
  92. DriverObject,
  93. sizeof( DEVICE_EXTENSION ),
  94. &deviceName,
  95. FILE_DEVICE_UNKNOWN,
  96. 0,
  97. FALSE,
  98. &pTracekmpDeviceObject);
  99. if( !NT_SUCCESS( status )) {
  100. return status;
  101. }
  102. pTracekmpDeviceObject->Flags |= DO_BUFFERED_IO;
  103. //
  104. // STEP 2. Register with ETW here
  105. //
  106. status = IoWMIRegistrationControl(pTracekmpDeviceObject,
  107. WMIREG_ACTION_REGISTER);
  108. if (!NT_SUCCESS(status))
  109. {
  110. KdPrint((
  111. "TRACEKMP: IoWMIRegistrationControl failed with %x\n",
  112. status
  113. ));
  114. }
  115. return STATUS_SUCCESS;
  116. }
  117. VOID
  118. TracekmpDriverUnload(
  119. IN PDRIVER_OBJECT DriverObject
  120. )
  121. /*++
  122. Routine Description:
  123. Unregister from ETW logging and Unload this driver
  124. Arguments:
  125. DriverObject - Supplies a pointer to the driver object
  126. Return Value:
  127. --*/
  128. {
  129. PDEVICE_OBJECT pDevObj;
  130. NTSTATUS status;
  131. ExFreePool(KmpRegistryPath.Buffer);
  132. pDevObj = DriverObject->DeviceObject;
  133. //
  134. // STEP 3: Unregister with ETW.
  135. //
  136. if (pDevObj != NULL) {
  137. status = IoWMIRegistrationControl(pDevObj, WMIREG_ACTION_DEREGISTER);
  138. if (!NT_SUCCESS(status))
  139. {
  140. KdPrint((
  141. "TracekmpDriverUnload: Failed to unregister for ETW support\n"
  142. ));
  143. }
  144. }
  145. IoDeleteDevice( pDevObj );
  146. }
  147. //
  148. // STEP 4: Wire the ETW Dispatch function.
  149. //
  150. NTSTATUS
  151. EtwDispatch(
  152. IN PDEVICE_OBJECT pDO,
  153. IN PIRP Irp
  154. )
  155. /*++
  156. Routine Description:
  157. This is the dispatch routine for MJ_SYSTEM_CONTROL irps.
  158. Arguments:
  159. pDO - Pointer to the target device object.
  160. Irp - Pointer to IRP
  161. Return Value:
  162. NTSTATUS - Completion status.
  163. --*/
  164. {
  165. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  166. ULONG BufferSize = irpSp->Parameters.WMI.BufferSize;
  167. PVOID Buffer = irpSp->Parameters.WMI.Buffer;
  168. ULONG ReturnSize = 0;
  169. NTSTATUS status = STATUS_SUCCESS;
  170. UNREFERENCED_PARAMETER(pDO);
  171. switch (irpSp->MinorFunction) {
  172. case IRP_MN_REGINFO:
  173. {
  174. status = EtwRegisterGuids( (PWMIREGINFO) Buffer,
  175. BufferSize,
  176. &ReturnSize);
  177. Irp->IoStatus.Information = ReturnSize;
  178. Irp->IoStatus.Status = status;
  179. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  180. return status;
  181. }
  182. case IRP_MN_ENABLE_EVENTS:
  183. {
  184. if ( (BufferSize < sizeof(WNODE_HEADER)) || (Buffer == NULL) ) {
  185. status = STATUS_INVALID_PARAMETER;
  186. }
  187. else {
  188. //
  189. // The Buffer that came is a WNODE_HEADER. Now Validate the
  190. // Wnode before using it.
  191. //
  192. PWNODE_HEADER Wnode = (PWNODE_HEADER)Buffer;
  193. if ( (Wnode->BufferSize < sizeof(WNODE_HEADER)) ||
  194. !IsEqualGUID(&Wnode->Guid, &ControlGuid) )
  195. {
  196. status = STATUS_INVALID_PARAMETER;
  197. }
  198. //
  199. // and the LoggerHandle
  200. // is in its HistoricalContext field.
  201. // We can pick up the Enable Level and Flags by using
  202. // the WmiGetLoggerEnableLevel and WmiGetLoggerEnableFlags calls
  203. //
  204. EtwLoggerHandle = Wnode->HistoricalContext;
  205. EtwTraceLevel = (ULONG) WmiGetLoggerEnableLevel(
  206. EtwLoggerHandle
  207. );
  208. //
  209. // After picking up the LoggerHandle and EnableLevel we can
  210. // set the flag EtwTraceEnable to true.
  211. //
  212. EtwTraceEnable = TRUE;
  213. //
  214. // Now this driver is enabled and ready to send traces to the
  215. // EventTrace session specified by the EtwLoggerHandle.
  216. //
  217. // The commented code fragment below shows a typical example of
  218. // sending an event to an Event Trace session. Insert this code
  219. // fragment (and remove the comments) wherever you want to
  220. // send traces to ETW from this driver.
  221. //
  222. // if (EtwTraceEnable) {
  223. // EVENT_TRACE_HEADER Header;
  224. // PEVENT_TRACE_HEADER Wnode;
  225. // NTSTATUS status;
  226. // Wnode = &Header;
  227. // RtlZeroMemory(Wnode, sizeof(EVENT_TRACE_HEADER));
  228. // Wnode->Size = sizeof(EVENT_TRACE_HEADER);
  229. // Wnode->Flags |= WNODE_FLAG_TRACED_GUID;
  230. // Wnode->Guid = TracekmpGuid;
  231. // ((PWNODE_HEADER)Wnode)->HistoricalContext = EtwLoggerHandle;
  232. // status = IoWMIWriteEvent((PVOID)Wnode);
  233. // }
  234. // STEP 6: Add IoWMIWriteEvent calls from various locations
  235. // of the driver code to trace its operation.
  236. //
  237. }
  238. Irp->IoStatus.Status = status;
  239. Irp->IoStatus.Information = 0;
  240. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  241. return status;
  242. }
  243. case IRP_MN_DISABLE_EVENTS:
  244. {
  245. EtwTraceEnable = FALSE;
  246. EtwTraceLevel = 0;
  247. EtwLoggerHandle = 0;
  248. Irp->IoStatus.Status = status;
  249. Irp->IoStatus.Information = 0;
  250. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  251. return status;
  252. }
  253. default:
  254. {
  255. status = STATUS_INVALID_DEVICE_REQUEST;
  256. Irp->IoStatus.Status = status;
  257. Irp->IoStatus.Information = 0;
  258. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  259. return status;
  260. }
  261. }
  262. return status;
  263. }
  264. //
  265. // STEP 5: RegisterGuids function
  266. //
  267. NTSTATUS
  268. EtwRegisterGuids(
  269. IN PWMIREGINFO EtwRegInfo,
  270. IN ULONG etwRegInfoSize,
  271. IN PULONG pReturnSize
  272. )
  273. /*++
  274. Routine Description:
  275. This function handles ETW GUID registration.
  276. Arguments:
  277. EtwRegInfo
  278. etwRegInfoSize,
  279. pReturnSize
  280. Return Value:
  281. NTSTATUS - Completion status.
  282. --*/
  283. {
  284. //
  285. // Register a Control Guid as a Trace Guid.
  286. //
  287. ULONG SizeNeeded;
  288. PWMIREGGUIDW EtwRegGuidPtr;
  289. ULONG RegistryPathSize;
  290. ULONG MofResourceSize;
  291. PUCHAR ptmp;
  292. //
  293. // We either have a valid buffer to fill up or have at least
  294. // enough room to return the SizeNeeded.
  295. //
  296. if ( (pReturnSize == NULL) ||
  297. (EtwRegInfo == NULL) ||
  298. (etwRegInfoSize < sizeof(ULONG)) ) {
  299. return STATUS_INVALID_PARAMETER;
  300. }
  301. *pReturnSize = 0;
  302. //
  303. // Allocate WMIREGINFO for controlGuid
  304. //
  305. RegistryPathSize = KmpRegistryPath.Length +
  306. sizeof(USHORT);
  307. MofResourceSize = sizeof(TRACEKMP_MOF_FILE) -
  308. sizeof(WCHAR) +
  309. sizeof(USHORT);
  310. SizeNeeded = sizeof(WMIREGINFOW) + sizeof(WMIREGGUIDW) +
  311. RegistryPathSize +
  312. MofResourceSize;
  313. //
  314. // If there is not sufficient space, return the size required as
  315. // a ULONG and WMI will send another request with the right size buffer.
  316. //
  317. if (SizeNeeded > etwRegInfoSize) {
  318. *((PULONG)EtwRegInfo) = SizeNeeded;
  319. *pReturnSize = sizeof(ULONG);
  320. return STATUS_BUFFER_TOO_SMALL;
  321. }
  322. RtlZeroMemory(EtwRegInfo, SizeNeeded);
  323. EtwRegInfo->BufferSize = SizeNeeded;
  324. EtwRegInfo->GuidCount = 1;
  325. EtwRegInfo->RegistryPath = sizeof(WMIREGINFOW) + sizeof(WMIREGGUIDW);
  326. EtwRegInfo->MofResourceName = EtwRegInfo->RegistryPath + RegistryPathSize;
  327. EtwRegGuidPtr = &EtwRegInfo->WmiRegGuid[0];
  328. EtwRegGuidPtr->Guid = ControlGuid;
  329. EtwRegGuidPtr->Flags |= WMIREG_FLAG_TRACED_GUID;
  330. EtwRegGuidPtr->Flags |= WMIREG_FLAG_TRACE_CONTROL_GUID;
  331. EtwRegGuidPtr->InstanceCount = 0;
  332. EtwRegGuidPtr->InstanceInfo = 0;
  333. ptmp = (PUCHAR)&EtwRegInfo->WmiRegGuid[1];
  334. *((PUSHORT)ptmp) = KmpRegistryPath.Length;
  335. ptmp += sizeof(USHORT);
  336. RtlCopyMemory(ptmp,
  337. KmpRegistryPath.Buffer,
  338. KmpRegistryPath.Length);
  339. ptmp = (PUCHAR)EtwRegInfo + EtwRegInfo->MofResourceName;
  340. *((PUSHORT)ptmp) = sizeof(TRACEKMP_MOF_FILE) - sizeof(WCHAR);
  341. ptmp += sizeof(USHORT);
  342. RtlCopyMemory(ptmp,
  343. TRACEKMP_MOF_FILE,
  344. sizeof(TRACEKMP_MOF_FILE) - sizeof(WCHAR)
  345. );
  346. *pReturnSize = SizeNeeded;
  347. return STATUS_SUCCESS;
  348. }