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