xref: /reactos/ntoskrnl/wmi/wmidrv.c (revision c2c66aff)
1 /*
2  * PROJECT:         ReactOS Kernel
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            ntoskrnl/wmi/wmidrv.c
5  * PURPOSE:         I/O Windows Management Instrumentation (WMI) Support
6  * PROGRAMMERS:     Timo Kreuzer (timo.kreuzer@reactos.org)
7  */
8 
9 /* INCLUDES *****************************************************************/
10 
11 #include <ntoskrnl.h>
12 #include <wmistr.h>
13 #include <wmiioctl.h>
14 #include "wmip.h"
15 
16 #define NDEBUG
17 #include <debug.h>
18 
19 // FIXME: these should go to a shared header
20 typedef struct _WMIP_REGISTER_GUIDS
21 {
22     POBJECT_ATTRIBUTES ObjectAttributes;
23     ULONG Unknown04;
24     ULONG Unknown08;
25     ULONG Unknown0C;
26     ULONG Unknown10;
27     ULONG Unknown14;
28 
29     WMIREGINFOW RegInfo;
30 } WMIP_REGISTER_GUIDS, *PWMIP_REGISTER_GUIDS;
31 
32 typedef struct _WMIP_RESULT
33 {
34     HANDLE Handle;
35     ULONG Unknown04;
36     TRACEHANDLE TraceHandle;
37     BOOLEAN Unknown10;
38 } WMIP_RESULT, *PWMIP_RESULT;
39 
40 typedef struct _WMI_UNREGISTER_GUID
41 {
42     GUID Guid;
43     ULONG Unknown10;
44     ULONG Unknown14;
45     ULONG Unknown18;
46     ULONG Unknown1C;
47 } WMI_UNREGISTER_GUID, *PWMI_UNREGISTER_GUID;
48 
49 typedef struct _WMI_GUID_OBJECT_ENTRY
50 {
51     HANDLE Handle;
52     ULONG Unknown04;
53 } WMI_GUID_OBJECT_ENTRY, *PWMI_GUID_OBJECT_ENTRY;
54 
55 typedef struct _WMI_NOTIFICATION
56 {
57     ULONG NumberOfGuidObjects;
58     ULONG Unknown04;
59     ULONG Unknown08;
60     ULONG Unknown0C;
61     ULONG Unknown10;
62     ULONG Unknown14;
63     WMI_GUID_OBJECT_ENTRY GuidObjects[0];
64 } WMI_NOTIFICATION, *PWMI_NOTIFICATION;
65 
66 typedef struct _WMI_SET_MARK
67 {
68     ULONG Flags;
69     WCHAR Mark[1];
70 } WMI_SET_MARK, *PWMI_SET_MARK;
71 
72 PDEVICE_OBJECT WmipServiceDeviceObject;
73 PDEVICE_OBJECT WmipAdminDeviceObject;
74 FAST_IO_DISPATCH WmipFastIoDispatch;
75 
76 
77 /* FUNCTIONS *****************************************************************/
78 
79 DRIVER_DISPATCH WmipOpenCloseCleanup;
80 DRIVER_DISPATCH WmipIoControl;
81 DRIVER_DISPATCH WmipSystemControl;
82 DRIVER_DISPATCH WmipShutdown;
83 
84 NTSTATUS
85 NTAPI
WmipOpenCloseCleanup(_In_ PDEVICE_OBJECT DeviceObject,_Inout_ PIRP Irp)86 WmipOpenCloseCleanup(
87     _In_ PDEVICE_OBJECT DeviceObject,
88     _Inout_ PIRP Irp)
89 {
90     PAGED_CODE();
91 
92     /* No work to do, just return success */
93     Irp->IoStatus.Status = STATUS_SUCCESS;
94     Irp->IoStatus.Information = 0;
95     IoCompleteRequest(Irp, IO_NO_INCREMENT);
96     return STATUS_SUCCESS;
97 }
98 
99 static
100 NTSTATUS
WmiTraceEvent(PVOID InputBuffer,KPROCESSOR_MODE PreviousMode)101 WmiTraceEvent(
102     PVOID InputBuffer,
103     KPROCESSOR_MODE PreviousMode)
104 {
105     UNIMPLEMENTED_DBGBREAK();
106     return STATUS_SUCCESS;
107 }
108 
109 static
110 NTSTATUS
WmiTraceUserMessage(PVOID InputBuffer,ULONG InputBufferLength)111 WmiTraceUserMessage(
112     PVOID InputBuffer,
113     ULONG InputBufferLength)
114 {
115     UNIMPLEMENTED_DBGBREAK();
116     return STATUS_SUCCESS;
117 }
118 
119 static
120 NTSTATUS
WmipCaptureGuidObjectAttributes(_In_ POBJECT_ATTRIBUTES GuidObjectAttributes,_Out_ POBJECT_ATTRIBUTES CapuredObjectAttributes,_Out_ PUNICODE_STRING CapturedObjectName,_Out_ PWSTR ObjectNameBuffer,_In_ KPROCESSOR_MODE AccessMode)121 WmipCaptureGuidObjectAttributes(
122     _In_ POBJECT_ATTRIBUTES GuidObjectAttributes,
123     _Out_ POBJECT_ATTRIBUTES CapuredObjectAttributes,
124     _Out_ PUNICODE_STRING CapturedObjectName,
125     _Out_ PWSTR ObjectNameBuffer,
126     _In_ KPROCESSOR_MODE AccessMode)
127 {
128     ASSERT(AccessMode != KernelMode);
129 
130     _SEH2_TRY
131     {
132         /* Probe and copy the object attributes structure */
133         ProbeForRead(GuidObjectAttributes,
134                      sizeof(OBJECT_ATTRIBUTES),
135                      sizeof(PVOID));
136         *CapuredObjectAttributes = *GuidObjectAttributes;
137 
138         /* Probe and copy the object name UNICODE_STRING */
139         ProbeForRead(CapuredObjectAttributes->ObjectName,
140                      sizeof(UNICODE_STRING),
141                      sizeof(PVOID));
142         *CapturedObjectName = *CapuredObjectAttributes->ObjectName;
143 
144         /* Check if the object name has the expected length */
145         if (CapturedObjectName->Length != 45 * sizeof(WCHAR))
146         {
147             _SEH2_YIELD(return STATUS_INVALID_PARAMETER);
148         }
149 
150         /* Probe and copy the object name buffer */
151         ProbeForRead(CapturedObjectName->Buffer,
152                      CapturedObjectName->Length,
153                      sizeof(WCHAR));
154         RtlCopyMemory(ObjectNameBuffer,
155                       CapturedObjectName->Buffer,
156                       CapturedObjectName->Length);
157 
158         /* Fix pointers */
159         CapturedObjectName->Buffer = ObjectNameBuffer;
160         GuidObjectAttributes->ObjectName = CapturedObjectName;
161     }
162     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
163     {
164         DPRINT1("Got exception!\n");
165         _SEH2_YIELD(return _SEH2_GetExceptionCode());
166     }
167     _SEH2_END;
168 
169     return STATUS_SUCCESS;
170 }
171 
172 static
173 NTSTATUS
WmipRegisterGuids(_In_ PDEVICE_OBJECT DeviceObject,_In_ PVOID Buffer,_In_ ULONG InputLength,_Inout_ PULONG OutputLength)174 WmipRegisterGuids(
175     _In_ PDEVICE_OBJECT DeviceObject,
176     _In_ PVOID Buffer,
177     _In_ ULONG InputLength,
178     _Inout_ PULONG OutputLength)
179 {
180     PWMIP_REGISTER_GUIDS RegisterGuids = (PWMIP_REGISTER_GUIDS)Buffer;
181     PWMIP_RESULT Result = (PWMIP_RESULT)Buffer;
182     OBJECT_ATTRIBUTES LocalObjectAttributes;
183     UNICODE_STRING LocalObjectName;
184     WCHAR LocalObjectNameBuffer[45 + 1];
185     KPROCESSOR_MODE PreviousMode;
186     HANDLE GuidObjectHandle;
187     PVOID GuidObject;
188     NTSTATUS Status;
189 
190     /* Make sure the input buffer is large enough */
191     if ((InputLength < sizeof(WMIP_REGISTER_GUIDS)) ||
192         (RegisterGuids->RegInfo.BufferSize >
193          (InputLength - FIELD_OFFSET(WMIP_REGISTER_GUIDS, RegInfo))))
194     {
195         return STATUS_UNSUCCESSFUL;
196     }
197 
198     /* Make sure we have a resonable GUID count */
199     if ((RegisterGuids->RegInfo.GuidCount == 0) ||
200         (RegisterGuids->RegInfo.GuidCount > 0x10000))
201     {
202         return STATUS_UNSUCCESSFUL;
203     }
204 
205     /* Capture object attributes */
206     PreviousMode = ExGetPreviousMode();
207     Status = WmipCaptureGuidObjectAttributes(RegisterGuids->ObjectAttributes,
208                                              &LocalObjectAttributes,
209                                              &LocalObjectName,
210                                              LocalObjectNameBuffer,
211                                              PreviousMode);
212     if (!NT_SUCCESS(Status))
213     {
214         DPRINT1("WmipCaptureGuidObjectAttributes failed: 0x%lx\n", Status);
215         return Status;
216     }
217 
218     /* Open a new GUID object */
219     Status = WmipOpenGuidObjectByName(&LocalObjectAttributes,
220                                       SPECIFIC_RIGHTS_ALL,
221                                       PreviousMode,
222                                       &GuidObjectHandle,
223                                       &GuidObject);
224     if (!NT_SUCCESS(Status))
225     {
226         DPRINT1("WmipOpenGuidObjectByName failed: 0x%lx\n", Status);
227         return Status;
228     }
229 
230     /* Dereference the GUID object */
231     ObDereferenceObject(GuidObject);
232 
233     /* Return the handle (user mode will close it) */
234     Result->Handle = GuidObjectHandle;
235     Result->TraceHandle = 0;
236     *OutputLength = 24;
237 
238     return STATUS_SUCCESS;
239 }
240 
241 
242 static
243 NTSTATUS
WmipUnregisterGuids(_In_ PVOID Buffer,_In_ ULONG InputLength,_Inout_ PULONG OutputLength)244 WmipUnregisterGuids(
245     _In_ PVOID Buffer,
246     _In_ ULONG InputLength,
247     _Inout_ PULONG OutputLength)
248 {
249     /* For now we have nothing to do */
250     return STATUS_SUCCESS;
251 }
252 
253 VOID
254 NTAPI
WmipClearIrpObjectList(_In_ PIRP Irp)255 WmipClearIrpObjectList(
256     _In_ PIRP Irp)
257 {
258     PWMIP_IRP_CONTEXT IrpContext;
259     PLIST_ENTRY ListEntry;
260     PWMIP_GUID_OBJECT GuidObject;
261 
262     /* Get the IRP context */
263     IrpContext = (PWMIP_IRP_CONTEXT)Irp->Tail.Overlay.DriverContext;
264 
265     /* Loop all GUID objects attached to this IRP */
266     for (ListEntry = IrpContext->GuidObjectListHead.Flink;
267          ListEntry != &IrpContext->GuidObjectListHead;
268          ListEntry = ListEntry->Flink)
269     {
270         /* Get the GUID object */
271         GuidObject = CONTAINING_RECORD(ListEntry, WMIP_GUID_OBJECT, IrpLink);
272 
273         /* Make sure the IRP matches and clear it */
274         ASSERT(GuidObject->Irp == Irp);
275         GuidObject->Irp = NULL;
276 
277         /* Remove the entry */
278         RemoveEntryList(ListEntry);
279     }
280 }
281 
282 VOID
283 NTAPI
WmipNotificationIrpCancel(_In_ PDEVICE_OBJECT DeviceObject,_Inout_ PIRP Irp)284 WmipNotificationIrpCancel(
285     _In_ PDEVICE_OBJECT DeviceObject,
286     _Inout_ PIRP Irp)
287 {
288     /* Clear the list */
289     WmipClearIrpObjectList(Irp);
290 
291     /* Release the cancel spin lock */
292     IoReleaseCancelSpinLock(Irp->CancelIrql);
293 
294     /* Set the status to cancelled and complete the IRP */
295     Irp->IoStatus.Status = STATUS_CANCELLED;
296     Irp->IoStatus.Information = 0;
297     IoCompleteRequest(Irp, IO_NO_INCREMENT);
298 }
299 
300 static
301 VOID
WmipInitializeIrpContext(PWMIP_IRP_CONTEXT IrpContext)302 WmipInitializeIrpContext(
303     PWMIP_IRP_CONTEXT IrpContext)
304 {
305     /* Initialize the list head for GUID objects */
306     InitializeListHead(&IrpContext->GuidObjectListHead);
307 }
308 
309 static
310 NTSTATUS
WmipReceiveNotifications(_Inout_ PIRP Irp,_In_ PVOID Buffer,_In_ ULONG InputLength,_Inout_ PULONG OutputLength)311 WmipReceiveNotifications(
312     _Inout_ PIRP Irp,
313     _In_ PVOID Buffer,
314     _In_ ULONG InputLength,
315     _Inout_ PULONG OutputLength)
316 {
317     PWMI_NOTIFICATION Notification;
318     PWMIP_IRP_CONTEXT IrpContext;
319     NTSTATUS Status;
320 
321     //__debugbreak();
322     if ((InputLength < sizeof(WMI_NOTIFICATION)) || (*OutputLength < 0x38))
323     {
324         return STATUS_INVALID_DEVICE_REQUEST;
325     }
326 
327     /// FIXME: For now we don't do any actual work, but simply pretend we are
328     /// waiting for notifications. We won't ever deliver any though.
329     Notification = (PWMI_NOTIFICATION)Buffer;
330     DBG_UNREFERENCED_LOCAL_VARIABLE(Notification);
331 
332     // loop all objects
333         // reference the object
334             // on failure, fail the whole request
335 
336     // loop all objects
337         // update the irp (synchronization!)
338             // if we had one before complete the old irp with an error
339 
340     /* Get the IRP context and initialize it */
341     IrpContext = (PWMIP_IRP_CONTEXT)Irp->Tail.Overlay.DriverContext;
342     WmipInitializeIrpContext(IrpContext);
343 
344     // loop all objects
345         // insert the objects into the IRP list
346 
347     /* Set our cancel routine for cleanup */
348     IoSetCancelRoutine(Irp, WmipNotificationIrpCancel);
349 
350     /* Check if the IRP is already being cancelled */
351     if (Irp->Cancel && IoSetCancelRoutine(Irp, NULL))
352     {
353         Status = STATUS_CANCELLED;
354     }
355     else
356     {
357         /* Mark the IRP as pending */
358         IoMarkIrpPending(Irp);
359         Status = STATUS_PENDING;
360     }
361 
362     return Status;
363 }
364 
365 typedef struct _WMI_OPEN_GUID_FOR_EVENTS
366 {
367     POBJECT_ATTRIBUTES ObjectAttributes;
368     ACCESS_MASK DesiredAccess;
369     ULONG Unknown08;
370     ULONG Unknown0C;
371 } WMI_OPEN_GUID_FOR_EVENTS, *PWMI_OPEN_GUID_FOR_EVENTS;
372 
373 typedef struct _WMIP_RESULT2
374 {
375     ULONG Unknown00;
376     ULONG Unknown04;
377     HANDLE Handle;
378     ULONG Unknown0C;
379 } WMIP_RESULT2, *PWMIP_RESULT2;
380 
381 static
382 NTSTATUS
WmipOpenGuidForEvents(PVOID Buffer,ULONG InputLength,PULONG OutputLength)383 WmipOpenGuidForEvents(
384     PVOID Buffer,
385     ULONG InputLength,
386     PULONG OutputLength)
387 {
388     PWMI_OPEN_GUID_FOR_EVENTS OpenGuidForEvents = Buffer;
389     PWMIP_RESULT2 Result = (PWMIP_RESULT2)Buffer;
390     OBJECT_ATTRIBUTES LocalObjectAttributes;
391     UNICODE_STRING LocalObjectName;
392     WCHAR LocalObjectNameBuffer[45 + 1];
393     KPROCESSOR_MODE PreviousMode;
394     HANDLE GuidObjectHandle;
395     PVOID GuidObject;
396     NTSTATUS Status;
397 
398     if ((InputLength != sizeof(WMI_OPEN_GUID_FOR_EVENTS)) ||
399         (*OutputLength != sizeof(WMIP_RESULT2)))
400     {
401         return STATUS_UNSUCCESSFUL;
402     }
403 
404     /* Capture object attributes */
405     PreviousMode = ExGetPreviousMode();
406     Status = WmipCaptureGuidObjectAttributes(OpenGuidForEvents->ObjectAttributes,
407                                              &LocalObjectAttributes,
408                                              &LocalObjectName,
409                                              LocalObjectNameBuffer,
410                                              PreviousMode);
411     if (!NT_SUCCESS(Status))
412     {
413         DPRINT1("ProbeAndCaptureGuidObjectAttributes failed: 0x%lx\n", Status);
414         return Status;
415     }
416 
417     /* Open a new GUID object */
418     Status = WmipOpenGuidObjectByName(&LocalObjectAttributes,
419                                       OpenGuidForEvents->DesiredAccess,
420                                       PreviousMode,
421                                       &GuidObjectHandle,
422                                       &GuidObject);
423     if (!NT_SUCCESS(Status))
424     {
425         DPRINT1("WmipOpenGuidObjectByName failed: 0x%lx\n", Status);
426         return Status;
427     }
428 
429     Result->Handle = GuidObjectHandle;
430 
431     ObDereferenceObject(GuidObject);
432 
433     return STATUS_SUCCESS;
434 }
435 
436 static
437 NTSTATUS
WmiSetMark(PWMI_SET_MARK Buffer,ULONG Length)438 WmiSetMark(
439     PWMI_SET_MARK Buffer,
440     ULONG Length)
441 {
442     UNIMPLEMENTED;
443     return STATUS_SUCCESS;
444 }
445 
446 NTSTATUS
447 NTAPI
WmipIoControl(_In_ PDEVICE_OBJECT DeviceObject,_Inout_ PIRP Irp)448 WmipIoControl(
449     _In_ PDEVICE_OBJECT DeviceObject,
450     _Inout_ PIRP Irp)
451 {
452     PIO_STACK_LOCATION IoStackLocation;
453     ULONG IoControlCode;
454     PVOID Buffer;
455     ULONG InputLength, OutputLength;
456     NTSTATUS Status;
457     PAGED_CODE();
458 
459     /* Get the current stack location */
460     IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
461 
462     /* Get the io control parameters */
463     IoControlCode = IoStackLocation->Parameters.DeviceIoControl.IoControlCode;
464     Buffer = Irp->AssociatedIrp.SystemBuffer;
465     InputLength = IoStackLocation->Parameters.DeviceIoControl.InputBufferLength;
466     OutputLength = IoStackLocation->Parameters.DeviceIoControl.OutputBufferLength;
467 
468     switch (IoControlCode)
469     {
470 
471         case IOCTL_WMI_REGISTER_GUIDS:
472         {
473             Status = WmipRegisterGuids(DeviceObject,
474                                        Buffer,
475                                        InputLength,
476                                        &OutputLength);
477             break;
478         }
479 
480         case IOCTL_WMI_UNREGISTER_GUIDS:
481         {
482             Status = WmipUnregisterGuids(Buffer,
483                                          InputLength,
484                                          &OutputLength);
485             break;
486         }
487 
488         case IOCTL_WMI_RECEIVE_NOTIFICATIONS:
489         {
490             Status = WmipReceiveNotifications(Irp,
491                                               Buffer,
492                                               InputLength,
493                                               &OutputLength);
494             break;
495         }
496 
497         case 0x228168:
498         {
499             DPRINT1("IOCTL 0x228168 is unimplemented, ignoring\n");
500             Status = STATUS_SUCCESS;
501             break;
502         }
503 
504         case IOCTL_WMI_OPEN_GUID_FOR_EVENTS:
505         {
506             Status = WmipOpenGuidForEvents(Buffer, InputLength, &OutputLength);
507             break;
508         }
509 
510         case IOCTL_WMI_SET_MARK:
511         {
512             if (InputLength < FIELD_OFFSET(WMI_SET_MARK, Mark))
513             {
514                 Status = STATUS_UNSUCCESSFUL;
515                 break;
516             }
517 
518             Status = WmiSetMark(Buffer, InputLength);
519             break;
520         }
521 
522         default:
523             DPRINT1("Unsupported yet IOCTL: 0x%lx\n", IoControlCode);
524             Status = STATUS_INVALID_DEVICE_REQUEST;
525             __debugbreak();
526             break;
527     }
528 
529     if (Status == STATUS_PENDING)
530         return Status;
531 
532     Irp->IoStatus.Status = Status;
533     Irp->IoStatus.Information = NT_SUCCESS(Status) ? OutputLength : 0;
534 
535     IoCompleteRequest(Irp, IO_NO_INCREMENT);
536     return Status;
537 }
538 
539 NTSTATUS
540 NTAPI
WmipSystemControl(_Inout_ PDEVICE_OBJECT DeviceObject,_Inout_ PIRP Irp)541 WmipSystemControl(
542   _Inout_  PDEVICE_OBJECT DeviceObject,
543   _Inout_  PIRP Irp)
544 {
545     UNIMPLEMENTED_DBGBREAK();
546     return STATUS_NOT_IMPLEMENTED;
547 }
548 
549 NTSTATUS
550 NTAPI
WmipShutdown(_Inout_ PDEVICE_OBJECT DeviceObject,_Inout_ PIRP Irp)551 WmipShutdown(
552   _Inout_  PDEVICE_OBJECT DeviceObject,
553   _Inout_  PIRP Irp)
554 {
555     Irp->IoStatus.Status = STATUS_SUCCESS;
556     IoCompleteRequest(Irp, IO_NO_INCREMENT);
557     return STATUS_SUCCESS;
558 }
559 
_Function_class_(FAST_IO_DEVICE_CONTROL)560 _Function_class_(FAST_IO_DEVICE_CONTROL)
561 _IRQL_requires_same_
562 BOOLEAN
563 NTAPI
564 WmipFastIoDeviceControl(
565     _In_ PFILE_OBJECT FileObject,
566     _In_ BOOLEAN Wait,
567     _In_opt_ PVOID InputBuffer,
568     _In_ ULONG InputBufferLength,
569     _Out_opt_ PVOID OutputBuffer,
570     _In_ ULONG OutputBufferLength,
571     _In_ ULONG IoControlCode,
572     _Out_ PIO_STATUS_BLOCK IoStatus,
573     _In_ PDEVICE_OBJECT DeviceObject)
574 {
575     PAGED_CODE();
576 
577     if (IoControlCode == IOCTL_WMI_TRACE_EVENT)
578     {
579         if (InputBufferLength < 0x30)
580         {
581             DPRINT1("Buffer too small\n");
582             return FALSE;
583         }
584 
585         IoStatus->Status = WmiTraceEvent(InputBuffer, ExGetPreviousMode());
586         return TRUE;
587     }
588     else if (IoControlCode == IOCTL_WMI_TRACE_USER_MESSAGE)
589     {
590         if (InputBufferLength < 0x30)
591         {
592             DPRINT1("Buffer too small\n");
593             return FALSE;
594         }
595 
596         IoStatus->Status = WmiTraceUserMessage(InputBuffer, InputBufferLength);
597         return TRUE;
598     }
599 
600     DPRINT1("Invalid io control code for fast dispatch: 0x%lx\n", IoControlCode);
601     return FALSE;
602 }
603 
604 NTSTATUS
605 NTAPI
WmipDockUndockEventCallback(_In_ PVOID NotificationStructure,_Inout_opt_ PVOID Context)606 WmipDockUndockEventCallback(
607     _In_ PVOID NotificationStructure,
608     _Inout_opt_ PVOID Context)
609 {
610     UNIMPLEMENTED_DBGBREAK();
611     return STATUS_NOT_IMPLEMENTED;
612 }
613 
_Function_class_(DRIVER_INITIALIZE)614 _Function_class_(DRIVER_INITIALIZE)
615 _IRQL_requires_same_
616 NTSTATUS
617 NTAPI
618 WmipDriverEntry(
619     _In_ PDRIVER_OBJECT DriverObject,
620     _In_ PUNICODE_STRING RegistryPath)
621 {
622     static UNICODE_STRING ServiceDeviceName = RTL_CONSTANT_STRING(L"\\Device\\WMIDataDevice");
623     static UNICODE_STRING ServiceDosDeviceName = RTL_CONSTANT_STRING(L"\\DosDevices\\WMIDataDevice");
624     static UNICODE_STRING AdminDeviceName = RTL_CONSTANT_STRING(L"\\Device\\WMIAdminDevice");
625     static UNICODE_STRING AdminDosDeviceName = RTL_CONSTANT_STRING(L"\\DosDevices\\WMIAdminDevice");
626     NTSTATUS Status;
627     PAGED_CODE();
628 
629     /* Create the service device object */
630     Status = IoCreateDevice(DriverObject,
631                             0,
632                             &ServiceDeviceName,
633                             FILE_DEVICE_UNKNOWN,
634                             FILE_DEVICE_SECURE_OPEN,
635                             0,
636                             &WmipServiceDeviceObject);
637     if (!NT_SUCCESS(Status))
638     {
639         DPRINT1("Failed to create service device: 0x%lx\n", Status);
640         return Status;
641     }
642 
643     /* Create a symbolic link for the service device */
644     Status = IoCreateSymbolicLink(&ServiceDosDeviceName, &ServiceDeviceName);
645     if (!NT_SUCCESS(Status))
646     {
647         DPRINT1("IoCreateSymbolicLink() failed: 0x%lx\n", Status);
648         IoDeleteDevice(WmipServiceDeviceObject);
649         return Status;
650     }
651 
652     /* Create the admin device object */
653     Status = IoCreateDevice(DriverObject,
654                             0,
655                             &AdminDeviceName,
656                             FILE_DEVICE_UNKNOWN,
657                             FILE_DEVICE_SECURE_OPEN,
658                             0,
659                             &WmipAdminDeviceObject);
660     if (!NT_SUCCESS(Status))
661     {
662         DPRINT1("Failed to create admin device: 0x%lx\n", Status);
663         IoDeleteDevice(WmipServiceDeviceObject);
664         IoDeleteSymbolicLink(&ServiceDosDeviceName);
665         return Status;
666     }
667 
668     /* Create a symbolic link for the admin device */
669     Status = IoCreateSymbolicLink(&AdminDosDeviceName, &AdminDeviceName);
670     if (!NT_SUCCESS(Status))
671     {
672         DPRINT1("IoCreateSymbolicLink() failed: 0x%lx\n", Status);
673         IoDeleteSymbolicLink(&ServiceDosDeviceName);
674         IoDeleteDevice(WmipServiceDeviceObject);
675         IoDeleteDevice(WmipAdminDeviceObject);
676         return Status;
677     }
678 
679     /* Initialize dispatch routines */
680     DriverObject->MajorFunction[IRP_MJ_CREATE] = WmipOpenCloseCleanup;
681     DriverObject->MajorFunction[IRP_MJ_CLOSE] = WmipOpenCloseCleanup;
682     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = WmipIoControl;
683     DriverObject->MajorFunction[IRP_MJ_CLEANUP] = WmipOpenCloseCleanup;
684     DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = WmipSystemControl;
685     DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = WmipShutdown;
686 
687     /* Initialize fast dispatch */
688     RtlZeroMemory(&WmipFastIoDispatch, sizeof(WmipFastIoDispatch));
689     WmipFastIoDispatch.SizeOfFastIoDispatch = sizeof(WmipFastIoDispatch);
690     WmipFastIoDispatch.FastIoDeviceControl = WmipFastIoDeviceControl;
691     DriverObject->FastIoDispatch = &WmipFastIoDispatch;
692 
693     /* Register the WMI service device */
694     IoWMIRegistrationControl(WmipServiceDeviceObject, WMIREG_ACTION_REGISTER);
695 
696     /* Register a shutdown notification */
697     IoRegisterShutdownNotification(WmipServiceDeviceObject);
698 
699     /* Initialization is done */
700     WmipServiceDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
701     WmipAdminDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
702 
703     return STATUS_SUCCESS;
704 }
705 
706 
707