[ntoskrnl] Never suppose that buffer in UNICODE_STRING is null terminated. Fixes...
[reactos.git] / reactos / ntoskrnl / io / iomgr / driver.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/iomgr/driver.c
5 * PURPOSE: Driver Object Management
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Filip Navara (navaraf@reactos.org)
8 * Hervé Poussineau (hpoussin@reactos.org)
9 */
10
11 /* INCLUDES *******************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16
17 /* GLOBALS ********************************************************************/
18
19 LIST_ENTRY DriverReinitListHead;
20 KSPIN_LOCK DriverReinitListLock;
21 PLIST_ENTRY DriverReinitTailEntry;
22
23 PLIST_ENTRY DriverBootReinitTailEntry;
24 LIST_ENTRY DriverBootReinitListHead;
25 KSPIN_LOCK DriverBootReinitListLock;
26
27 UNICODE_STRING IopHardwareDatabaseKey =
28 RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\SYSTEM");
29
30 POBJECT_TYPE IoDriverObjectType = NULL;
31
32 #define TAG_RTLREGISTRY 'vrqR'
33
34 extern BOOLEAN ExpInTextModeSetup;
35 extern BOOLEAN PnpSystemInit;
36
37 /* PRIVATE FUNCTIONS **********************************************************/
38
39 NTSTATUS NTAPI
40 IopInvalidDeviceRequest(
41 PDEVICE_OBJECT DeviceObject,
42 PIRP Irp)
43 {
44 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
45 Irp->IoStatus.Information = 0;
46 IoCompleteRequest(Irp, IO_NO_INCREMENT);
47 return STATUS_INVALID_DEVICE_REQUEST;
48 }
49
50 VOID
51 NTAPI
52 IopDeleteDriver(IN PVOID ObjectBody)
53 {
54 PDRIVER_OBJECT DriverObject = ObjectBody;
55 PIO_CLIENT_EXTENSION DriverExtension, NextDriverExtension;
56 PAGED_CODE();
57
58 /* Get the extension and loop them */
59 DriverExtension = IoGetDrvObjExtension(DriverObject)->
60 ClientDriverExtension;
61 while (DriverExtension)
62 {
63 /* Get the next one */
64 NextDriverExtension = DriverExtension->NextExtension;
65 ExFreePoolWithTag(DriverExtension, TAG_DRIVER_EXTENSION);
66
67 /* Move on */
68 DriverExtension = NextDriverExtension;
69 }
70
71 /* Check if the driver image is still loaded */
72 if (DriverObject->DriverSection)
73 {
74 /* Unload it */
75 MmUnloadSystemImage(DriverObject->DriverSection);
76 }
77
78 /* Check if it has a name */
79 if (DriverObject->DriverName.Buffer)
80 {
81 /* Free it */
82 ExFreePool(DriverObject->DriverName.Buffer);
83 }
84
85 #if 0 /* See a bit of hack in IopCreateDriver */
86 /* Check if it has a service key name */
87 if (DriverObject->DriverExtension->ServiceKeyName.Buffer)
88 {
89 /* Free it */
90 ExFreePool(DriverObject->DriverExtension->ServiceKeyName.Buffer);
91 }
92 #endif
93 }
94
95 NTSTATUS FASTCALL
96 IopGetDriverObject(
97 PDRIVER_OBJECT *DriverObject,
98 PUNICODE_STRING ServiceName,
99 BOOLEAN FileSystem)
100 {
101 PDRIVER_OBJECT Object;
102 WCHAR NameBuffer[MAX_PATH];
103 UNICODE_STRING DriverName;
104 NTSTATUS Status;
105
106 DPRINT("IopGetDriverObject(%p '%wZ' %x)\n",
107 DriverObject, ServiceName, FileSystem);
108
109 *DriverObject = NULL;
110
111 /* Create ModuleName string */
112 if (ServiceName == NULL || ServiceName->Buffer == NULL)
113 /* We don't know which DriverObject we have to open */
114 return STATUS_INVALID_PARAMETER_2;
115
116 DriverName.Buffer = NameBuffer;
117 DriverName.Length = 0;
118 DriverName.MaximumLength = sizeof(NameBuffer);
119
120 if (FileSystem == TRUE)
121 RtlAppendUnicodeToString(&DriverName, FILESYSTEM_ROOT_NAME);
122 else
123 RtlAppendUnicodeToString(&DriverName, DRIVER_ROOT_NAME);
124 RtlAppendUnicodeStringToString(&DriverName, ServiceName);
125
126 DPRINT("Driver name: '%wZ'\n", &DriverName);
127
128 /* Open driver object */
129 Status = ObReferenceObjectByName(
130 &DriverName,
131 OBJ_OPENIF | OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, /* Attributes */
132 NULL, /* PassedAccessState */
133 0, /* DesiredAccess */
134 IoDriverObjectType,
135 KernelMode,
136 NULL, /* ParseContext */
137 (PVOID*)&Object);
138
139 if (!NT_SUCCESS(Status))
140 {
141 DPRINT("Failed to reference driver object, status=0x%08x\n", Status);
142 return Status;
143 }
144
145 *DriverObject = Object;
146
147 DPRINT("Driver Object: %p\n", Object);
148
149 return STATUS_SUCCESS;
150 }
151
152 /*
153 * IopDisplayLoadingMessage
154 *
155 * Display 'Loading XXX...' message.
156 */
157
158 VOID
159 FASTCALL
160 INIT_FUNCTION
161 IopDisplayLoadingMessage(PUNICODE_STRING ServiceName)
162 {
163 CHAR TextBuffer[256];
164
165 if (ExpInTextModeSetup) return;
166 RtlUpcaseUnicodeString(ServiceName, ServiceName, FALSE);
167 snprintf(TextBuffer, sizeof(TextBuffer),
168 "%s%s%s\\%wZ",
169 KeLoaderBlock->ArcBootDeviceName,
170 KeLoaderBlock->NtBootPathName,
171 "System32\\Drivers",
172 ServiceName);
173 if (!strstr(TextBuffer, ".sys"))
174 strcat(TextBuffer, ".sys\n");
175 else
176 strcat(TextBuffer, "\n");
177 HalDisplayString(TextBuffer);
178 }
179
180 /*
181 * IopNormalizeImagePath
182 *
183 * Normalize an image path to contain complete path.
184 *
185 * Parameters
186 * ImagePath
187 * The input path and on exit the result path. ImagePath.Buffer
188 * must be allocated by ExAllocatePool on input. Caller is responsible
189 * for freeing the buffer when it's no longer needed.
190 *
191 * ServiceName
192 * Name of the service that ImagePath belongs to.
193 *
194 * Return Value
195 * Status
196 *
197 * Remarks
198 * The input image path isn't freed on error.
199 */
200
201 NTSTATUS FASTCALL
202 IopNormalizeImagePath(
203 IN OUT PUNICODE_STRING ImagePath,
204 IN PUNICODE_STRING ServiceName)
205 {
206 UNICODE_STRING InputImagePath;
207
208 RtlCopyMemory(
209 &InputImagePath,
210 ImagePath,
211 sizeof(UNICODE_STRING));
212
213 if (InputImagePath.Length == 0)
214 {
215 ImagePath->Length = 0;
216 ImagePath->MaximumLength =
217 (33 * sizeof(WCHAR)) + ServiceName->Length + sizeof(UNICODE_NULL);
218 ImagePath->Buffer = ExAllocatePool(NonPagedPool, ImagePath->MaximumLength);
219 if (ImagePath->Buffer == NULL)
220 return STATUS_NO_MEMORY;
221
222 RtlAppendUnicodeToString(ImagePath, L"\\SystemRoot\\system32\\drivers\\");
223 RtlAppendUnicodeStringToString(ImagePath, ServiceName);
224 RtlAppendUnicodeToString(ImagePath, L".sys");
225 } else
226 if (InputImagePath.Buffer[0] != L'\\')
227 {
228 ImagePath->Length = 0;
229 ImagePath->MaximumLength =
230 12 * sizeof(WCHAR) + InputImagePath.Length + sizeof(UNICODE_NULL);
231 ImagePath->Buffer = ExAllocatePool(NonPagedPool, ImagePath->MaximumLength);
232 if (ImagePath->Buffer == NULL)
233 return STATUS_NO_MEMORY;
234
235 RtlAppendUnicodeToString(ImagePath, L"\\SystemRoot\\");
236 RtlAppendUnicodeStringToString(ImagePath, &InputImagePath);
237
238 /* Free caller's string */
239 ExFreePoolWithTag(InputImagePath.Buffer, TAG_RTLREGISTRY);
240 }
241
242 return STATUS_SUCCESS;
243 }
244
245 /*
246 * IopLoadServiceModule
247 *
248 * Load a module specified by registry settings for service.
249 *
250 * Parameters
251 * ServiceName
252 * Name of the service to load.
253 *
254 * Return Value
255 * Status
256 */
257
258 NTSTATUS FASTCALL
259 IopLoadServiceModule(
260 IN PUNICODE_STRING ServiceName,
261 OUT PLDR_DATA_TABLE_ENTRY *ModuleObject)
262 {
263 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
264 ULONG ServiceStart;
265 UNICODE_STRING ServiceImagePath, CCSName;
266 NTSTATUS Status;
267 HANDLE CCSKey, ServiceKey;
268 PVOID BaseAddress;
269
270 DPRINT("IopLoadServiceModule(%wZ, 0x%p)\n", ServiceName, ModuleObject);
271
272 /* FIXME: This check may be removed once the bug is fixed */
273 if (ServiceName->Buffer == NULL)
274 {
275 DPRINT1("If you see this, please report to Fireball or hpoussin!\n");
276 return STATUS_UNSUCCESSFUL;
277 }
278
279 /* Open CurrentControlSet */
280 RtlInitUnicodeString(&CCSName,
281 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services");
282 Status = IopOpenRegistryKeyEx(&CCSKey, NULL, &CCSName, KEY_READ);
283 if (!NT_SUCCESS(Status))
284 {
285 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
286 return Status;
287 }
288
289 /* Open service key */
290 Status = IopOpenRegistryKeyEx(&ServiceKey, CCSKey, ServiceName, KEY_READ);
291 if (!NT_SUCCESS(Status))
292 {
293 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
294 ZwClose(CCSKey);
295 return Status;
296 }
297
298 /*
299 * Get information about the service.
300 */
301
302 RtlZeroMemory(QueryTable, sizeof(QueryTable));
303
304 RtlInitUnicodeString(&ServiceImagePath, NULL);
305
306 QueryTable[0].Name = L"Start";
307 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
308 QueryTable[0].EntryContext = &ServiceStart;
309
310 QueryTable[1].Name = L"ImagePath";
311 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
312 QueryTable[1].EntryContext = &ServiceImagePath;
313
314 Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
315 (PWSTR)ServiceKey, QueryTable, NULL, NULL);
316
317 ZwClose(ServiceKey);
318 ZwClose(CCSKey);
319
320 if (!NT_SUCCESS(Status))
321 {
322 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status);
323 return Status;
324 }
325
326 /*
327 * Normalize the image path for all later processing.
328 */
329
330 Status = IopNormalizeImagePath(&ServiceImagePath, ServiceName);
331
332 if (!NT_SUCCESS(Status))
333 {
334 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
335 return Status;
336 }
337
338 /*
339 * Case for disabled drivers
340 */
341
342 if (ServiceStart >= 4)
343 {
344 /* FIXME: Check if it is the right status code */
345 Status = STATUS_PLUGPLAY_NO_DEVICE;
346 }
347 else
348 {
349 DPRINT("Loading module\n");
350 Status = MmLoadSystemImage(&ServiceImagePath, NULL, NULL, 0, (PVOID)ModuleObject, &BaseAddress);
351 }
352
353 ExFreePool(ServiceImagePath.Buffer);
354
355 /*
356 * Now check if the module was loaded successfully.
357 */
358
359 if (!NT_SUCCESS(Status))
360 {
361 DPRINT("Module loading failed (Status %x)\n", Status);
362 }
363
364 DPRINT("Module loading (Status %x)\n", Status);
365
366 return Status;
367 }
368
369 /*
370 * IopInitializeDriverModule
371 *
372 * Initalize a loaded driver.
373 *
374 * Parameters
375 * DeviceNode
376 * Pointer to device node.
377 *
378 * ModuleObject
379 * Module object representing the driver. It can be retrieve by
380 * IopLoadServiceModule.
381 *
382 * ServiceName
383 * Name of the service (as in registry).
384 *
385 * FileSystemDriver
386 * Set to TRUE for file system drivers.
387 *
388 * DriverObject
389 * On successful return this contains the driver object representing
390 * the loaded driver.
391 */
392
393 NTSTATUS FASTCALL
394 IopInitializeDriverModule(
395 IN PDEVICE_NODE DeviceNode,
396 IN PLDR_DATA_TABLE_ENTRY ModuleObject,
397 IN PUNICODE_STRING ServiceName,
398 IN BOOLEAN FileSystemDriver,
399 OUT PDRIVER_OBJECT *DriverObject)
400 {
401 const WCHAR ServicesKeyName[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
402 WCHAR NameBuffer[MAX_PATH];
403 UNICODE_STRING DriverName;
404 UNICODE_STRING RegistryKey;
405 PDRIVER_INITIALIZE DriverEntry;
406 PDRIVER_OBJECT Driver;
407 PDEVICE_OBJECT DeviceObject;
408 NTSTATUS Status;
409
410 DriverEntry = ModuleObject->EntryPoint;
411
412 if (ServiceName != NULL && ServiceName->Length != 0)
413 {
414 RegistryKey.Length = 0;
415 RegistryKey.MaximumLength = sizeof(ServicesKeyName) + ServiceName->Length;
416 RegistryKey.Buffer = ExAllocatePool(PagedPool, RegistryKey.MaximumLength);
417 if (RegistryKey.Buffer == NULL)
418 {
419 return STATUS_INSUFFICIENT_RESOURCES;
420 }
421 RtlAppendUnicodeToString(&RegistryKey, ServicesKeyName);
422 RtlAppendUnicodeStringToString(&RegistryKey, ServiceName);
423 }
424 else
425 {
426 RtlInitUnicodeString(&RegistryKey, NULL);
427 }
428
429 /* Create ModuleName string */
430 if (ServiceName && ServiceName->Length > 0)
431 {
432 if (FileSystemDriver == TRUE)
433 wcscpy(NameBuffer, FILESYSTEM_ROOT_NAME);
434 else
435 wcscpy(NameBuffer, DRIVER_ROOT_NAME);
436
437 RtlInitUnicodeString(&DriverName, NameBuffer);
438 DriverName.MaximumLength = sizeof(NameBuffer);
439
440 RtlAppendUnicodeStringToString(&DriverName, ServiceName);
441
442 DPRINT("Driver name: '%wZ'\n", &DriverName);
443 }
444 else
445 DriverName.Length = 0;
446
447 Status = IopCreateDriver(
448 DriverName.Length > 0 ? &DriverName : NULL,
449 DriverEntry,
450 &RegistryKey,
451 ModuleObject->DllBase,
452 ModuleObject->SizeOfImage,
453 &Driver);
454 RtlFreeUnicodeString(&RegistryKey);
455
456 *DriverObject = Driver;
457 if (!NT_SUCCESS(Status))
458 {
459 DPRINT("IopCreateDriver() failed (Status 0x%08lx)\n", Status);
460 return Status;
461 }
462
463 /* Set the driver as initialized */
464 Driver->Flags |= DRVO_INITIALIZED;
465 DeviceObject = Driver->DeviceObject;
466 while (DeviceObject)
467 {
468 /* Set every device as initialized too */
469 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
470 DeviceObject = DeviceObject->NextDevice;
471 }
472
473 if (PnpSystemInit) IopReinitializeDrivers();
474
475 return STATUS_SUCCESS;
476 }
477
478 /*
479 * IopAttachFilterDriversCallback
480 *
481 * Internal routine used by IopAttachFilterDrivers.
482 */
483
484 NTSTATUS NTAPI
485 IopAttachFilterDriversCallback(
486 PWSTR ValueName,
487 ULONG ValueType,
488 PVOID ValueData,
489 ULONG ValueLength,
490 PVOID Context,
491 PVOID EntryContext)
492 {
493 PDEVICE_NODE DeviceNode = Context;
494 UNICODE_STRING ServiceName;
495 PWCHAR Filters;
496 PLDR_DATA_TABLE_ENTRY ModuleObject;
497 PDRIVER_OBJECT DriverObject;
498 NTSTATUS Status;
499
500 for (Filters = ValueData;
501 ((ULONG_PTR)Filters - (ULONG_PTR)ValueData) < ValueLength &&
502 *Filters != 0;
503 Filters += (ServiceName.Length / sizeof(WCHAR)) + 1)
504 {
505 DPRINT("Filter Driver: %S (%wZ)\n", Filters, &DeviceNode->InstancePath);
506 ServiceName.Buffer = Filters;
507 ServiceName.MaximumLength =
508 ServiceName.Length = wcslen(Filters) * sizeof(WCHAR);
509
510 /* Load and initialize the filter driver */
511 Status = IopLoadServiceModule(&ServiceName, &ModuleObject);
512 if (Status != STATUS_IMAGE_ALREADY_LOADED)
513 {
514 if (!NT_SUCCESS(Status))
515 continue;
516
517 Status = IopInitializeDriverModule(DeviceNode, ModuleObject, &ServiceName,
518 FALSE, &DriverObject);
519 if (!NT_SUCCESS(Status))
520 continue;
521 }
522 else
523 {
524 /* get existing DriverObject pointer */
525 Status = IopGetDriverObject(
526 &DriverObject,
527 &ServiceName,
528 FALSE);
529 if (!NT_SUCCESS(Status))
530 {
531 DPRINT1("IopGetDriverObject() returned status 0x%08x!\n", Status);
532 continue;
533 }
534 }
535
536 Status = IopInitializeDevice(DeviceNode, DriverObject);
537 if (!NT_SUCCESS(Status))
538 continue;
539 }
540
541 return STATUS_SUCCESS;
542 }
543
544 /*
545 * IopAttachFilterDrivers
546 *
547 * Load filter drivers for specified device node.
548 *
549 * Parameters
550 * Lower
551 * Set to TRUE for loading lower level filters or FALSE for upper
552 * level filters.
553 */
554
555 NTSTATUS FASTCALL
556 IopAttachFilterDrivers(
557 PDEVICE_NODE DeviceNode,
558 BOOLEAN Lower)
559 {
560 RTL_QUERY_REGISTRY_TABLE QueryTable[2] = { { NULL, 0, NULL, NULL, 0, NULL, 0 }, };
561 UNICODE_STRING Class;
562 WCHAR ClassBuffer[40];
563 UNICODE_STRING EnumRoot = RTL_CONSTANT_STRING(ENUM_ROOT);
564 HANDLE EnumRootKey, SubKey;
565 NTSTATUS Status;
566
567 /* Open enumeration root key */
568 Status = IopOpenRegistryKeyEx(&EnumRootKey, NULL,
569 &EnumRoot, KEY_READ);
570 if (!NT_SUCCESS(Status))
571 {
572 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
573 return Status;
574 }
575
576 /* Open subkey */
577 Status = IopOpenRegistryKeyEx(&SubKey, EnumRootKey,
578 &DeviceNode->InstancePath, KEY_READ);
579 if (!NT_SUCCESS(Status))
580 {
581 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
582 ZwClose(EnumRootKey);
583 return Status;
584 }
585
586 /*
587 * First load the device filters
588 */
589 QueryTable[0].QueryRoutine = IopAttachFilterDriversCallback;
590 if (Lower)
591 QueryTable[0].Name = L"LowerFilters";
592 else
593 QueryTable[0].Name = L"UpperFilters";
594 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
595
596 RtlQueryRegistryValues(
597 RTL_REGISTRY_HANDLE,
598 (PWSTR)SubKey,
599 QueryTable,
600 DeviceNode,
601 NULL);
602
603 /*
604 * Now get the class GUID
605 */
606 Class.Length = 0;
607 Class.MaximumLength = 40 * sizeof(WCHAR);
608 Class.Buffer = ClassBuffer;
609 QueryTable[0].QueryRoutine = NULL;
610 QueryTable[0].Name = L"ClassGUID";
611 QueryTable[0].EntryContext = &Class;
612 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
613
614 Status = RtlQueryRegistryValues(
615 RTL_REGISTRY_HANDLE,
616 (PWSTR)SubKey,
617 QueryTable,
618 DeviceNode,
619 NULL);
620
621 /* Close handles */
622 ZwClose(SubKey);
623 ZwClose(EnumRootKey);
624
625 /*
626 * Load the class filter driver
627 */
628 if (NT_SUCCESS(Status))
629 {
630 UNICODE_STRING ControlClass = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class");
631
632 Status = IopOpenRegistryKeyEx(&EnumRootKey, NULL,
633 &ControlClass, KEY_READ);
634 if (!NT_SUCCESS(Status))
635 {
636 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
637 return Status;
638 }
639
640 /* Open subkey */
641 Status = IopOpenRegistryKeyEx(&SubKey, EnumRootKey,
642 &Class, KEY_READ);
643 if (!NT_SUCCESS(Status))
644 {
645 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
646 ZwClose(EnumRootKey);
647 return Status;
648 }
649
650 QueryTable[0].QueryRoutine = IopAttachFilterDriversCallback;
651 if (Lower)
652 QueryTable[0].Name = L"LowerFilters";
653 else
654 QueryTable[0].Name = L"UpperFilters";
655 QueryTable[0].EntryContext = NULL;
656 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
657
658 RtlQueryRegistryValues(
659 RTL_REGISTRY_HANDLE,
660 (PWSTR)SubKey,
661 QueryTable,
662 DeviceNode,
663 NULL);
664
665 /* Clean up */
666 ZwClose(SubKey);
667 ZwClose(EnumRootKey);
668 }
669
670 return STATUS_SUCCESS;
671 }
672
673 NTSTATUS
674 NTAPI
675 MiResolveImageReferences(IN PVOID ImageBase,
676 IN PUNICODE_STRING ImageFileDirectory,
677 IN PUNICODE_STRING NamePrefix OPTIONAL,
678 OUT PCHAR *MissingApi,
679 OUT PWCHAR *MissingDriver,
680 OUT PLOAD_IMPORTS *LoadImports);
681
682 //
683 // Used for images already loaded (boot drivers)
684 //
685 NTSTATUS
686 NTAPI
687 LdrProcessDriverModule(PLDR_DATA_TABLE_ENTRY LdrEntry,
688 PUNICODE_STRING FileName,
689 PLDR_DATA_TABLE_ENTRY *ModuleObject)
690 {
691 NTSTATUS Status;
692 PLDR_DATA_TABLE_ENTRY NewEntry;
693 UNICODE_STRING BaseName, BaseDirectory;
694 PLOAD_IMPORTS LoadedImports = (PVOID)-2;
695 PCHAR MissingApiName, Buffer;
696 PWCHAR MissingDriverName;
697 PVOID DriverBase = LdrEntry->DllBase;
698
699 /* Allocate a buffer we'll use for names */
700 Buffer = ExAllocatePoolWithTag(NonPagedPool, MAX_PATH, TAG_LDR_WSTR);
701 if (!Buffer)
702 {
703 /* Fail */
704 return STATUS_INSUFFICIENT_RESOURCES;
705 }
706
707 /* Check for a separator */
708 if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
709 {
710 PWCHAR p;
711 ULONG BaseLength;
712
713 /* Loop the path until we get to the base name */
714 p = &FileName->Buffer[FileName->Length / sizeof(WCHAR)];
715 while (*(p - 1) != OBJ_NAME_PATH_SEPARATOR) p--;
716
717 /* Get the length */
718 BaseLength = (ULONG)(&FileName->Buffer[FileName->Length / sizeof(WCHAR)] - p);
719 BaseLength *= sizeof(WCHAR);
720
721 /* Setup the string */
722 BaseName.Length = (USHORT)BaseLength;
723 BaseName.Buffer = p;
724 }
725 else
726 {
727 /* Otherwise, we already have a base name */
728 BaseName.Length = FileName->Length;
729 BaseName.Buffer = FileName->Buffer;
730 }
731
732 /* Setup the maximum length */
733 BaseName.MaximumLength = BaseName.Length;
734
735 /* Now compute the base directory */
736 BaseDirectory = *FileName;
737 BaseDirectory.Length -= BaseName.Length;
738 BaseDirectory.MaximumLength = BaseDirectory.Length;
739
740 NewEntry = LdrEntry;
741
742 /* Resolve imports */
743 MissingApiName = Buffer;
744 Status = MiResolveImageReferences(DriverBase,
745 &BaseDirectory,
746 NULL,
747 &MissingApiName,
748 &MissingDriverName,
749 &LoadedImports);
750 if (!NT_SUCCESS(Status)) return Status;
751
752 /* Return */
753 *ModuleObject = LdrEntry;
754 return STATUS_SUCCESS;
755 }
756
757 /*
758 * IopInitializeBuiltinDriver
759 *
760 * Initialize a driver that is already loaded in memory.
761 */
762
763 NTSTATUS
764 NTAPI
765 IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
766 {
767 PDEVICE_NODE DeviceNode;
768 PDRIVER_OBJECT DriverObject;
769 NTSTATUS Status;
770 PWCHAR FileNameWithoutPath;
771 LPWSTR FileExtension;
772 PUNICODE_STRING ModuleName = &LdrEntry->BaseDllName;
773 UNICODE_STRING ServiceName;
774
775 /*
776 * Display 'Loading XXX...' message
777 */
778 IopDisplayLoadingMessage(ModuleName);
779 InbvIndicateProgress();
780
781 /*
782 * Generate filename without path (not needed by freeldr)
783 */
784 FileNameWithoutPath = wcsrchr(ModuleName->Buffer, L'\\');
785 if (FileNameWithoutPath == NULL)
786 {
787 FileNameWithoutPath = ModuleName->Buffer;
788 }
789 else
790 {
791 FileNameWithoutPath++;
792 }
793
794 /*
795 * Strip the file extension from ServiceName
796 */
797 RtlCreateUnicodeString(&ServiceName, FileNameWithoutPath);
798 FileExtension = wcsrchr(ServiceName.Buffer, '.');
799 if (FileExtension != NULL)
800 {
801 ServiceName.Length -= wcslen(FileExtension) * sizeof(WCHAR);
802 FileExtension[0] = 0;
803 }
804
805 /*
806 * Determine the right device object
807 */
808 /* Use IopRootDeviceNode for now */
809 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &ServiceName, &DeviceNode);
810 if (!NT_SUCCESS(Status))
811 {
812 DPRINT1("Driver '%wZ' load failed, status (%x)\n", ModuleName, Status);
813 return(Status);
814 }
815 DeviceNode->ServiceName = ServiceName;
816
817 /*
818 * Initialize the driver
819 */
820 Status = IopInitializeDriverModule(DeviceNode, LdrEntry,
821 &DeviceNode->ServiceName, FALSE, &DriverObject);
822
823 if (!NT_SUCCESS(Status))
824 {
825 IopFreeDeviceNode(DeviceNode);
826 return Status;
827 }
828
829 Status = IopInitializeDevice(DeviceNode, DriverObject);
830 if (NT_SUCCESS(Status))
831 {
832 Status = IopStartDevice(DeviceNode);
833 }
834
835 return Status;
836 }
837
838 /*
839 * IopInitializeBootDrivers
840 *
841 * Initialize boot drivers and free memory for boot files.
842 *
843 * Parameters
844 * None
845 *
846 * Return Value
847 * None
848 */
849 VOID
850 FASTCALL
851 IopInitializeBootDrivers(VOID)
852 {
853 PLIST_ENTRY ListHead, NextEntry;
854 PLDR_DATA_TABLE_ENTRY LdrEntry;
855 PDEVICE_NODE DeviceNode;
856 PDRIVER_OBJECT DriverObject;
857 LDR_DATA_TABLE_ENTRY ModuleObject;
858 NTSTATUS Status;
859 UNICODE_STRING DriverName;
860
861 DPRINT("IopInitializeBootDrivers()\n");
862
863 /* Use IopRootDeviceNode for now */
864 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, NULL, &DeviceNode);
865 if (!NT_SUCCESS(Status)) return;
866
867 /* Setup the module object for the RAW FS Driver */
868 ModuleObject.DllBase = NULL;
869 ModuleObject.SizeOfImage = 0;
870 ModuleObject.EntryPoint = RawFsDriverEntry;
871 RtlInitUnicodeString(&DriverName, L"RAW");
872
873 /* Initialize it */
874 Status = IopInitializeDriverModule(DeviceNode,
875 &ModuleObject,
876 &DriverName,
877 TRUE,
878 &DriverObject);
879 if (!NT_SUCCESS(Status))
880 {
881 /* Fail */
882 IopFreeDeviceNode(DeviceNode);
883 return;
884 }
885
886 /* Now initialize the associated device */
887 Status = IopInitializeDevice(DeviceNode, DriverObject);
888 if (!NT_SUCCESS(Status))
889 {
890 /* Fail */
891 IopFreeDeviceNode(DeviceNode);
892 return;
893 }
894
895 /* Start it up */
896 Status = IopStartDevice(DeviceNode);
897 if (!NT_SUCCESS(Status))
898 {
899 /* Fail */
900 IopFreeDeviceNode(DeviceNode);
901 return;
902 }
903
904 /* Loop the boot modules */
905 ListHead = &KeLoaderBlock->LoadOrderListHead;
906 NextEntry = ListHead->Flink;
907 while (ListHead != NextEntry)
908 {
909 /* Get the entry */
910 LdrEntry = CONTAINING_RECORD(NextEntry,
911 LDR_DATA_TABLE_ENTRY,
912 InLoadOrderLinks);
913
914 /*
915 * HACK: Make sure we're loading a driver
916 * (we should be using BootDriverListHead!)
917 */
918 if (wcsstr(_wcsupr(LdrEntry->BaseDllName.Buffer), L".SYS"))
919 {
920 /* Make sure we didn't load this driver already */
921 if (!(LdrEntry->Flags & LDRP_ENTRY_INSERTED))
922 {
923 DPRINT("Initializing bootdriver %wZ\n", &LdrEntry->BaseDllName);
924 /* Initialize it */
925 IopInitializeBuiltinDriver(LdrEntry);
926 }
927 }
928
929 /* Go to the next driver */
930 NextEntry = NextEntry->Flink;
931 }
932
933 /* In old ROS, the loader list became empty after this point. Simulate. */
934 InitializeListHead(&KeLoaderBlock->LoadOrderListHead);
935 }
936
937 /*
938 * IopUnloadDriver
939 *
940 * Unloads a device driver.
941 *
942 * Parameters
943 * DriverServiceName
944 * Name of the service to unload (registry key).
945 *
946 * UnloadPnpDrivers
947 * Whether to unload Plug & Plug or only legacy drivers. If this
948 * parameter is set to FALSE, the routine will unload only legacy
949 * drivers.
950 *
951 * Return Value
952 * Status
953 *
954 * To do
955 * Guard the whole function by SEH.
956 */
957
958 NTSTATUS NTAPI
959 IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
960 {
961 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
962 UNICODE_STRING ImagePath;
963 UNICODE_STRING ServiceName;
964 UNICODE_STRING ObjectName;
965 PDRIVER_OBJECT DriverObject;
966 PDEVICE_OBJECT DeviceObject;
967 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
968 LOAD_UNLOAD_PARAMS LoadParams;
969 NTSTATUS Status;
970 LPWSTR Start;
971 BOOLEAN SafeToUnload = TRUE;
972
973 DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName, UnloadPnpDrivers);
974
975 PAGED_CODE();
976
977 /*
978 * Get the service name from the registry key name
979 */
980
981 Start = wcsrchr(DriverServiceName->Buffer, L'\\');
982 if (Start == NULL)
983 Start = DriverServiceName->Buffer;
984 else
985 Start++;
986
987 RtlInitUnicodeString(&ServiceName, Start);
988
989 /*
990 * Construct the driver object name
991 */
992
993 ObjectName.Length = (wcslen(Start) + 8) * sizeof(WCHAR);
994 ObjectName.MaximumLength = ObjectName.Length + sizeof(WCHAR);
995 ObjectName.Buffer = ExAllocatePool(PagedPool, ObjectName.MaximumLength);
996 if (!ObjectName.Buffer) return STATUS_INSUFFICIENT_RESOURCES;
997 wcscpy(ObjectName.Buffer, L"\\Driver\\");
998 memcpy(ObjectName.Buffer + 8, Start, ObjectName.Length - 8 * sizeof(WCHAR));
999 ObjectName.Buffer[ObjectName.Length/sizeof(WCHAR)] = 0;
1000
1001 /*
1002 * Find the driver object
1003 */
1004 Status = ObReferenceObjectByName(&ObjectName,
1005 0,
1006 0,
1007 0,
1008 IoDriverObjectType,
1009 KernelMode,
1010 0,
1011 (PVOID*)&DriverObject);
1012
1013 /*
1014 * Free the buffer for driver object name
1015 */
1016 ExFreePool(ObjectName.Buffer);
1017
1018 if (!NT_SUCCESS(Status))
1019 {
1020 DPRINT1("Can't locate driver object for %wZ\n", &ObjectName);
1021 return Status;
1022 }
1023
1024 /* Check that driver is not already unloading */
1025 if (DriverObject->Flags & DRVO_UNLOAD_INVOKED)
1026 {
1027 DPRINT1("Driver deletion pending\n");
1028 ObDereferenceObject(DriverObject);
1029 return STATUS_DELETE_PENDING;
1030 }
1031
1032 /*
1033 * Get path of service...
1034 */
1035
1036 RtlZeroMemory(QueryTable, sizeof(QueryTable));
1037
1038 RtlInitUnicodeString(&ImagePath, NULL);
1039
1040 QueryTable[0].Name = L"ImagePath";
1041 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
1042 QueryTable[0].EntryContext = &ImagePath;
1043
1044 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1045 DriverServiceName->Buffer, QueryTable, NULL, NULL);
1046
1047 if (!NT_SUCCESS(Status))
1048 {
1049 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status);
1050 ObDereferenceObject(DriverObject);
1051 return Status;
1052 }
1053
1054 /*
1055 * Normalize the image path for all later processing.
1056 */
1057
1058 Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
1059
1060 if (!NT_SUCCESS(Status))
1061 {
1062 DPRINT1("IopNormalizeImagePath() failed (Status %x)\n", Status);
1063 ObDereferenceObject(DriverObject);
1064 return Status;
1065 }
1066
1067 /*
1068 * Free the service path
1069 */
1070
1071 ExFreePool(ImagePath.Buffer);
1072
1073 /*
1074 * Unload the module and release the references to the device object
1075 */
1076
1077 /* Call the load/unload routine, depending on current process */
1078 if (DriverObject->DriverUnload && DriverObject->DriverSection)
1079 {
1080 /* Loop through each device object of the driver
1081 and set DOE_UNLOAD_PENDING flag */
1082 DeviceObject = DriverObject->DeviceObject;
1083 while (DeviceObject)
1084 {
1085 /* Set the unload pending flag for the device */
1086 DeviceExtension = IoGetDevObjExtension(DeviceObject);
1087 DeviceExtension->ExtensionFlags |= DOE_UNLOAD_PENDING;
1088
1089 /* Make sure there are no attached devices or no reference counts */
1090 if ((DeviceObject->ReferenceCount) || (DeviceObject->AttachedDevice))
1091 {
1092 /* Not safe to unload */
1093 DPRINT1("Drivers device object is referenced or has attached devices\n");
1094
1095 SafeToUnload = FALSE;
1096 }
1097
1098 DeviceObject = DeviceObject->NextDevice;
1099 }
1100
1101 /* If not safe to unload, then return success */
1102 if (!SafeToUnload)
1103 {
1104 ObDereferenceObject(DriverObject);
1105 return STATUS_SUCCESS;
1106 }
1107
1108 /* Set the unload invoked flag */
1109 DriverObject->Flags |= DRVO_UNLOAD_INVOKED;
1110
1111 if (PsGetCurrentProcess() == PsInitialSystemProcess)
1112 {
1113 /* Just call right away */
1114 (*DriverObject->DriverUnload)(DriverObject);
1115 }
1116 else
1117 {
1118 /* Load/Unload must be called from system process */
1119
1120 /* Prepare parameters block */
1121 LoadParams.DriverObject = DriverObject;
1122 KeInitializeEvent(&LoadParams.Event, NotificationEvent, FALSE);
1123
1124 ExInitializeWorkItem(&LoadParams.WorkItem,
1125 (PWORKER_THREAD_ROUTINE)IopLoadUnloadDriver,
1126 (PVOID)&LoadParams);
1127
1128 /* Queue it */
1129 ExQueueWorkItem(&LoadParams.WorkItem, DelayedWorkQueue);
1130
1131 /* And wait when it completes */
1132 KeWaitForSingleObject(&LoadParams.Event, UserRequest, KernelMode,
1133 FALSE, NULL);
1134 }
1135
1136 /* Mark the driver object temporary, so it could be deleted later */
1137 ObMakeTemporaryObject(DriverObject);
1138
1139 /* Dereference it 2 times */
1140 ObDereferenceObject(DriverObject);
1141 ObDereferenceObject(DriverObject);
1142
1143 return STATUS_SUCCESS;
1144 }
1145 else
1146 {
1147 /* Dereference one time (refd inside this function) */
1148 ObDereferenceObject(DriverObject);
1149
1150 /* Return unloading failure */
1151 return STATUS_INVALID_DEVICE_REQUEST;
1152 }
1153 }
1154
1155 VOID
1156 NTAPI
1157 IopReinitializeDrivers(VOID)
1158 {
1159 PDRIVER_REINIT_ITEM ReinitItem;
1160 PLIST_ENTRY Entry;
1161
1162 /* Get the first entry and start looping */
1163 Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
1164 &DriverReinitListLock);
1165 while (Entry)
1166 {
1167 /* Get the item*/
1168 ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);
1169
1170 /* Increment reinitialization counter */
1171 ReinitItem->DriverObject->DriverExtension->Count++;
1172
1173 /* Remove the device object flag */
1174 ReinitItem->DriverObject->Flags &= ~DRVO_REINIT_REGISTERED;
1175
1176 /* Call the routine */
1177 ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
1178 ReinitItem->Context,
1179 ReinitItem->DriverObject->
1180 DriverExtension->Count);
1181
1182 /* Free the entry */
1183 ExFreePool(Entry);
1184
1185 /* Move to the next one */
1186 Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
1187 &DriverReinitListLock);
1188 }
1189 }
1190
1191 VOID
1192 NTAPI
1193 IopReinitializeBootDrivers(VOID)
1194 {
1195 PDRIVER_REINIT_ITEM ReinitItem;
1196 PLIST_ENTRY Entry;
1197
1198 /* Get the first entry and start looping */
1199 Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead,
1200 &DriverBootReinitListLock);
1201 while (Entry)
1202 {
1203 /* Get the item*/
1204 ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);
1205
1206 /* Increment reinitialization counter */
1207 ReinitItem->DriverObject->DriverExtension->Count++;
1208
1209 /* Remove the device object flag */
1210 ReinitItem->DriverObject->Flags &= ~DRVO_BOOTREINIT_REGISTERED;
1211
1212 /* Call the routine */
1213 ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
1214 ReinitItem->Context,
1215 ReinitItem->DriverObject->
1216 DriverExtension->Count);
1217
1218 /* Free the entry */
1219 ExFreePool(Entry);
1220
1221 /* Move to the next one */
1222 Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead,
1223 &DriverBootReinitListLock);
1224 }
1225 }
1226
1227 NTSTATUS
1228 NTAPI
1229 IopCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL,
1230 IN PDRIVER_INITIALIZE InitializationFunction,
1231 IN PUNICODE_STRING RegistryPath,
1232 IN PVOID DllBase,
1233 IN ULONG SizeOfImage,
1234 OUT PDRIVER_OBJECT *pDriverObject)
1235 {
1236 WCHAR NameBuffer[100];
1237 USHORT NameLength;
1238 UNICODE_STRING LocalDriverName;
1239 NTSTATUS Status;
1240 OBJECT_ATTRIBUTES ObjectAttributes;
1241 ULONG ObjectSize;
1242 PDRIVER_OBJECT DriverObject;
1243 UNICODE_STRING ServiceKeyName;
1244 HANDLE hDriver;
1245 ULONG i, RetryCount = 0;
1246
1247 try_again:
1248 /* First, create a unique name for the driver if we don't have one */
1249 if (!DriverName)
1250 {
1251 /* Create a random name and set up the string*/
1252 NameLength = (USHORT)swprintf(NameBuffer,
1253 L"\\Driver\\%08u",
1254 KeTickCount);
1255 LocalDriverName.Length = NameLength * sizeof(WCHAR);
1256 LocalDriverName.MaximumLength = LocalDriverName.Length + sizeof(UNICODE_NULL);
1257 LocalDriverName.Buffer = NameBuffer;
1258 }
1259 else
1260 {
1261 /* So we can avoid another code path, use a local var */
1262 LocalDriverName = *DriverName;
1263 }
1264
1265 /* Initialize the Attributes */
1266 ObjectSize = sizeof(DRIVER_OBJECT) + sizeof(EXTENDED_DRIVER_EXTENSION);
1267 InitializeObjectAttributes(&ObjectAttributes,
1268 &LocalDriverName,
1269 OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
1270 NULL,
1271 NULL);
1272
1273 /* Create the Object */
1274 Status = ObCreateObject(KernelMode,
1275 IoDriverObjectType,
1276 &ObjectAttributes,
1277 KernelMode,
1278 NULL,
1279 ObjectSize,
1280 0,
1281 0,
1282 (PVOID*)&DriverObject);
1283 if (!NT_SUCCESS(Status)) return Status;
1284
1285 DPRINT("IopCreateDriver(): created DO %p\n", DriverObject);
1286
1287 /* Set up the Object */
1288 RtlZeroMemory(DriverObject, ObjectSize);
1289 DriverObject->Type = IO_TYPE_DRIVER;
1290 DriverObject->Size = sizeof(DRIVER_OBJECT);
1291 DriverObject->Flags = DRVO_LEGACY_DRIVER;//DRVO_BUILTIN_DRIVER;
1292 DriverObject->DriverExtension = (PDRIVER_EXTENSION)(DriverObject + 1);
1293 DriverObject->DriverExtension->DriverObject = DriverObject;
1294 DriverObject->DriverInit = InitializationFunction;
1295
1296 /* Loop all Major Functions */
1297 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
1298 {
1299 /* Invalidate each function */
1300 DriverObject->MajorFunction[i] = IopInvalidDeviceRequest;
1301 }
1302
1303 /* Set up the service key name buffer */
1304 ServiceKeyName.Buffer = ExAllocatePoolWithTag(PagedPool,
1305 LocalDriverName.Length +
1306 sizeof(WCHAR),
1307 TAG_IO);
1308 if (!ServiceKeyName.Buffer)
1309 {
1310 /* Fail */
1311 ObMakeTemporaryObject(DriverObject);
1312 ObDereferenceObject(DriverObject);
1313 return STATUS_INSUFFICIENT_RESOURCES;
1314 }
1315
1316 /* Fill out the key data and copy the buffer */
1317 ServiceKeyName.Length = LocalDriverName.Length;
1318 ServiceKeyName.MaximumLength = LocalDriverName.MaximumLength;
1319 RtlCopyMemory(ServiceKeyName.Buffer,
1320 LocalDriverName.Buffer,
1321 LocalDriverName.Length);
1322
1323 /* Null-terminate it and set it */
1324 ServiceKeyName.Buffer[ServiceKeyName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1325 DriverObject->DriverExtension->ServiceKeyName = ServiceKeyName;
1326
1327 /* Also store it in the Driver Object. This is a bit of a hack. */
1328 RtlCopyMemory(&DriverObject->DriverName,
1329 &ServiceKeyName,
1330 sizeof(UNICODE_STRING));
1331
1332 /* Add the Object and get its handle */
1333 Status = ObInsertObject(DriverObject,
1334 NULL,
1335 FILE_READ_DATA,
1336 0,
1337 NULL,
1338 &hDriver);
1339
1340 /* Eliminate small possibility when this function is called more than
1341 once in a row, and KeTickCount doesn't get enough time to change */
1342 if (!DriverName && (Status == STATUS_OBJECT_NAME_COLLISION) && (RetryCount < 100))
1343 {
1344 RetryCount++;
1345 goto try_again;
1346 }
1347
1348 if (!NT_SUCCESS(Status)) return Status;
1349
1350 /* Now reference it */
1351 Status = ObReferenceObjectByHandle(hDriver,
1352 0,
1353 IoDriverObjectType,
1354 KernelMode,
1355 (PVOID*)&DriverObject,
1356 NULL);
1357 if (!NT_SUCCESS(Status))
1358 {
1359 /* Fail */
1360 ObMakeTemporaryObject(DriverObject);
1361 ObDereferenceObject(DriverObject);
1362 return Status;
1363 }
1364
1365 /* Close the extra handle */
1366 ZwClose(hDriver);
1367
1368 DriverObject->HardwareDatabase = &IopHardwareDatabaseKey;
1369 DriverObject->DriverStart = DllBase;
1370 DriverObject->DriverSize = SizeOfImage;
1371
1372 /* Finally, call its init function */
1373 DPRINT("RegistryKey: %wZ\n", RegistryPath);
1374 DPRINT("Calling driver entrypoint at %p\n", InitializationFunction);
1375 Status = (*InitializationFunction)(DriverObject, RegistryPath);
1376 if (!NT_SUCCESS(Status))
1377 {
1378 /* If it didn't work, then kill the object */
1379 DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName, Status);
1380 ObMakeTemporaryObject(DriverObject);
1381 ObDereferenceObject(DriverObject);
1382 }
1383 else
1384 {
1385 /* Returns to caller the object */
1386 *pDriverObject = DriverObject;
1387 }
1388
1389 /* Loop all Major Functions */
1390 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
1391 {
1392 /*
1393 * Make sure the driver didn't set any dispatch entry point to NULL!
1394 * Doing so is illegal; drivers shouldn't touch entry points they
1395 * do not implement.
1396 */
1397 ASSERT(DriverObject->MajorFunction[i] != NULL);
1398
1399 /* Check if it did so anyway */
1400 if (!DriverObject->MajorFunction[i])
1401 {
1402 /* Fix it up */
1403 DriverObject->MajorFunction[i] = IopInvalidDeviceRequest;
1404 }
1405 }
1406
1407 /* Return the Status */
1408 return Status;
1409 }
1410
1411 /* PUBLIC FUNCTIONS ***********************************************************/
1412
1413 /*
1414 * @implemented
1415 */
1416 NTSTATUS
1417 NTAPI
1418 IoCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL,
1419 IN PDRIVER_INITIALIZE InitializationFunction)
1420 {
1421 PDRIVER_OBJECT DriverObject;
1422 return IopCreateDriver(DriverName, InitializationFunction, NULL, 0, 0, &DriverObject);
1423 }
1424
1425 /*
1426 * @implemented
1427 */
1428 VOID
1429 NTAPI
1430 IoDeleteDriver(IN PDRIVER_OBJECT DriverObject)
1431 {
1432 /* Simply dereference the Object */
1433 ObDereferenceObject(DriverObject);
1434 }
1435
1436 /*
1437 * @implemented
1438 */
1439 VOID
1440 NTAPI
1441 IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject,
1442 IN PDRIVER_REINITIALIZE ReinitRoutine,
1443 IN PVOID Context)
1444 {
1445 PDRIVER_REINIT_ITEM ReinitItem;
1446
1447 /* Allocate the entry */
1448 ReinitItem = ExAllocatePoolWithTag(NonPagedPool,
1449 sizeof(DRIVER_REINIT_ITEM),
1450 TAG_REINIT);
1451 if (!ReinitItem) return;
1452
1453 /* Fill it out */
1454 ReinitItem->DriverObject = DriverObject;
1455 ReinitItem->ReinitRoutine = ReinitRoutine;
1456 ReinitItem->Context = Context;
1457
1458 /* Set the Driver Object flag and insert the entry into the list */
1459 DriverObject->Flags |= DRVO_BOOTREINIT_REGISTERED;
1460 ExInterlockedInsertTailList(&DriverBootReinitListHead,
1461 &ReinitItem->ItemEntry,
1462 &DriverBootReinitListLock);
1463 }
1464
1465 /*
1466 * @implemented
1467 */
1468 VOID
1469 NTAPI
1470 IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject,
1471 IN PDRIVER_REINITIALIZE ReinitRoutine,
1472 IN PVOID Context)
1473 {
1474 PDRIVER_REINIT_ITEM ReinitItem;
1475
1476 /* Allocate the entry */
1477 ReinitItem = ExAllocatePoolWithTag(NonPagedPool,
1478 sizeof(DRIVER_REINIT_ITEM),
1479 TAG_REINIT);
1480 if (!ReinitItem) return;
1481
1482 /* Fill it out */
1483 ReinitItem->DriverObject = DriverObject;
1484 ReinitItem->ReinitRoutine = ReinitRoutine;
1485 ReinitItem->Context = Context;
1486
1487 /* Set the Driver Object flag and insert the entry into the list */
1488 DriverObject->Flags |= DRVO_REINIT_REGISTERED;
1489 ExInterlockedInsertTailList(&DriverReinitListHead,
1490 &ReinitItem->ItemEntry,
1491 &DriverReinitListLock);
1492 }
1493
1494 /*
1495 * @implemented
1496 */
1497 NTSTATUS
1498 NTAPI
1499 IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject,
1500 IN PVOID ClientIdentificationAddress,
1501 IN ULONG DriverObjectExtensionSize,
1502 OUT PVOID *DriverObjectExtension)
1503 {
1504 KIRQL OldIrql;
1505 PIO_CLIENT_EXTENSION DriverExtensions, NewDriverExtension;
1506 BOOLEAN Inserted = FALSE;
1507
1508 /* Assume failure */
1509 *DriverObjectExtension = NULL;
1510
1511 /* Allocate the extension */
1512 NewDriverExtension = ExAllocatePoolWithTag(NonPagedPool,
1513 sizeof(IO_CLIENT_EXTENSION) +
1514 DriverObjectExtensionSize,
1515 TAG_DRIVER_EXTENSION);
1516 if (!NewDriverExtension) return STATUS_INSUFFICIENT_RESOURCES;
1517
1518 /* Clear the extension for teh caller */
1519 RtlZeroMemory(NewDriverExtension,
1520 sizeof(IO_CLIENT_EXTENSION) + DriverObjectExtensionSize);
1521
1522 /* Acqure lock */
1523 OldIrql = KeRaiseIrqlToDpcLevel();
1524
1525 /* Fill out the extension */
1526 NewDriverExtension->ClientIdentificationAddress = ClientIdentificationAddress;
1527
1528 /* Loop the current extensions */
1529 DriverExtensions = IoGetDrvObjExtension(DriverObject)->
1530 ClientDriverExtension;
1531 while (DriverExtensions)
1532 {
1533 /* Check if the identifier matches */
1534 if (DriverExtensions->ClientIdentificationAddress ==
1535 ClientIdentificationAddress)
1536 {
1537 /* We have a collision, break out */
1538 break;
1539 }
1540
1541 /* Go to the next one */
1542 DriverExtensions = DriverExtensions->NextExtension;
1543 }
1544
1545 /* Check if we didn't collide */
1546 if (!DriverExtensions)
1547 {
1548 /* Link this one in */
1549 NewDriverExtension->NextExtension =
1550 IoGetDrvObjExtension(DriverObject)->ClientDriverExtension;
1551 IoGetDrvObjExtension(DriverObject)->ClientDriverExtension =
1552 NewDriverExtension;
1553 Inserted = TRUE;
1554 }
1555
1556 /* Release the lock */
1557 KeLowerIrql(OldIrql);
1558
1559 /* Check if insertion failed */
1560 if (!Inserted)
1561 {
1562 /* Free the entry and fail */
1563 ExFreePool(NewDriverExtension);
1564 return STATUS_OBJECT_NAME_COLLISION;
1565 }
1566
1567 /* Otherwise, return the pointer */
1568 *DriverObjectExtension = NewDriverExtension + 1;
1569 return STATUS_SUCCESS;
1570 }
1571
1572 /*
1573 * @implemented
1574 */
1575 PVOID
1576 NTAPI
1577 IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject,
1578 IN PVOID ClientIdentificationAddress)
1579 {
1580 KIRQL OldIrql;
1581 PIO_CLIENT_EXTENSION DriverExtensions;
1582
1583 /* Acquire lock */
1584 OldIrql = KeRaiseIrqlToDpcLevel();
1585
1586 /* Loop the list until we find the right one */
1587 DriverExtensions = IoGetDrvObjExtension(DriverObject)->ClientDriverExtension;
1588 while (DriverExtensions)
1589 {
1590 /* Check for a match */
1591 if (DriverExtensions->ClientIdentificationAddress ==
1592 ClientIdentificationAddress)
1593 {
1594 /* Break out */
1595 break;
1596 }
1597
1598 /* Keep looping */
1599 DriverExtensions = DriverExtensions->NextExtension;
1600 }
1601
1602 /* Release lock */
1603 KeLowerIrql(OldIrql);
1604
1605 /* Return nothing or the extension */
1606 if (!DriverExtensions) return NULL;
1607 return DriverExtensions + 1;
1608 }
1609
1610 VOID NTAPI
1611 IopLoadUnloadDriver(PLOAD_UNLOAD_PARAMS LoadParams)
1612 {
1613 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
1614 UNICODE_STRING ImagePath;
1615 UNICODE_STRING ServiceName;
1616 NTSTATUS Status;
1617 ULONG Type;
1618 PDEVICE_NODE DeviceNode;
1619 PDRIVER_OBJECT DriverObject;
1620 PLDR_DATA_TABLE_ENTRY ModuleObject;
1621 PVOID BaseAddress;
1622 WCHAR *cur;
1623
1624 /* Check if it's an unload request */
1625 if (LoadParams->DriverObject)
1626 {
1627 (*LoadParams->DriverObject->DriverUnload)(LoadParams->DriverObject);
1628
1629 /* Return success and signal the event */
1630 LoadParams->Status = STATUS_SUCCESS;
1631 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1632 return;
1633 }
1634
1635 RtlInitUnicodeString(&ImagePath, NULL);
1636
1637 /*
1638 * Get the service name from the registry key name.
1639 */
1640 ASSERT(LoadParams->ServiceName->Length >= sizeof(WCHAR));
1641
1642 ServiceName = *LoadParams->ServiceName;
1643 cur = LoadParams->ServiceName->Buffer +
1644 (LoadParams->ServiceName->Length / sizeof(WCHAR)) - 1;
1645 while (LoadParams->ServiceName->Buffer != cur)
1646 {
1647 if(*cur == L'\\')
1648 {
1649 ServiceName.Buffer = cur + 1;
1650 ServiceName.Length = LoadParams->ServiceName->Length -
1651 (USHORT)((ULONG_PTR)ServiceName.Buffer -
1652 (ULONG_PTR)LoadParams->ServiceName->Buffer);
1653 break;
1654 }
1655 cur--;
1656 }
1657
1658 /*
1659 * Get service type.
1660 */
1661
1662 RtlZeroMemory(&QueryTable, sizeof(QueryTable));
1663
1664 RtlInitUnicodeString(&ImagePath, NULL);
1665
1666 QueryTable[0].Name = L"Type";
1667 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
1668 QueryTable[0].EntryContext = &Type;
1669
1670 QueryTable[1].Name = L"ImagePath";
1671 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
1672 QueryTable[1].EntryContext = &ImagePath;
1673
1674 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1675 LoadParams->ServiceName->Buffer, QueryTable, NULL, NULL);
1676
1677 if (!NT_SUCCESS(Status))
1678 {
1679 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
1680 if (ImagePath.Buffer)
1681 ExFreePool(ImagePath.Buffer);
1682 LoadParams->Status = Status;
1683 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1684 return;
1685 }
1686
1687 /*
1688 * Normalize the image path for all later processing.
1689 */
1690
1691 Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
1692
1693 if (!NT_SUCCESS(Status))
1694 {
1695 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
1696 LoadParams->Status = Status;
1697 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1698 return;
1699 }
1700
1701 DPRINT("FullImagePath: '%wZ'\n", &ImagePath);
1702 DPRINT("Type: %lx\n", Type);
1703
1704 /*
1705 * Create device node
1706 */
1707
1708 /* Use IopRootDeviceNode for now */
1709 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &ServiceName, &DeviceNode);
1710
1711 if (!NT_SUCCESS(Status))
1712 {
1713 DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status);
1714 LoadParams->Status = Status;
1715 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1716 return;
1717 }
1718
1719 /* Get existing DriverObject pointer (in case the driver has
1720 already been loaded and initialized) */
1721 Status = IopGetDriverObject(
1722 &DriverObject,
1723 &ServiceName,
1724 (Type == 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1725 Type == 8 /* SERVICE_RECOGNIZER_DRIVER */));
1726
1727 if (!NT_SUCCESS(Status))
1728 {
1729 /*
1730 * Load the driver module
1731 */
1732
1733 Status = MmLoadSystemImage(&ImagePath, NULL, NULL, 0, (PVOID)&ModuleObject, &BaseAddress);
1734 if (!NT_SUCCESS(Status) && Status != STATUS_IMAGE_ALREADY_LOADED)
1735 {
1736 DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status);
1737 IopFreeDeviceNode(DeviceNode);
1738 LoadParams->Status = Status;
1739 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1740 return;
1741 }
1742
1743 /*
1744 * Set a service name for the device node
1745 */
1746
1747 RtlCreateUnicodeString(&DeviceNode->ServiceName, ServiceName.Buffer);
1748
1749 /*
1750 * Initialize the driver module if it's loaded for the first time
1751 */
1752 if (Status != STATUS_IMAGE_ALREADY_LOADED)
1753 {
1754 Status = IopInitializeDriverModule(
1755 DeviceNode,
1756 ModuleObject,
1757 &DeviceNode->ServiceName,
1758 (Type == 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1759 Type == 8 /* SERVICE_RECOGNIZER_DRIVER */),
1760 &DriverObject);
1761
1762 if (!NT_SUCCESS(Status))
1763 {
1764 DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status);
1765 MmUnloadSystemImage(ModuleObject);
1766 IopFreeDeviceNode(DeviceNode);
1767 LoadParams->Status = Status;
1768 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1769 return;
1770 }
1771 }
1772
1773 /* Store its DriverSection, so that it could be unloaded */
1774 DriverObject->DriverSection = ModuleObject;
1775
1776 /* Initialize and start device */
1777 IopInitializeDevice(DeviceNode, DriverObject);
1778 Status = IopStartDevice(DeviceNode);
1779 }
1780 else
1781 {
1782 DPRINT("DriverObject already exist in ObjectManager\n");
1783
1784 /* IopGetDriverObject references the DriverObject, so dereference it */
1785 ObDereferenceObject(DriverObject);
1786
1787 /* Free device node since driver loading failed */
1788 IopFreeDeviceNode(DeviceNode);
1789 }
1790
1791 /* Pass status to the caller and signal the event */
1792 LoadParams->Status = Status;
1793 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1794 }
1795
1796 /*
1797 * NtLoadDriver
1798 *
1799 * Loads a device driver.
1800 *
1801 * Parameters
1802 * DriverServiceName
1803 * Name of the service to load (registry key).
1804 *
1805 * Return Value
1806 * Status
1807 *
1808 * Status
1809 * implemented
1810 */
1811 NTSTATUS NTAPI
1812 NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
1813 {
1814 UNICODE_STRING CapturedDriverServiceName = { 0, 0, NULL };
1815 KPROCESSOR_MODE PreviousMode;
1816 LOAD_UNLOAD_PARAMS LoadParams;
1817 NTSTATUS Status;
1818
1819 PAGED_CODE();
1820
1821 PreviousMode = KeGetPreviousMode();
1822
1823 /*
1824 * Check security privileges
1825 */
1826
1827 /* FIXME: Uncomment when privileges will be correctly implemented. */
1828 #if 0
1829 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
1830 {
1831 DPRINT("Privilege not held\n");
1832 return STATUS_PRIVILEGE_NOT_HELD;
1833 }
1834 #endif
1835
1836 Status = ProbeAndCaptureUnicodeString(&CapturedDriverServiceName,
1837 PreviousMode,
1838 DriverServiceName);
1839 if (!NT_SUCCESS(Status))
1840 {
1841 return Status;
1842 }
1843
1844 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName);
1845
1846 LoadParams.ServiceName = &CapturedDriverServiceName;
1847 LoadParams.DriverObject = NULL;
1848 KeInitializeEvent(&LoadParams.Event, NotificationEvent, FALSE);
1849
1850 /* Call the load/unload routine, depending on current process */
1851 if (PsGetCurrentProcess() == PsInitialSystemProcess)
1852 {
1853 /* Just call right away */
1854 IopLoadUnloadDriver(&LoadParams);
1855 }
1856 else
1857 {
1858 /* Load/Unload must be called from system process */
1859 ExInitializeWorkItem(&LoadParams.WorkItem,
1860 (PWORKER_THREAD_ROUTINE)IopLoadUnloadDriver,
1861 (PVOID)&LoadParams);
1862
1863 /* Queue it */
1864 ExQueueWorkItem(&LoadParams.WorkItem, DelayedWorkQueue);
1865
1866 /* And wait when it completes */
1867 KeWaitForSingleObject(&LoadParams.Event, UserRequest, KernelMode,
1868 FALSE, NULL);
1869 }
1870
1871 ReleaseCapturedUnicodeString(&CapturedDriverServiceName,
1872 PreviousMode);
1873
1874 return LoadParams.Status;
1875 }
1876
1877 /*
1878 * NtUnloadDriver
1879 *
1880 * Unloads a legacy device driver.
1881 *
1882 * Parameters
1883 * DriverServiceName
1884 * Name of the service to unload (registry key).
1885 *
1886 * Return Value
1887 * Status
1888 *
1889 * Status
1890 * implemented
1891 */
1892
1893 NTSTATUS NTAPI
1894 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName)
1895 {
1896 return IopUnloadDriver(DriverServiceName, FALSE);
1897 }
1898
1899 /* EOF */