- ObpCreateDosDevicesDirectory: Check that allocation succeeded before dereference
[reactos.git] / reactos / ntoskrnl / ob / obname.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ob/obname.c
5 * PURPOSE: Manages all functions related to the Object Manager name-
6 * space, such as finding objects or querying their names.
7 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
8 * Eric Kohl
9 * Thomas Weidenmueller (w3seek@reactos.org)
10 */
11
12 /* INCLUDES ******************************************************************/
13
14 #include <ntoskrnl.h>
15 #define NDEBUG
16 #include <debug.h>
17
18 BOOLEAN ObpCaseInsensitive = TRUE;
19 POBJECT_DIRECTORY ObpRootDirectoryObject;
20 POBJECT_DIRECTORY ObpTypeDirectoryObject;
21
22 /* DOS Device Prefix \??\ and \?? */
23 ALIGNEDNAME ObpDosDevicesShortNamePrefix = {{L'\\',L'?',L'?',L'\\'}};
24 ALIGNEDNAME ObpDosDevicesShortNameRoot = {{L'\\',L'?',L'?',L'\0'}};
25 UNICODE_STRING ObpDosDevicesShortName =
26 {
27 sizeof(ObpDosDevicesShortNamePrefix),
28 sizeof(ObpDosDevicesShortNamePrefix),
29 (PWSTR)&ObpDosDevicesShortNamePrefix
30 };
31
32 /* PRIVATE FUNCTIONS *********************************************************/
33
34 NTSTATUS
35 NTAPI
36 ObpCreateDosDevicesDirectory(VOID)
37 {
38 OBJECT_ATTRIBUTES ObjectAttributes;
39 UNICODE_STRING Name, LinkName;
40 HANDLE Handle, SymHandle;
41 NTSTATUS Status;
42
43 /* Create the '\??' directory */
44 RtlInitUnicodeString(&Name, L"\\??");
45 InitializeObjectAttributes(&ObjectAttributes,
46 &Name,
47 OBJ_PERMANENT,
48 NULL,
49 NULL);
50 Status = NtCreateDirectoryObject(&Handle,
51 DIRECTORY_ALL_ACCESS,
52 &ObjectAttributes);
53 if (!NT_SUCCESS(Status)) return FALSE;
54
55 /* Initialize the GLOBALROOT path */
56 RtlInitUnicodeString(&LinkName, L"GLOBALROOT");
57 RtlInitUnicodeString(&Name, L"");
58 InitializeObjectAttributes(&ObjectAttributes,
59 &LinkName,
60 OBJ_PERMANENT,
61 Handle,
62 NULL);
63 Status = NtCreateSymbolicLinkObject(&SymHandle,
64 SYMBOLIC_LINK_ALL_ACCESS,
65 &ObjectAttributes,
66 &Name);
67 if (NT_SUCCESS(Status)) NtClose(SymHandle);
68
69 /* Link \??\Global to \?? */
70 RtlInitUnicodeString(&LinkName, L"Global");
71 RtlInitUnicodeString(&Name, L"\\??");
72 InitializeObjectAttributes(&ObjectAttributes,
73 &LinkName,
74 OBJ_PERMANENT,
75 Handle,
76 NULL);
77 Status = NtCreateSymbolicLinkObject(&SymHandle,
78 SYMBOLIC_LINK_ALL_ACCESS,
79 &ObjectAttributes,
80 &Name);
81 if (NT_SUCCESS(Status)) NtClose(SymHandle);
82
83 /* Close the directory handle */
84 NtClose(Handle);
85 if (!NT_SUCCESS(Status)) return Status;
86
87 /* Create link from '\DosDevices' to '\??' directory */
88 RtlCreateUnicodeString(&LinkName, L"\\DosDevices");
89 InitializeObjectAttributes(&ObjectAttributes,
90 &LinkName,
91 OBJ_PERMANENT,
92 NULL,
93 NULL);
94 Status = NtCreateSymbolicLinkObject(&SymHandle,
95 SYMBOLIC_LINK_ALL_ACCESS,
96 &ObjectAttributes,
97 &Name);
98 if (NT_SUCCESS(Status)) NtClose(SymHandle);
99
100 /* FIXME: Hack Hack! */
101 ObSystemDeviceMap = ExAllocatePoolWithTag(NonPagedPool,
102 sizeof(*ObSystemDeviceMap),
103 'mDbO');
104 if (!ObSystemDeviceMap) return STATUS_INSUFFICIENT_RESOURCES;
105 RtlZeroMemory(ObSystemDeviceMap, sizeof(*ObSystemDeviceMap));
106
107 /* Return status */
108 return Status;
109 }
110
111 VOID
112 NTAPI
113 ObDereferenceDeviceMap(IN PEPROCESS Process)
114 {
115 //KIRQL OldIrql;
116 PDEVICE_MAP DeviceMap = Process->DeviceMap;
117
118 /* FIXME: We don't use Process Devicemaps yet */
119 if (DeviceMap)
120 {
121 /* FIXME: Acquire the DeviceMap Spinlock */
122 // KeAcquireSpinLock(DeviceMap->Lock, &OldIrql);
123
124 /* Delete the device map link and dereference it */
125 Process->DeviceMap = NULL;
126 if (--DeviceMap->ReferenceCount)
127 {
128 /* Nobody is referencing it anymore, unlink the DOS directory */
129 DeviceMap->DosDevicesDirectory->DeviceMap = NULL;
130
131 /* FIXME: Release the DeviceMap Spinlock */
132 // KeReleasepinLock(DeviceMap->Lock, OldIrql);
133
134 /* Dereference the DOS Devices Directory and free the Device Map */
135 ObDereferenceObject(DeviceMap->DosDevicesDirectory);
136 ExFreePool(DeviceMap);
137 }
138 else
139 {
140 /* FIXME: Release the DeviceMap Spinlock */
141 // KeReleasepinLock(DeviceMap->Lock, OldIrql);
142 }
143 }
144 }
145
146 VOID
147 NTAPI
148 ObInheritDeviceMap(IN PEPROCESS Parent,
149 IN PEPROCESS Process)
150 {
151 /* FIXME: Devicemap Support */
152 }
153
154 /*++
155 * @name ObpDeleteNameCheck
156 *
157 * The ObpDeleteNameCheck routine checks if a named object should be
158 * removed from the object directory namespace.
159 *
160 * @param Object
161 * Pointer to the object to check for possible removal.
162 *
163 * @return None.
164 *
165 * @remarks An object is removed if the following 4 criteria are met:
166 * 1) The object has 0 handles open
167 * 2) The object is in the directory namespace and has a name
168 * 3) The object is not permanent
169 *
170 *--*/
171 VOID
172 NTAPI
173 ObpDeleteNameCheck(IN PVOID Object)
174 {
175 POBJECT_HEADER ObjectHeader;
176 OBP_LOOKUP_CONTEXT Context;
177 POBJECT_HEADER_NAME_INFO ObjectNameInfo;
178 POBJECT_TYPE ObjectType;
179 PVOID Directory = NULL;
180
181 /* Get object structures */
182 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
183 ObjectNameInfo = ObpReferenceNameInfo(ObjectHeader);
184 ObjectType = ObjectHeader->Type;
185
186 /*
187 * Check if the handle count is 0, if the object is named,
188 * and if the object isn't a permanent object.
189 */
190 if (!(ObjectHeader->HandleCount) &&
191 (ObjectNameInfo) &&
192 (ObjectNameInfo->Name.Length) &&
193 (ObjectNameInfo->Directory) &&
194 !(ObjectHeader->Flags & OB_FLAG_PERMANENT))
195 {
196 /* Setup a lookup context */
197 ObpInitializeLookupContext(&Context);
198
199 /* Lock the directory */
200 ObpAcquireDirectoryLockExclusive(ObjectNameInfo->Directory, &Context);
201
202 /* Do the lookup */
203 Object = ObpLookupEntryDirectory(ObjectNameInfo->Directory,
204 &ObjectNameInfo->Name,
205 0,
206 FALSE,
207 &Context);
208 if (Object)
209 {
210 /* Lock the object */
211 ObpAcquireObjectLock(ObjectHeader);
212
213 /* Make sure we can still delete the object */
214 if (!(ObjectHeader->HandleCount) &&
215 !(ObjectHeader->Flags & OB_FLAG_PERMANENT))
216 {
217 /* First delete it from the directory */
218 ObpDeleteEntryDirectory(&Context);
219
220 /* Check if this is a symbolic link */
221 if (ObjectType == ObSymbolicLinkType)
222 {
223 /* Remove internal name */
224 ObpDeleteSymbolicLinkName(Object);
225 }
226
227 /* Check if the magic protection flag is set */
228 ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
229 if ((ObjectNameInfo) &&
230 (ObjectNameInfo->QueryReferences & 0x40000000))
231 {
232 /* Remove protection flag */
233 InterlockedExchangeAdd((PLONG)&ObjectNameInfo->QueryReferences,
234 -0x40000000);
235 }
236
237 /* Get the directory */
238 Directory = ObjectNameInfo->Directory;
239 }
240
241 /* Release the lock */
242 ObpReleaseObjectLock(ObjectHeader);
243 }
244
245 /* Cleanup after lookup */
246 ObpReleaseLookupContext(&Context);
247
248 /* Remove another query reference since we added one on top */
249 ObpDereferenceNameInfo(ObjectNameInfo);
250
251 /* Check if we were inserted in a directory */
252 if (Directory)
253 {
254 /* We were, so first remove the extra reference we had added */
255 ObpDereferenceNameInfo(ObjectNameInfo);
256
257 /* Now dereference the object as well */
258 ObDereferenceObject(Object);
259 }
260 }
261 else
262 {
263 /* Remove the reference we added */
264 ObpDereferenceNameInfo(ObjectNameInfo);
265 }
266 }
267
268 NTSTATUS
269 NTAPI
270 ObpLookupObjectName(IN HANDLE RootHandle OPTIONAL,
271 IN PUNICODE_STRING ObjectName,
272 IN ULONG Attributes,
273 IN POBJECT_TYPE ObjectType,
274 IN KPROCESSOR_MODE AccessMode,
275 IN OUT PVOID ParseContext,
276 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
277 IN PVOID InsertObject OPTIONAL,
278 IN OUT PACCESS_STATE AccessState,
279 OUT POBP_LOOKUP_CONTEXT LookupContext,
280 OUT PVOID *FoundObject)
281 {
282 PVOID Object;
283 POBJECT_HEADER ObjectHeader;
284 UNICODE_STRING ComponentName, RemainingName;
285 BOOLEAN Reparse = FALSE, SymLink = FALSE;
286 POBJECT_DIRECTORY Directory = NULL, ParentDirectory = NULL, RootDirectory;
287 POBJECT_DIRECTORY ReferencedDirectory = NULL, ReferencedParentDirectory = NULL;
288 KIRQL CalloutIrql;
289 OB_PARSE_METHOD ParseRoutine;
290 NTSTATUS Status;
291 KPROCESSOR_MODE AccessCheckMode;
292 PWCHAR NewName;
293 POBJECT_HEADER_NAME_INFO ObjectNameInfo;
294 ULONG MaxReparse = 30;
295 PAGED_CODE();
296 OBTRACE(OB_NAMESPACE_DEBUG,
297 "%s - Finding Object: %wZ. Expecting: %p\n",
298 __FUNCTION__,
299 ObjectName,
300 InsertObject);
301
302 /* Initialize starting state */
303 ObpInitializeLookupContext(LookupContext);
304 *FoundObject = NULL;
305 Status = STATUS_SUCCESS;
306 Object = NULL;
307
308 /* Check if case-insensitivity is checked */
309 if (ObpCaseInsensitive)
310 {
311 /* Check if the object type requests this */
312 if (!(ObjectType) || (ObjectType->TypeInfo.CaseInsensitive))
313 {
314 /* Add the flag to disable case sensitivity */
315 Attributes |= OBJ_CASE_INSENSITIVE;
316 }
317 }
318
319 /* Check if this is a access checks are being forced */
320 AccessCheckMode = (Attributes & OBJ_FORCE_ACCESS_CHECK) ?
321 UserMode : AccessMode;
322
323 /* Check if we got a Root Directory */
324 if (RootHandle)
325 {
326 /* We did. Reference it */
327 Status = ObReferenceObjectByHandle(RootHandle,
328 0,
329 NULL,
330 AccessMode,
331 (PVOID*)&RootDirectory,
332 NULL);
333 if (!NT_SUCCESS(Status)) return Status;
334
335 /* Get the header */
336 ObjectHeader = OBJECT_TO_OBJECT_HEADER(RootDirectory);
337
338 /* The name cannot start with a separator, unless this is a file */
339 if ((ObjectName->Buffer) &&
340 (ObjectName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR) &&
341 (ObjectHeader->Type != IoFileObjectType))
342 {
343 /* The syntax is bad, so fail this request */
344 ObDereferenceObject(RootDirectory);
345 return STATUS_OBJECT_PATH_SYNTAX_BAD;
346 }
347
348 /* Don't parse a Directory */
349 if (ObjectHeader->Type != ObDirectoryType)
350 {
351 /* Make sure the Object Type has a parse routine */
352 ParseRoutine = ObjectHeader->Type->TypeInfo.ParseProcedure;
353 if (!ParseRoutine)
354 {
355 /* We can't parse a name if we don't have a parse routine */
356 ObDereferenceObject(RootDirectory);
357 return STATUS_INVALID_HANDLE;
358 }
359
360 /* Set default parse count */
361 MaxReparse = 30;
362
363 /* Now parse */
364 while (TRUE)
365 {
366 /* Start with the full name */
367 RemainingName = *ObjectName;
368
369 /* Call the Parse Procedure */
370 ObpCalloutStart(&CalloutIrql);
371 Status = ParseRoutine(RootDirectory,
372 ObjectType,
373 AccessState,
374 AccessCheckMode,
375 Attributes,
376 ObjectName,
377 &RemainingName,
378 ParseContext,
379 SecurityQos,
380 &Object);
381 ObpCalloutEnd(CalloutIrql, "Parse", ObjectHeader->Type, Object);
382
383 /* Check for success or failure, so not reparse */
384 if ((Status != STATUS_REPARSE) &&
385 (Status != STATUS_REPARSE_OBJECT))
386 {
387 /* Check for failure */
388 if (!NT_SUCCESS(Status))
389 {
390 /* Parse routine might not have cleared this, do it */
391 Object = NULL;
392 }
393 else if (!Object)
394 {
395 /* Modify status to reflect failure inside Ob */
396 Status = STATUS_OBJECT_NAME_NOT_FOUND;
397 }
398
399 /* We're done, return the status and object */
400 *FoundObject = Object;
401 ObDereferenceObject(RootDirectory);
402 return Status;
403 }
404 else if ((!ObjectName->Length) ||
405 (!ObjectName->Buffer) ||
406 (ObjectName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR))
407 {
408 /* Reparsed to the root directory, so start over */
409 ObDereferenceObject(RootDirectory);
410 RootDirectory = ObpRootDirectoryObject;
411
412 /* Don't use this anymore, since we're starting at root */
413 RootHandle = NULL;
414 goto ParseFromRoot;
415 }
416 else if (--MaxReparse)
417 {
418 /* Try reparsing again */
419 continue;
420 }
421 else
422 {
423 /* Reparsed too many times */
424 ObDereferenceObject(RootDirectory);
425
426 /* Return the object and normalized status */
427 *FoundObject = Object;
428 if (!Object) Status = STATUS_OBJECT_NAME_NOT_FOUND;
429 return Status;
430 }
431 }
432 }
433 else if (!(ObjectName->Length) || !(ObjectName->Buffer))
434 {
435 /* Just return the Root Directory if we didn't get a name*/
436 Status = ObReferenceObjectByPointer(RootDirectory,
437 0,
438 ObjectType,
439 AccessMode);
440 if (NT_SUCCESS(Status)) Object = RootDirectory;
441
442 /* Remove the first reference we added and return the object */
443 ObDereferenceObject(RootDirectory);
444 *FoundObject = Object;
445 return Status;
446 }
447 }
448 else
449 {
450 /* We did not get a Root Directory, so use the root */
451 RootDirectory = ObpRootDirectoryObject;
452
453 /* It must start with a path separator */
454 if (!(ObjectName->Length) ||
455 !(ObjectName->Buffer) ||
456 (ObjectName->Buffer[0] != OBJ_NAME_PATH_SEPARATOR))
457 {
458 /* This name is invalid, so fail */
459 return STATUS_OBJECT_PATH_SYNTAX_BAD;
460 }
461
462 /* Check if the name is only the path separator */
463 if (ObjectName->Length == sizeof(OBJ_NAME_PATH_SEPARATOR))
464 {
465 /* So the caller only wants the root directory; do we have one? */
466 if (!RootDirectory)
467 {
468 /* This must be the first time we're creating it... right? */
469 if (InsertObject)
470 {
471 /* Yes, so return it to ObInsert so that it can create it */
472 Status = ObReferenceObjectByPointer(InsertObject,
473 0,
474 ObjectType,
475 AccessMode);
476 if (NT_SUCCESS(Status)) *FoundObject = InsertObject;
477 return Status;
478 }
479 else
480 {
481 /* This should never really happen */
482 ASSERT(FALSE);
483 return STATUS_INVALID_PARAMETER;
484 }
485 }
486 else
487 {
488 /* We do have the root directory, so just return it */
489 Status = ObReferenceObjectByPointer(RootDirectory,
490 0,
491 ObjectType,
492 AccessMode);
493 if (NT_SUCCESS(Status)) *FoundObject = RootDirectory;
494 return Status;
495 }
496 }
497 else
498 {
499 ParseFromRoot:
500 /* FIXME: Check if we have a device map */
501
502 /* Check if this is a possible DOS name */
503 if (!((ULONG_PTR)(ObjectName->Buffer) & 7))
504 {
505 /*
506 * This could be one. Does it match the prefix?
507 * Note that as an optimization, the match is done as 64-bit
508 * compare since the prefix is "\??\" which is exactly 8 bytes.
509 *
510 * In the second branch, we test for "\??" which is also valid.
511 * This time, we use a 32-bit compare followed by a Unicode
512 * character compare (16-bit), since the sum is 6 bytes.
513 */
514 if ((ObjectName->Length >= ObpDosDevicesShortName.Length) &&
515 (*(PULONGLONG)(ObjectName->Buffer) ==
516 ObpDosDevicesShortNamePrefix.Alignment.QuadPart))
517 {
518 /* FIXME! */
519 }
520 else if ((ObjectName->Length == ObpDosDevicesShortName.Length -
521 sizeof(WCHAR)) &&
522 (*(PULONG)(ObjectName->Buffer) ==
523 ObpDosDevicesShortNameRoot.Alignment.LowPart) &&
524 (*((PWCHAR)(ObjectName->Buffer) + 2) ==
525 (WCHAR)(ObpDosDevicesShortNameRoot.Alignment.HighPart)))
526 {
527 /* FIXME! */
528 }
529 }
530 }
531 }
532
533 /* Check if we were reparsing a symbolic link */
534 if (!SymLink)
535 {
536 /* Allow reparse */
537 Reparse = TRUE;
538 MaxReparse = 30;
539 }
540
541 /* Reparse */
542 while (Reparse)
543 {
544 /* Get the name */
545 RemainingName = *ObjectName;
546
547 /* Disable reparsing again */
548 Reparse = FALSE;
549
550 /* Start parse loop */
551 while (TRUE)
552 {
553 /* Clear object */
554 Object = NULL;
555
556 /* Check if the name starts with a path separator */
557 if ((RemainingName.Length) &&
558 (RemainingName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR))
559 {
560 /* Skip the path separator */
561 RemainingName.Buffer++;
562 RemainingName.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR);
563 }
564
565 /* Find the next Part Name */
566 ComponentName = RemainingName;
567 while (RemainingName.Length)
568 {
569 /* Break if we found the \ ending */
570 if (RemainingName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR) break;
571
572 /* Move on */
573 RemainingName.Buffer++;
574 RemainingName.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR);
575 }
576
577 /* Get its size and make sure it's valid */
578 ComponentName.Length -= RemainingName.Length;
579 if (!ComponentName.Length)
580 {
581 /* Invalid size, fail */
582 Status = STATUS_OBJECT_NAME_INVALID;
583 break;
584 }
585
586 /* Check if we're in the root */
587 if (!Directory) Directory = RootDirectory;
588
589 /* Check if this is a user-mode call that needs to traverse */
590 if ((AccessCheckMode != KernelMode) &&
591 !(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE))
592 {
593 /* We shouldn't have referenced a directory yet */
594 ASSERT(ReferencedDirectory == NULL);
595
596 /* Reference the directory */
597 ObReferenceObject(Directory);
598 ReferencedDirectory = Directory;
599
600 /* Check if we have a parent directory */
601 if (ParentDirectory)
602 {
603 /* Check for traverse access */
604 if (!ObpCheckTraverseAccess(ParentDirectory,
605 DIRECTORY_TRAVERSE,
606 AccessState,
607 FALSE,
608 AccessCheckMode,
609 &Status))
610 {
611 /* We don't have it, fail */
612 break;
613 }
614 }
615 }
616
617 /* Check if we don't have a remaining name yet */
618 if (!RemainingName.Length)
619 {
620 /* Check if we don't have a referenced directory yet */
621 if (!ReferencedDirectory)
622 {
623 /* Reference it */
624 ObReferenceObject(Directory);
625 ReferencedDirectory = Directory;
626 }
627
628 /* Check if we are inserting an object */
629 if (InsertObject)
630 {
631 /* Lock the directory */
632 ObpAcquireDirectoryLockExclusive(Directory, LookupContext);
633 }
634 }
635
636 /* Do the lookup */
637 Object = ObpLookupEntryDirectory(Directory,
638 &ComponentName,
639 Attributes,
640 InsertObject ? FALSE : TRUE,
641 LookupContext);
642 if (!Object)
643 {
644 /* We didn't find it... do we still have a path? */
645 if (RemainingName.Length)
646 {
647 /* Then tell the caller the path wasn't found */
648 Status = STATUS_OBJECT_PATH_NOT_FOUND;
649 break;
650 }
651 else if (!InsertObject)
652 {
653 /* Otherwise, we have a path, but the name isn't valid */
654 Status = STATUS_OBJECT_NAME_NOT_FOUND;
655 break;
656 }
657
658 /* Check create access for the object */
659 if (!ObCheckCreateObjectAccess(Directory,
660 ObjectType == ObDirectoryType ?
661 DIRECTORY_CREATE_SUBDIRECTORY :
662 DIRECTORY_CREATE_OBJECT,
663 AccessState,
664 &ComponentName,
665 FALSE,
666 AccessCheckMode,
667 &Status))
668 {
669 /* We don't have create access, fail */
670 break;
671 }
672
673 /* Get the object header */
674 ObjectHeader = OBJECT_TO_OBJECT_HEADER(InsertObject);
675
676 /* FIXME: Check if this is a Section Object or Sym Link */
677 /* FIXME: If it is, then check if this isn't session 0 */
678 /* FIXME: If it isn't, check for SeCreateGlobalPrivilege */
679 /* FIXME: If privilege isn't there, check for unsecure name */
680 /* FIXME: If it isn't a known unsecure name, then fail */
681
682 /* Create Object Name */
683 NewName = ExAllocatePoolWithTag(PagedPool,
684 ComponentName.Length,
685 OB_NAME_TAG);
686 if (!(NewName) ||
687 !(ObpInsertEntryDirectory(Directory,
688 LookupContext,
689 ObjectHeader)))
690 {
691 /* Either couldn't allocate the name, or insert failed */
692 if (NewName) ExFreePool(NewName);
693
694 /* Fail due to memory reasons */
695 Status = STATUS_INSUFFICIENT_RESOURCES;
696 break;
697 }
698
699 /* Reference newly to be inserted object */
700 ObReferenceObject(InsertObject);
701
702 /* Get the name information */
703 ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
704
705 /* Reference the directory */
706 ObReferenceObject(Directory);
707
708 /* Copy the Name */
709 RtlCopyMemory(NewName,
710 ComponentName.Buffer,
711 ComponentName.Length);
712
713 /* Check if we had an old name */
714 if (ObjectNameInfo->Name.Buffer)
715 {
716 /* Free it */
717 ExFreePoolWithTag(ObjectNameInfo->Name.Buffer, OB_NAME_TAG );
718 }
719
720 /* Write new one */
721 ObjectNameInfo->Name.Buffer = NewName;
722 ObjectNameInfo->Name.Length = ComponentName.Length;
723 ObjectNameInfo->Name.MaximumLength = ComponentName.Length;
724
725 /* Return Status and the Expected Object */
726 Status = STATUS_SUCCESS;
727 Object = InsertObject;
728
729 /* Get out of here */
730 break;
731 }
732
733 ReparseObject:
734 /* We found it, so now get its header */
735 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
736
737 /*
738 * Check for a parse Procedure, but don't bother to parse for an insert
739 * unless it's a Symbolic Link, in which case we MUST parse
740 */
741 ParseRoutine = ObjectHeader->Type->TypeInfo.ParseProcedure;
742 if ((ParseRoutine) &&
743 (!(InsertObject) || (ParseRoutine == ObpParseSymbolicLink)))
744 {
745 /* Use the Root Directory next time */
746 Directory = NULL;
747
748 /* Increment the pointer count */
749 InterlockedExchangeAdd(&ObjectHeader->PointerCount, 1);
750
751 /* Cleanup from the first lookup */
752 ObpReleaseLookupContext(LookupContext);
753
754 /* Check if we have a referenced directory */
755 if (ReferencedDirectory)
756 {
757 /* We do, dereference it */
758 ObDereferenceObject(ReferencedDirectory);
759 ReferencedDirectory = NULL;
760 }
761
762 /* Check if we have a referenced parent directory */
763 if (ReferencedParentDirectory)
764 {
765 /* We do, dereference it */
766 ObDereferenceObject(ReferencedParentDirectory);
767 ReferencedParentDirectory = NULL;
768 }
769
770 /* Call the Parse Procedure */
771 ObpCalloutStart(&CalloutIrql);
772 Status = ParseRoutine(Object,
773 ObjectType,
774 AccessState,
775 AccessCheckMode,
776 Attributes,
777 ObjectName,
778 &RemainingName,
779 ParseContext,
780 SecurityQos,
781 &Object);
782 ObpCalloutEnd(CalloutIrql, "Parse", ObjectHeader->Type, Object);
783
784 /* Remove our extra reference */
785 ObDereferenceObject(&ObjectHeader->Body);
786
787 /* Check if we have to reparse */
788 if ((Status == STATUS_REPARSE) ||
789 (Status == STATUS_REPARSE_OBJECT))
790 {
791 /* Reparse again */
792 Reparse = TRUE;
793
794 /* Start over from root if we got sent back there */
795 if ((Status == STATUS_REPARSE_OBJECT) ||
796 (ObjectName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR))
797 {
798 /* Check if we got a root directory */
799 if (RootHandle)
800 {
801 /* Stop using it, because we have a new directory now */
802 ObDereferenceObject(RootDirectory);
803 RootHandle = NULL;
804 }
805
806 /* Start at Root */
807 ParentDirectory = NULL;
808 RootDirectory = ObpRootDirectoryObject;
809
810 /* Check for reparse status */
811 if (Status == STATUS_REPARSE_OBJECT)
812 {
813 /* Don't reparse again */
814 Reparse = FALSE;
815
816 /* Did we actually get an object to which to reparse? */
817 if (!Object)
818 {
819 /* We didn't, so set a failure status */
820 Status = STATUS_OBJECT_NAME_NOT_FOUND;
821 }
822 else
823 {
824 /* We did, so we're free to parse the new object */
825 goto ReparseObject;
826 }
827 }
828 else
829 {
830 /* This is a symbolic link */
831 SymLink = TRUE;
832 goto ParseFromRoot;
833 }
834 }
835 else if (RootDirectory == ObpRootDirectoryObject)
836 {
837 /* We got STATUS_REPARSE but are at the Root Directory */
838 Object = NULL;
839 Status = STATUS_OBJECT_NAME_NOT_FOUND;
840 Reparse = FALSE;
841 }
842 }
843 else if (!NT_SUCCESS(Status))
844 {
845 /* Total failure */
846 Object = NULL;
847 }
848 else if (!Object)
849 {
850 /* We didn't reparse but we didn't find the Object Either */
851 Status = STATUS_OBJECT_NAME_NOT_FOUND;
852 }
853
854 /* Break out of the loop */
855 break;
856 }
857 else
858 {
859 /* No parse routine...do we still have a remaining name? */
860 if (!RemainingName.Length)
861 {
862 /* Are we creating an object? */
863 if (!InsertObject)
864 {
865 /* Check if this is a user-mode call that needs to traverse */
866 if ((AccessCheckMode != KernelMode) &&
867 !(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE))
868 {
869 /* Check if we can get it */
870 if (!ObpCheckTraverseAccess(Directory,
871 DIRECTORY_TRAVERSE,
872 AccessState,
873 FALSE,
874 AccessCheckMode,
875 &Status))
876 {
877 /* We don't have access, fail */
878 Object = NULL;
879 break;
880 }
881 }
882
883 /* Reference the Object */
884 Status = ObReferenceObjectByPointer(Object,
885 0,
886 ObjectType,
887 AccessMode);
888 if (!NT_SUCCESS(Status)) Object = NULL;
889 }
890
891 /* And get out of the reparse loop */
892 break;
893 }
894 else
895 {
896 /* We still have a name; check if this is a directory object */
897 if (ObjectHeader->Type == ObDirectoryType)
898 {
899 /* Check if we have a referenced parent directory */
900 if (ReferencedParentDirectory)
901 {
902 /* Dereference it */
903 ObDereferenceObject(ReferencedParentDirectory);
904 }
905
906 /* Restart the lookup from this directory */
907 ReferencedParentDirectory = ReferencedDirectory;
908 ParentDirectory = Directory;
909 Directory = Object;
910 ReferencedDirectory = NULL;
911 }
912 else
913 {
914 /* We still have a name, but no parse routine for it */
915 Status = STATUS_OBJECT_TYPE_MISMATCH;
916 Object = NULL;
917 break;
918 }
919 }
920 }
921 }
922 }
923
924 /* Check if we failed */
925 if (!NT_SUCCESS(Status))
926 {
927 /* Cleanup after lookup */
928 ObpReleaseLookupContext(LookupContext);
929 }
930
931 /* Check if we have a device map and dereference it if so */
932 //if (DeviceMap) ObfDereferenceDeviceMap(DeviceMap);
933
934 /* Check if we have a referenced directory and dereference it if so */
935 if (ReferencedDirectory) ObDereferenceObject(ReferencedDirectory);
936
937 /* Check if we have a referenced parent directory */
938 if (ReferencedParentDirectory)
939 {
940 /* We do, dereference it */
941 ObDereferenceObject(ReferencedParentDirectory);
942 }
943
944 /* Set the found object and check if we got one */
945 *FoundObject = Object;
946 if (!Object)
947 {
948 /* Nothing was found. Did we reparse or get success? */
949 if ((Status == STATUS_REPARSE) || (NT_SUCCESS(Status)))
950 {
951 /* Set correct failure */
952 Status = STATUS_OBJECT_NAME_NOT_FOUND;
953 }
954 }
955
956 /* Check if we had a root directory */
957 if (RootHandle) ObDereferenceObject(RootDirectory);
958
959 /* Return status to caller */
960 OBTRACE(OB_NAMESPACE_DEBUG,
961 "%s - Found Object: %p. Expected: %p\n",
962 __FUNCTION__,
963 *FoundObject,
964 InsertObject);
965 return Status;
966 }
967
968 /* PUBLIC FUNCTIONS *********************************************************/
969
970 NTSTATUS
971 NTAPI
972 ObQueryNameString(IN PVOID Object,
973 OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
974 IN ULONG Length,
975 OUT PULONG ReturnLength)
976 {
977 POBJECT_HEADER_NAME_INFO LocalInfo;
978 POBJECT_HEADER ObjectHeader;
979 POBJECT_DIRECTORY ParentDirectory;
980 ULONG NameSize;
981 PWCH ObjectName;
982 BOOLEAN ObjectIsNamed;
983
984 /* Get the Kernel Meta-Structures */
985 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
986 LocalInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
987
988 /* Check if a Query Name Procedure is available */
989 if (ObjectHeader->Type->TypeInfo.QueryNameProcedure)
990 {
991 /* Call the procedure */
992 ObjectIsNamed = ((LocalInfo) && (LocalInfo->Name.Length > 0));
993 return ObjectHeader->Type->TypeInfo.QueryNameProcedure(Object,
994 ObjectIsNamed,
995 ObjectNameInfo,
996 Length,
997 ReturnLength,
998 KernelMode);
999 }
1000
1001 /* Check if the object doesn't even have a name */
1002 if (!(LocalInfo) || !(LocalInfo->Name.Buffer))
1003 {
1004 /* We're returning the name structure */
1005 *ReturnLength = sizeof(OBJECT_NAME_INFORMATION);
1006
1007 /* Check if we were given enough space */
1008 if (*ReturnLength > Length) return STATUS_INFO_LENGTH_MISMATCH;
1009
1010 /* Return an empty buffer */
1011 RtlInitEmptyUnicodeString(&ObjectNameInfo->Name, NULL, 0);
1012 return STATUS_SUCCESS;
1013 }
1014
1015 /*
1016 * Find the size needed for the name. We won't do
1017 * this during the Name Creation loop because we want
1018 * to let the caller know that the buffer isn't big
1019 * enough right at the beginning, not work our way through
1020 * and find out at the end
1021 */
1022 if (Object == ObpRootDirectoryObject)
1023 {
1024 /* Size of the '\' string */
1025 NameSize = sizeof(OBJ_NAME_PATH_SEPARATOR);
1026 }
1027 else
1028 {
1029 /* Get the Object Directory and add name of Object */
1030 ParentDirectory = LocalInfo->Directory;
1031 NameSize = sizeof(OBJ_NAME_PATH_SEPARATOR) + LocalInfo->Name.Length;
1032
1033 /* Loop inside the directory to get the top-most one (meaning root) */
1034 while ((ParentDirectory != ObpRootDirectoryObject) && (ParentDirectory))
1035 {
1036 /* Get the Name Information */
1037 LocalInfo = OBJECT_HEADER_TO_NAME_INFO(
1038 OBJECT_TO_OBJECT_HEADER(ParentDirectory));
1039
1040 /* Add the size of the Directory Name */
1041 if (LocalInfo && LocalInfo->Directory)
1042 {
1043 /* Size of the '\' string + Directory Name */
1044 NameSize += sizeof(OBJ_NAME_PATH_SEPARATOR) +
1045 LocalInfo->Name.Length;
1046
1047 /* Move to next parent Directory */
1048 ParentDirectory = LocalInfo->Directory;
1049 }
1050 else
1051 {
1052 /* Directory with no name. We append "...\" */
1053 NameSize += sizeof(L"...") + sizeof(OBJ_NAME_PATH_SEPARATOR);
1054 break;
1055 }
1056 }
1057 }
1058
1059 /* Finally, add the name of the structure and the null char */
1060 *ReturnLength = NameSize +
1061 sizeof(OBJECT_NAME_INFORMATION) +
1062 sizeof(UNICODE_NULL);
1063
1064 /* Check if we were given enough space */
1065 if (*ReturnLength > Length) return STATUS_INFO_LENGTH_MISMATCH;
1066
1067 /*
1068 * Now we will actually create the name. We work backwards because
1069 * it's easier to start off from the Name we have and walk up the
1070 * parent directories. We use the same logic as Name Length calculation.
1071 */
1072 LocalInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
1073 ObjectName = (PWCH)((ULONG_PTR)ObjectNameInfo + *ReturnLength);
1074 *--ObjectName = UNICODE_NULL;
1075
1076 /* Check if the object is actually the Root directory */
1077 if (Object == ObpRootDirectoryObject)
1078 {
1079 /* This is already the Root Directory, return "\\" */
1080 *--ObjectName = OBJ_NAME_PATH_SEPARATOR;
1081 ObjectNameInfo->Name.Length = (USHORT)NameSize;
1082 ObjectNameInfo->Name.MaximumLength = (USHORT)(NameSize +
1083 sizeof(UNICODE_NULL));
1084 ObjectNameInfo->Name.Buffer = ObjectName;
1085 return STATUS_SUCCESS;
1086 }
1087 else
1088 {
1089 /* Start by adding the Object's Name */
1090 ObjectName = (PWCH)((ULONG_PTR)ObjectName -
1091 LocalInfo->Name.Length);
1092 RtlCopyMemory(ObjectName,
1093 LocalInfo->Name.Buffer,
1094 LocalInfo->Name.Length);
1095
1096 /* Now parse the Parent directories until we reach the top */
1097 ParentDirectory = LocalInfo->Directory;
1098 while ((ParentDirectory != ObpRootDirectoryObject) && (ParentDirectory))
1099 {
1100 /* Get the name information */
1101 LocalInfo = OBJECT_HEADER_TO_NAME_INFO(
1102 OBJECT_TO_OBJECT_HEADER(ParentDirectory));
1103
1104 /* Add the "\" */
1105 *(--ObjectName) = OBJ_NAME_PATH_SEPARATOR;
1106
1107 /* Add the Parent Directory's Name */
1108 if (LocalInfo && LocalInfo->Name.Buffer)
1109 {
1110 /* Add the name */
1111 ObjectName = (PWCH)((ULONG_PTR)ObjectName -
1112 LocalInfo->Name.Length);
1113 RtlCopyMemory(ObjectName,
1114 LocalInfo->Name.Buffer,
1115 LocalInfo->Name.Length);
1116
1117 /* Move to next parent */
1118 ParentDirectory = LocalInfo->Directory;
1119 }
1120 else
1121 {
1122 /* Directory without a name, we add "..." */
1123 ObjectName -= sizeof(L"...");
1124 ObjectName = L"...";
1125 break;
1126 }
1127 }
1128
1129 /* Add Root Directory Name */
1130 *(--ObjectName) = OBJ_NAME_PATH_SEPARATOR;
1131 ObjectNameInfo->Name.Length = (USHORT)NameSize;
1132 ObjectNameInfo->Name.MaximumLength = (USHORT)(NameSize +
1133 sizeof(UNICODE_NULL));
1134 ObjectNameInfo->Name.Buffer = ObjectName;
1135 }
1136
1137 /* Return success */
1138 return STATUS_SUCCESS;
1139 }
1140
1141 VOID
1142 NTAPI
1143 ObQueryDeviceMapInformation(IN PEPROCESS Process,
1144 IN PPROCESS_DEVICEMAP_INFORMATION DeviceMapInfo)
1145 {
1146 //KIRQL OldIrql ;
1147
1148 /*
1149 * FIXME: This is an ugly hack for now, to always return the System Device Map
1150 * instead of returning the Process Device Map. Not important yet since we don't use it
1151 */
1152
1153 /* FIXME: Acquire the DeviceMap Spinlock */
1154 // KeAcquireSpinLock(DeviceMap->Lock, &OldIrql);
1155
1156 /* Make a copy */
1157 DeviceMapInfo->Query.DriveMap = ObSystemDeviceMap->DriveMap;
1158 RtlCopyMemory(DeviceMapInfo->Query.DriveType,
1159 ObSystemDeviceMap->DriveType,
1160 sizeof(ObSystemDeviceMap->DriveType));
1161
1162 /* FIXME: Release the DeviceMap Spinlock */
1163 // KeReleasepinLock(DeviceMap->Lock, OldIrql);
1164 }
1165
1166 /* EOF */