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)
9 * Thomas Weidenmueller (w3seek@reactos.org)
12 /* INCLUDES ******************************************************************/
18 BOOLEAN ObpCaseInsensitive
= TRUE
;
19 POBJECT_DIRECTORY ObpRootDirectoryObject
;
20 POBJECT_DIRECTORY ObpTypeDirectoryObject
;
22 /* DOS Device Prefix \??\ and \?? */
23 ALIGNEDNAME ObpDosDevicesShortNamePrefix
= {{L
'\\',L
'?',L
'?',L
'\\'}};
24 ALIGNEDNAME ObpDosDevicesShortNameRoot
= {{L
'\\',L
'?',L
'?',L
'\0'}};
25 UNICODE_STRING ObpDosDevicesShortName
=
27 sizeof(ObpDosDevicesShortNamePrefix
),
28 sizeof(ObpDosDevicesShortNamePrefix
),
29 (PWSTR
)&ObpDosDevicesShortNamePrefix
32 /* PRIVATE FUNCTIONS *********************************************************/
37 ObpCreateGlobalDosDevicesSD(OUT PSECURITY_DESCRIPTOR
*SecurityDescriptor
)
39 PSECURITY_DESCRIPTOR Sd
= NULL
;
41 ULONG AclSize
, SdSize
;
44 AclSize
= sizeof(ACL
) +
45 sizeof(ACE
) + RtlLengthSid(SeWorldSid
) +
46 sizeof(ACE
) + RtlLengthSid(SeLocalSystemSid
) +
47 sizeof(ACE
) + RtlLengthSid(SeWorldSid
) +
48 sizeof(ACE
) + RtlLengthSid(SeAliasAdminsSid
) +
49 sizeof(ACE
) + RtlLengthSid(SeLocalSystemSid
) +
50 sizeof(ACE
) + RtlLengthSid(SeCreatorOwnerSid
);
52 SdSize
= sizeof(SECURITY_DESCRIPTOR
) + AclSize
;
54 /* Allocate the SD and ACL */
55 Sd
= ExAllocatePoolWithTag(PagedPool
, SdSize
, TAG_SD
);
58 return STATUS_INSUFFICIENT_RESOURCES
;
61 /* Initialize the SD */
62 Status
= RtlCreateSecurityDescriptor(Sd
,
63 SECURITY_DESCRIPTOR_REVISION
);
64 if (!NT_SUCCESS(Status
))
67 Dacl
= (PACL
)((INT_PTR
)Sd
+ sizeof(SECURITY_DESCRIPTOR
));
69 /* Initialize the DACL */
70 RtlCreateAcl(Dacl
, AclSize
, ACL_REVISION
);
73 RtlAddAccessAllowedAce(Dacl
,
75 GENERIC_READ
| GENERIC_EXECUTE
,
78 RtlAddAccessAllowedAce(Dacl
,
83 RtlAddAccessAllowedAceEx(Dacl
,
85 INHERIT_ONLY_ACE
| CONTAINER_INHERIT_ACE
| OBJECT_INHERIT_ACE
,
89 RtlAddAccessAllowedAceEx(Dacl
,
91 INHERIT_ONLY_ACE
| CONTAINER_INHERIT_ACE
| OBJECT_INHERIT_ACE
,
95 RtlAddAccessAllowedAceEx(Dacl
,
97 INHERIT_ONLY_ACE
| CONTAINER_INHERIT_ACE
| OBJECT_INHERIT_ACE
,
101 RtlAddAccessAllowedAceEx(Dacl
,
103 INHERIT_ONLY_ACE
| CONTAINER_INHERIT_ACE
| OBJECT_INHERIT_ACE
,
107 /* Attach the DACL to the SD */
108 Status
= RtlSetDaclSecurityDescriptor(Sd
,
112 if (!NT_SUCCESS(Status
))
115 *SecurityDescriptor
= Sd
;
118 if (!NT_SUCCESS(Status
))
121 ExFreePoolWithTag(Sd
, TAG_SD
);
130 ObpCreateDosDevicesDirectory(VOID
)
132 OBJECT_ATTRIBUTES ObjectAttributes
;
133 UNICODE_STRING RootName
, TargetName
, LinkName
;
134 HANDLE Handle
, SymHandle
;
135 PSECURITY_DESCRIPTOR DosDevicesSD
= NULL
;
138 /* Create a custom security descriptor for the global DosDevices directory */
139 Status
= ObpCreateGlobalDosDevicesSD(&DosDevicesSD
);
140 if (!NT_SUCCESS(Status
))
143 /* Create the global DosDevices directory \?? */
144 RtlInitUnicodeString(&RootName
, L
"\\GLOBAL??");
145 InitializeObjectAttributes(&ObjectAttributes
,
150 Status
= NtCreateDirectoryObject(&Handle
,
151 DIRECTORY_ALL_ACCESS
,
153 ExFreePoolWithTag(DosDevicesSD
, TAG_SD
);
154 if (!NT_SUCCESS(Status
)) return Status
;
156 /* Create the system device map */
157 Status
= ObpCreateDeviceMap(Handle
);
158 if (!NT_SUCCESS(Status
))
161 /*********************************************\
162 |*** HACK until we support device mappings ***|
163 |*** Add a symlink \??\ <--> \GLOBAL??\ ***|
164 \*********************************************/
165 RtlInitUnicodeString(&LinkName
, L
"\\??");
166 InitializeObjectAttributes(&ObjectAttributes
,
171 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
172 SYMBOLIC_LINK_ALL_ACCESS
,
175 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
176 /*********************************************\
177 \*********************************************/
179 // FIXME: Create a device mapping for the global \?? directory
182 * Initialize the \??\GLOBALROOT symbolic link
183 * pointing to the root directory \ .
185 RtlInitUnicodeString(&LinkName
, L
"GLOBALROOT");
186 RtlInitUnicodeString(&TargetName
, L
"");
187 InitializeObjectAttributes(&ObjectAttributes
,
192 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
193 SYMBOLIC_LINK_ALL_ACCESS
,
196 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
199 * Initialize the \??\Global symbolic link pointing to the global
200 * DosDevices directory \?? . It is used to access the global \??
201 * by user-mode components which, by default, use a per-session
202 * DosDevices directory.
204 RtlInitUnicodeString(&LinkName
, L
"Global");
205 InitializeObjectAttributes(&ObjectAttributes
,
210 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
211 SYMBOLIC_LINK_ALL_ACCESS
,
214 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
216 /* Close the directory handle */
218 if (!NT_SUCCESS(Status
)) return Status
;
221 * Initialize the \DosDevices symbolic link pointing to the global
222 * DosDevices directory \?? , for backward compatibility with
223 * Windows NT-2000 systems.
225 RtlCreateUnicodeString(&LinkName
, L
"\\DosDevices");
226 RtlInitUnicodeString(&RootName
, (PCWSTR
)&ObpDosDevicesShortNameRoot
);
227 InitializeObjectAttributes(&ObjectAttributes
,
232 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
233 SYMBOLIC_LINK_ALL_ACCESS
,
236 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
243 * @name ObpDeleteNameCheck
245 * The ObpDeleteNameCheck routine checks if a named object should be
246 * removed from the object directory namespace.
249 * Pointer to the object to check for possible removal.
253 * @remarks An object is removed if the following 4 criteria are met:
254 * 1) The object has 0 handles open
255 * 2) The object is in the directory namespace and has a name
256 * 3) The object is not permanent
261 ObpDeleteNameCheck(IN PVOID Object
)
263 POBJECT_HEADER ObjectHeader
;
264 OBP_LOOKUP_CONTEXT Context
;
265 POBJECT_HEADER_NAME_INFO ObjectNameInfo
;
266 POBJECT_TYPE ObjectType
;
267 PVOID Directory
= NULL
;
269 /* Get object structures */
270 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
271 ObjectNameInfo
= ObpReferenceNameInfo(ObjectHeader
);
272 ObjectType
= ObjectHeader
->Type
;
275 * Check if the handle count is 0, if the object is named,
276 * and if the object isn't a permanent object.
278 if (!(ObjectHeader
->HandleCount
) &&
280 (ObjectNameInfo
->Name
.Length
) &&
281 (ObjectNameInfo
->Directory
) &&
282 !(ObjectHeader
->Flags
& OB_FLAG_PERMANENT
))
284 /* Setup a lookup context */
285 ObpInitializeLookupContext(&Context
);
287 /* Lock the directory */
288 ObpAcquireDirectoryLockExclusive(ObjectNameInfo
->Directory
, &Context
);
291 Object
= ObpLookupEntryDirectory(ObjectNameInfo
->Directory
,
292 &ObjectNameInfo
->Name
,
298 /* Lock the object */
299 ObpAcquireObjectLock(ObjectHeader
);
301 /* Make sure we can still delete the object */
302 if (!(ObjectHeader
->HandleCount
) &&
303 !(ObjectHeader
->Flags
& OB_FLAG_PERMANENT
))
305 /* First delete it from the directory */
306 ObpDeleteEntryDirectory(&Context
);
308 /* Check if this is a symbolic link */
309 if (ObjectType
== ObpSymbolicLinkObjectType
)
311 /* Remove internal name */
312 ObpDeleteSymbolicLinkName(Object
);
315 /* Check if the kernel exclusive is set */
316 ObjectNameInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
317 if ((ObjectNameInfo
) &&
318 (ObjectNameInfo
->QueryReferences
& OB_FLAG_KERNEL_EXCLUSIVE
))
320 /* Remove protection flag */
321 InterlockedExchangeAdd((PLONG
)&ObjectNameInfo
->QueryReferences
,
322 -OB_FLAG_KERNEL_EXCLUSIVE
);
325 /* Get the directory */
326 Directory
= ObjectNameInfo
->Directory
;
329 /* Release the lock */
330 ObpReleaseObjectLock(ObjectHeader
);
333 /* Cleanup after lookup */
334 ObpReleaseLookupContext(&Context
);
336 /* Remove another query reference since we added one on top */
337 ObpDereferenceNameInfo(ObjectNameInfo
);
339 /* Check if we were inserted in a directory */
342 /* We were, so first remove the extra reference we had added */
343 ObpDereferenceNameInfo(ObjectNameInfo
);
345 /* Now dereference the object as well */
346 ObDereferenceObject(Object
);
351 /* Remove the reference we added */
352 ObpDereferenceNameInfo(ObjectNameInfo
);
358 ObpLookupObjectName(IN HANDLE RootHandle OPTIONAL
,
359 IN OUT PUNICODE_STRING ObjectName
,
361 IN POBJECT_TYPE ObjectType
,
362 IN KPROCESSOR_MODE AccessMode
,
363 IN OUT PVOID ParseContext
,
364 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
365 IN PVOID InsertObject OPTIONAL
,
366 IN OUT PACCESS_STATE AccessState
,
367 OUT POBP_LOOKUP_CONTEXT LookupContext
,
368 OUT PVOID
*FoundObject
)
371 POBJECT_HEADER ObjectHeader
;
372 UNICODE_STRING ComponentName
, RemainingName
;
373 BOOLEAN Reparse
= FALSE
, SymLink
= FALSE
;
374 POBJECT_DIRECTORY Directory
= NULL
, ParentDirectory
= NULL
, RootDirectory
;
375 POBJECT_DIRECTORY ReferencedDirectory
= NULL
, ReferencedParentDirectory
= NULL
;
377 OB_PARSE_METHOD ParseRoutine
;
379 KPROCESSOR_MODE AccessCheckMode
;
381 POBJECT_HEADER_NAME_INFO ObjectNameInfo
;
382 ULONG MaxReparse
= 30;
384 OBTRACE(OB_NAMESPACE_DEBUG
,
385 "%s - Finding Object: %wZ. Expecting: %p\n",
390 /* Initialize starting state */
391 ObpInitializeLookupContext(LookupContext
);
393 Status
= STATUS_SUCCESS
;
396 /* Check if case-insensitivity is checked */
397 if (ObpCaseInsensitive
)
399 /* Check if the object type requests this */
400 if (!(ObjectType
) || (ObjectType
->TypeInfo
.CaseInsensitive
))
402 /* Add the flag to disable case sensitivity */
403 Attributes
|= OBJ_CASE_INSENSITIVE
;
407 /* Check if this is a access checks are being forced */
408 AccessCheckMode
= (Attributes
& OBJ_FORCE_ACCESS_CHECK
) ?
409 UserMode
: AccessMode
;
411 /* Check if we got a Root Directory */
414 /* We did. Reference it */
415 Status
= ObReferenceObjectByHandle(RootHandle
,
419 (PVOID
*)&RootDirectory
,
421 if (!NT_SUCCESS(Status
)) return Status
;
424 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(RootDirectory
);
426 /* The name cannot start with a separator, unless this is a file */
427 if ((ObjectName
->Buffer
) &&
428 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
) &&
429 (ObjectHeader
->Type
!= IoFileObjectType
))
431 /* The syntax is bad, so fail this request */
432 ObDereferenceObject(RootDirectory
);
433 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
436 /* Don't parse a Directory */
437 if (ObjectHeader
->Type
!= ObpDirectoryObjectType
)
439 /* Make sure the Object Type has a parse routine */
440 ParseRoutine
= ObjectHeader
->Type
->TypeInfo
.ParseProcedure
;
443 /* We can't parse a name if we don't have a parse routine */
444 ObDereferenceObject(RootDirectory
);
445 return STATUS_INVALID_HANDLE
;
448 /* Set default parse count */
454 /* Start with the full name */
455 RemainingName
= *ObjectName
;
457 /* Call the Parse Procedure */
458 ObpCalloutStart(&CalloutIrql
);
459 Status
= ParseRoutine(RootDirectory
,
469 ObpCalloutEnd(CalloutIrql
, "Parse", ObjectHeader
->Type
, Object
);
471 /* Check for success or failure, so not reparse */
472 if ((Status
!= STATUS_REPARSE
) &&
473 (Status
!= STATUS_REPARSE_OBJECT
))
475 /* Check for failure */
476 if (!NT_SUCCESS(Status
))
478 /* Parse routine might not have cleared this, do it */
483 /* Modify status to reflect failure inside Ob */
484 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
487 /* We're done, return the status and object */
488 *FoundObject
= Object
;
489 ObDereferenceObject(RootDirectory
);
492 else if ((!ObjectName
->Length
) ||
493 (!ObjectName
->Buffer
) ||
494 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
496 /* Reparsed to the root directory, so start over */
497 ObDereferenceObject(RootDirectory
);
498 RootDirectory
= ObpRootDirectoryObject
;
500 /* Don't use this anymore, since we're starting at root */
504 else if (--MaxReparse
)
506 /* Try reparsing again */
511 /* Reparsed too many times */
512 ObDereferenceObject(RootDirectory
);
514 /* Return the object and normalized status */
515 *FoundObject
= Object
;
516 if (!Object
) Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
521 else if (!(ObjectName
->Length
) || !(ObjectName
->Buffer
))
523 /* Just return the Root Directory if we didn't get a name */
524 Status
= ObReferenceObjectByPointer(RootDirectory
,
528 if (NT_SUCCESS(Status
)) Object
= RootDirectory
;
530 /* Remove the first reference we added and return the object */
531 ObDereferenceObject(RootDirectory
);
532 *FoundObject
= Object
;
538 /* We did not get a Root Directory, so use the root */
539 RootDirectory
= ObpRootDirectoryObject
;
541 /* It must start with a path separator */
542 if (!(ObjectName
->Length
) ||
543 !(ObjectName
->Buffer
) ||
544 (ObjectName
->Buffer
[0] != OBJ_NAME_PATH_SEPARATOR
))
546 /* This name is invalid, so fail */
547 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
550 /* Check if the name is only the path separator */
551 if (ObjectName
->Length
== sizeof(OBJ_NAME_PATH_SEPARATOR
))
553 /* So the caller only wants the root directory; do we have one? */
556 /* This must be the first time we're creating it... right? */
559 /* Yes, so return it to ObInsert so that it can create it */
560 Status
= ObReferenceObjectByPointer(InsertObject
,
564 if (NT_SUCCESS(Status
)) *FoundObject
= InsertObject
;
569 /* This should never really happen */
571 return STATUS_INVALID_PARAMETER
;
576 /* We do have the root directory, so just return it */
577 Status
= ObReferenceObjectByPointer(RootDirectory
,
581 if (NT_SUCCESS(Status
)) *FoundObject
= RootDirectory
;
588 /* FIXME: Check if we have a device map */
590 /* Check if this is a possible DOS name */
591 if (!((ULONG_PTR
)(ObjectName
->Buffer
) & 7))
594 * This could be one. Does it match the prefix?
595 * Note that as an optimization, the match is done as 64-bit
596 * compare since the prefix is "\??\" which is exactly 8 bytes.
598 * In the second branch, we test for "\??" which is also valid.
599 * This time, we use a 32-bit compare followed by a Unicode
600 * character compare (16-bit), since the sum is 6 bytes.
602 if ((ObjectName
->Length
>= ObpDosDevicesShortName
.Length
) &&
603 (*(PULONGLONG
)(ObjectName
->Buffer
) ==
604 ObpDosDevicesShortNamePrefix
.Alignment
.QuadPart
))
608 else if ((ObjectName
->Length
== ObpDosDevicesShortName
.Length
-
610 (*(PULONG
)(ObjectName
->Buffer
) ==
611 ObpDosDevicesShortNameRoot
.Alignment
.LowPart
) &&
612 (*((PWCHAR
)(ObjectName
->Buffer
) + 2) ==
613 (WCHAR
)(ObpDosDevicesShortNameRoot
.Alignment
.HighPart
)))
621 /* Check if we were reparsing a symbolic link */
630 while (Reparse
&& MaxReparse
)
633 RemainingName
= *ObjectName
;
635 /* Disable reparsing again */
638 /* Start parse loop */
644 /* Check if the name starts with a path separator */
645 if ((RemainingName
.Length
) &&
646 (RemainingName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
648 /* Skip the path separator */
649 RemainingName
.Buffer
++;
650 RemainingName
.Length
-= sizeof(OBJ_NAME_PATH_SEPARATOR
);
653 /* Find the next Part Name */
654 ComponentName
= RemainingName
;
655 while (RemainingName
.Length
)
657 /* Break if we found the \ ending */
658 if (RemainingName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
) break;
661 RemainingName
.Buffer
++;
662 RemainingName
.Length
-= sizeof(OBJ_NAME_PATH_SEPARATOR
);
665 /* Get its size and make sure it's valid */
666 ComponentName
.Length
-= RemainingName
.Length
;
667 if (!ComponentName
.Length
)
669 /* Invalid size, fail */
670 Status
= STATUS_OBJECT_NAME_INVALID
;
674 /* Check if we're in the root */
675 if (!Directory
) Directory
= RootDirectory
;
677 /* Check if this is a user-mode call that needs to traverse */
678 if ((AccessCheckMode
!= KernelMode
) &&
679 !(AccessState
->Flags
& TOKEN_HAS_TRAVERSE_PRIVILEGE
))
681 /* We shouldn't have referenced a directory yet */
682 ASSERT(ReferencedDirectory
== NULL
);
684 /* Reference the directory */
685 ObReferenceObject(Directory
);
686 ReferencedDirectory
= Directory
;
688 /* Check if we have a parent directory */
691 /* Check for traverse access */
692 if (!ObpCheckTraverseAccess(ParentDirectory
,
699 /* We don't have it, fail */
705 /* Check if we don't have a remaining name yet */
706 if (!RemainingName
.Length
)
708 /* Check if we don't have a referenced directory yet */
709 if (!ReferencedDirectory
)
712 ObReferenceObject(Directory
);
713 ReferencedDirectory
= Directory
;
716 /* Check if we are inserting an object */
719 /* Lock the directory */
720 ObpAcquireDirectoryLockExclusive(Directory
, LookupContext
);
725 Object
= ObpLookupEntryDirectory(Directory
,
728 InsertObject
? FALSE
: TRUE
,
732 /* We didn't find it... do we still have a path? */
733 if (RemainingName
.Length
)
735 /* Then tell the caller the path wasn't found */
736 Status
= STATUS_OBJECT_PATH_NOT_FOUND
;
739 else if (!InsertObject
)
741 /* Otherwise, we have a path, but the name isn't valid */
742 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
746 /* Check create access for the object */
747 if (!ObCheckCreateObjectAccess(Directory
,
748 ObjectType
== ObpDirectoryObjectType
?
749 DIRECTORY_CREATE_SUBDIRECTORY
:
750 DIRECTORY_CREATE_OBJECT
,
757 /* We don't have create access, fail */
761 /* Get the object header */
762 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(InsertObject
);
764 /* FIXME: Check if this is a Section Object or Sym Link */
765 /* FIXME: If it is, then check if this isn't session 0 */
766 /* FIXME: If it isn't, check for SeCreateGlobalPrivilege */
767 /* FIXME: If privilege isn't there, check for unsecure name */
768 /* FIXME: If it isn't a known unsecure name, then fail */
770 /* Create Object Name */
771 NewName
= ExAllocatePoolWithTag(PagedPool
,
772 ComponentName
.Length
,
775 !(ObpInsertEntryDirectory(Directory
,
779 /* Either couldn't allocate the name, or insert failed */
780 if (NewName
) ExFreePoolWithTag(NewName
, OB_NAME_TAG
);
782 /* Fail due to memory reasons */
783 Status
= STATUS_INSUFFICIENT_RESOURCES
;
787 /* Reference newly to be inserted object */
788 ObReferenceObject(InsertObject
);
790 /* Get the name information */
791 ObjectNameInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
793 /* Reference the directory */
794 ObReferenceObject(Directory
);
797 RtlCopyMemory(NewName
,
798 ComponentName
.Buffer
,
799 ComponentName
.Length
);
801 /* Check if we had an old name */
802 if (ObjectNameInfo
->Name
.Buffer
)
805 ExFreePoolWithTag(ObjectNameInfo
->Name
.Buffer
, OB_NAME_TAG
);
809 ObjectNameInfo
->Name
.Buffer
= NewName
;
810 ObjectNameInfo
->Name
.Length
= ComponentName
.Length
;
811 ObjectNameInfo
->Name
.MaximumLength
= ComponentName
.Length
;
813 /* Return Status and the Expected Object */
814 Status
= STATUS_SUCCESS
;
815 Object
= InsertObject
;
817 /* Get out of here */
822 /* We found it, so now get its header */
823 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
826 * Check for a parse Procedure, but don't bother to parse for an insert
827 * unless it's a Symbolic Link, in which case we MUST parse
829 ParseRoutine
= ObjectHeader
->Type
->TypeInfo
.ParseProcedure
;
830 if ((ParseRoutine
) &&
831 (!(InsertObject
) || (ParseRoutine
== ObpParseSymbolicLink
)))
833 /* Use the Root Directory next time */
836 /* Increment the pointer count */
837 InterlockedExchangeAddSizeT(&ObjectHeader
->PointerCount
, 1);
839 /* Cleanup from the first lookup */
840 ObpReleaseLookupContext(LookupContext
);
842 /* Check if we have a referenced directory */
843 if (ReferencedDirectory
)
845 /* We do, dereference it */
846 ObDereferenceObject(ReferencedDirectory
);
847 ReferencedDirectory
= NULL
;
850 /* Check if we have a referenced parent directory */
851 if (ReferencedParentDirectory
)
853 /* We do, dereference it */
854 ObDereferenceObject(ReferencedParentDirectory
);
855 ReferencedParentDirectory
= NULL
;
858 /* Call the Parse Procedure */
859 ObpCalloutStart(&CalloutIrql
);
860 Status
= ParseRoutine(Object
,
870 ObpCalloutEnd(CalloutIrql
, "Parse", ObjectHeader
->Type
, Object
);
872 /* Remove our extra reference */
873 ObDereferenceObject(&ObjectHeader
->Body
);
875 /* Check if we have to reparse */
876 if ((Status
== STATUS_REPARSE
) ||
877 (Status
== STATUS_REPARSE_OBJECT
))
888 /* Start over from root if we got sent back there */
889 if ((Status
== STATUS_REPARSE_OBJECT
) ||
890 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
892 /* Check if we got a root directory */
895 /* Stop using it, because we have a new directory now */
896 ObDereferenceObject(RootDirectory
);
901 ParentDirectory
= NULL
;
902 RootDirectory
= ObpRootDirectoryObject
;
904 /* Check for reparse status */
905 if (Status
== STATUS_REPARSE_OBJECT
)
907 /* Don't reparse again */
910 /* Did we actually get an object to which to reparse? */
913 /* We didn't, so set a failure status */
914 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
918 /* We did, so we're free to parse the new object */
924 /* This is a symbolic link */
929 else if (RootDirectory
== ObpRootDirectoryObject
)
931 /* We got STATUS_REPARSE but are at the Root Directory */
933 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
937 else if (!NT_SUCCESS(Status
))
944 /* We didn't reparse but we didn't find the Object Either */
945 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
948 /* Break out of the loop */
953 /* No parse routine...do we still have a remaining name? */
954 if (!RemainingName
.Length
)
956 /* Are we creating an object? */
959 /* Check if this is a user-mode call that needs to traverse */
960 if ((AccessCheckMode
!= KernelMode
) &&
961 !(AccessState
->Flags
& TOKEN_HAS_TRAVERSE_PRIVILEGE
))
963 /* Check if we can get it */
964 if (!ObpCheckTraverseAccess(Directory
,
971 /* We don't have access, fail */
977 /* Reference the Object */
978 Status
= ObReferenceObjectByPointer(Object
,
982 if (!NT_SUCCESS(Status
)) Object
= NULL
;
985 /* And get out of the reparse loop */
990 /* We still have a name; check if this is a directory object */
991 if (ObjectHeader
->Type
== ObpDirectoryObjectType
)
993 /* Check if we have a referenced parent directory */
994 if (ReferencedParentDirectory
)
997 ObDereferenceObject(ReferencedParentDirectory
);
1000 /* Restart the lookup from this directory */
1001 ReferencedParentDirectory
= ReferencedDirectory
;
1002 ParentDirectory
= Directory
;
1004 ReferencedDirectory
= NULL
;
1008 /* We still have a name, but no parse routine for it */
1009 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
1018 /* Check if we failed */
1019 if (!NT_SUCCESS(Status
))
1021 /* Cleanup after lookup */
1022 ObpReleaseLookupContext(LookupContext
);
1025 /* Check if we have a device map and dereference it if so */
1026 //if (DeviceMap) ObfDereferenceDeviceMap(DeviceMap);
1028 /* Check if we have a referenced directory and dereference it if so */
1029 if (ReferencedDirectory
) ObDereferenceObject(ReferencedDirectory
);
1031 /* Check if we have a referenced parent directory */
1032 if (ReferencedParentDirectory
)
1034 /* We do, dereference it */
1035 ObDereferenceObject(ReferencedParentDirectory
);
1038 /* Set the found object and check if we got one */
1039 *FoundObject
= Object
;
1042 /* Nothing was found. Did we reparse or get success? */
1043 if ((Status
== STATUS_REPARSE
) || (NT_SUCCESS(Status
)))
1045 /* Set correct failure */
1046 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1050 /* Check if we had a root directory */
1051 if (RootHandle
) ObDereferenceObject(RootDirectory
);
1053 /* Return status to caller */
1054 OBTRACE(OB_NAMESPACE_DEBUG
,
1055 "%s - Found Object: %p. Expected: %p\n",
1062 /* PUBLIC FUNCTIONS *********************************************************/
1066 ObQueryNameString(IN PVOID Object
,
1067 OUT POBJECT_NAME_INFORMATION ObjectNameInfo
,
1069 OUT PULONG ReturnLength
)
1071 POBJECT_HEADER_NAME_INFO LocalInfo
;
1072 POBJECT_HEADER ObjectHeader
;
1073 POBJECT_DIRECTORY ParentDirectory
;
1076 BOOLEAN ObjectIsNamed
;
1077 NTSTATUS Status
= STATUS_SUCCESS
;
1079 /* Get the Kernel Meta-Structures */
1080 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
1081 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
1083 /* Check if a Query Name Procedure is available */
1084 if (ObjectHeader
->Type
->TypeInfo
.QueryNameProcedure
)
1086 /* Call the procedure inside SEH */
1087 ObjectIsNamed
= ((LocalInfo
) && (LocalInfo
->Name
.Length
> 0));
1091 Status
= ObjectHeader
->Type
->TypeInfo
.QueryNameProcedure(Object
,
1098 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1100 /* Return the exception code */
1101 Status
= _SEH2_GetExceptionCode();
1108 /* Check if the object doesn't even have a name */
1109 if (!(LocalInfo
) || !(LocalInfo
->Name
.Buffer
))
1111 Status
= STATUS_SUCCESS
;
1115 /* We're returning the name structure */
1116 *ReturnLength
= sizeof(OBJECT_NAME_INFORMATION
);
1118 /* Check if we were given enough space */
1119 if (*ReturnLength
> Length
)
1121 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1125 /* Return an empty buffer */
1126 RtlInitEmptyUnicodeString(&ObjectNameInfo
->Name
, NULL
, 0);
1129 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1131 /* Return the exception code */
1132 Status
= _SEH2_GetExceptionCode();
1140 * Find the size needed for the name. We won't do
1141 * this during the Name Creation loop because we want
1142 * to let the caller know that the buffer isn't big
1143 * enough right at the beginning, not work our way through
1144 * and find out at the end
1148 if (Object
== ObpRootDirectoryObject
)
1150 /* Size of the '\' string */
1151 NameSize
= sizeof(OBJ_NAME_PATH_SEPARATOR
);
1155 /* Get the Object Directory and add name of Object */
1156 ParentDirectory
= LocalInfo
->Directory
;
1157 NameSize
= sizeof(OBJ_NAME_PATH_SEPARATOR
) + LocalInfo
->Name
.Length
;
1159 /* Loop inside the directory to get the top-most one (meaning root) */
1160 while ((ParentDirectory
!= ObpRootDirectoryObject
) && (ParentDirectory
))
1162 /* Get the Name Information */
1163 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(
1164 OBJECT_TO_OBJECT_HEADER(ParentDirectory
));
1166 /* Add the size of the Directory Name */
1167 if (LocalInfo
&& LocalInfo
->Directory
)
1169 /* Size of the '\' string + Directory Name */
1170 NameSize
+= sizeof(OBJ_NAME_PATH_SEPARATOR
) +
1171 LocalInfo
->Name
.Length
;
1173 /* Move to next parent Directory */
1174 ParentDirectory
= LocalInfo
->Directory
;
1178 /* Directory with no name. We append "...\" */
1179 NameSize
+= sizeof(L
"...") + sizeof(OBJ_NAME_PATH_SEPARATOR
);
1185 /* Finally, add the name of the structure and the null char */
1186 *ReturnLength
= NameSize
+
1187 sizeof(OBJECT_NAME_INFORMATION
) +
1188 sizeof(UNICODE_NULL
);
1190 /* Check if we were given enough space */
1191 if (*ReturnLength
> Length
) _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH
);
1194 * Now we will actually create the name. We work backwards because
1195 * it's easier to start off from the Name we have and walk up the
1196 * parent directories. We use the same logic as Name Length calculation.
1198 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
1199 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectNameInfo
+ *ReturnLength
);
1200 *--ObjectName
= UNICODE_NULL
;
1202 /* Check if the object is actually the Root directory */
1203 if (Object
== ObpRootDirectoryObject
)
1205 /* This is already the Root Directory, return "\\" */
1206 *--ObjectName
= OBJ_NAME_PATH_SEPARATOR
;
1207 ObjectNameInfo
->Name
.Length
= (USHORT
)NameSize
;
1208 ObjectNameInfo
->Name
.MaximumLength
= (USHORT
)(NameSize
+
1209 sizeof(UNICODE_NULL
));
1210 ObjectNameInfo
->Name
.Buffer
= ObjectName
;
1211 Status
= STATUS_SUCCESS
;
1215 /* Start by adding the Object's Name */
1216 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1217 LocalInfo
->Name
.Length
);
1218 RtlCopyMemory(ObjectName
,
1219 LocalInfo
->Name
.Buffer
,
1220 LocalInfo
->Name
.Length
);
1222 /* Now parse the Parent directories until we reach the top */
1223 ParentDirectory
= LocalInfo
->Directory
;
1224 while ((ParentDirectory
!= ObpRootDirectoryObject
) && (ParentDirectory
))
1226 /* Get the name information */
1227 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(
1228 OBJECT_TO_OBJECT_HEADER(ParentDirectory
));
1231 *(--ObjectName
) = OBJ_NAME_PATH_SEPARATOR
;
1233 /* Add the Parent Directory's Name */
1234 if (LocalInfo
&& LocalInfo
->Name
.Buffer
)
1237 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1238 LocalInfo
->Name
.Length
);
1239 RtlCopyMemory(ObjectName
,
1240 LocalInfo
->Name
.Buffer
,
1241 LocalInfo
->Name
.Length
);
1243 /* Move to next parent */
1244 ParentDirectory
= LocalInfo
->Directory
;
1248 /* Directory without a name, we add "..." */
1249 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1251 sizeof(UNICODE_NULL
));
1252 RtlCopyMemory(ObjectName
, L
"...", sizeof(L
"..."));
1257 /* Add Root Directory Name */
1258 *(--ObjectName
) = OBJ_NAME_PATH_SEPARATOR
;
1259 ObjectNameInfo
->Name
.Length
= (USHORT
)NameSize
;
1260 ObjectNameInfo
->Name
.MaximumLength
=
1261 (USHORT
)(NameSize
+ sizeof(UNICODE_NULL
));
1262 ObjectNameInfo
->Name
.Buffer
= ObjectName
;
1265 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1267 /* Return the exception code */
1268 Status
= _SEH2_GetExceptionCode();
1272 /* Return success */