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 WCHAR ObpUnsecureGlobalNamesBuffer
[128] = {0};
33 ULONG ObpUnsecureGlobalNamesLength
= sizeof(ObpUnsecureGlobalNamesBuffer
);
35 /* PRIVATE FUNCTIONS *********************************************************/
40 ObpCreateGlobalDosDevicesSD(OUT PSECURITY_DESCRIPTOR
*SecurityDescriptor
)
42 PSECURITY_DESCRIPTOR Sd
= NULL
;
44 ULONG AclSize
, SdSize
;
47 AclSize
= sizeof(ACL
) +
48 sizeof(ACE
) + RtlLengthSid(SeWorldSid
) +
49 sizeof(ACE
) + RtlLengthSid(SeLocalSystemSid
) +
50 sizeof(ACE
) + RtlLengthSid(SeWorldSid
) +
51 sizeof(ACE
) + RtlLengthSid(SeAliasAdminsSid
) +
52 sizeof(ACE
) + RtlLengthSid(SeLocalSystemSid
) +
53 sizeof(ACE
) + RtlLengthSid(SeCreatorOwnerSid
);
55 SdSize
= sizeof(SECURITY_DESCRIPTOR
) + AclSize
;
57 /* Allocate the SD and ACL */
58 Sd
= ExAllocatePoolWithTag(PagedPool
, SdSize
, TAG_SD
);
61 return STATUS_INSUFFICIENT_RESOURCES
;
64 /* Initialize the SD */
65 Status
= RtlCreateSecurityDescriptor(Sd
,
66 SECURITY_DESCRIPTOR_REVISION
);
67 if (!NT_SUCCESS(Status
))
70 Dacl
= (PACL
)((INT_PTR
)Sd
+ sizeof(SECURITY_DESCRIPTOR
));
72 /* Initialize the DACL */
73 RtlCreateAcl(Dacl
, AclSize
, ACL_REVISION
);
76 RtlAddAccessAllowedAce(Dacl
,
78 GENERIC_READ
| GENERIC_EXECUTE
,
81 RtlAddAccessAllowedAce(Dacl
,
86 RtlAddAccessAllowedAceEx(Dacl
,
88 INHERIT_ONLY_ACE
| CONTAINER_INHERIT_ACE
| OBJECT_INHERIT_ACE
,
92 RtlAddAccessAllowedAceEx(Dacl
,
94 INHERIT_ONLY_ACE
| CONTAINER_INHERIT_ACE
| OBJECT_INHERIT_ACE
,
98 RtlAddAccessAllowedAceEx(Dacl
,
100 INHERIT_ONLY_ACE
| CONTAINER_INHERIT_ACE
| OBJECT_INHERIT_ACE
,
104 RtlAddAccessAllowedAceEx(Dacl
,
106 INHERIT_ONLY_ACE
| CONTAINER_INHERIT_ACE
| OBJECT_INHERIT_ACE
,
110 /* Attach the DACL to the SD */
111 Status
= RtlSetDaclSecurityDescriptor(Sd
,
115 if (!NT_SUCCESS(Status
))
118 *SecurityDescriptor
= Sd
;
121 if (!NT_SUCCESS(Status
))
124 ExFreePoolWithTag(Sd
, TAG_SD
);
133 ObpCreateDosDevicesDirectory(VOID
)
135 OBJECT_ATTRIBUTES ObjectAttributes
;
136 UNICODE_STRING RootName
, TargetName
, LinkName
;
137 HANDLE Handle
, SymHandle
;
138 PSECURITY_DESCRIPTOR DosDevicesSD
= NULL
;
141 /* Create a custom security descriptor for the global DosDevices directory */
142 Status
= ObpCreateGlobalDosDevicesSD(&DosDevicesSD
);
143 if (!NT_SUCCESS(Status
))
146 /* Create the global DosDevices directory \?? */
147 RtlInitUnicodeString(&RootName
, L
"\\GLOBAL??");
148 InitializeObjectAttributes(&ObjectAttributes
,
153 Status
= NtCreateDirectoryObject(&Handle
,
154 DIRECTORY_ALL_ACCESS
,
156 ExFreePoolWithTag(DosDevicesSD
, TAG_SD
);
157 if (!NT_SUCCESS(Status
)) return Status
;
159 /* Create the system device map */
160 Status
= ObpCreateDeviceMap(Handle
);
161 if (!NT_SUCCESS(Status
))
164 /*********************************************\
165 |*** HACK until we support device mappings ***|
166 |*** Add a symlink \??\ <--> \GLOBAL??\ ***|
167 \*********************************************/
168 RtlInitUnicodeString(&LinkName
, L
"\\??");
169 InitializeObjectAttributes(&ObjectAttributes
,
174 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
175 SYMBOLIC_LINK_ALL_ACCESS
,
178 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
179 /*********************************************\
180 \*********************************************/
182 // FIXME: Create a device mapping for the global \?? directory
185 * Initialize the \??\GLOBALROOT symbolic link
186 * pointing to the root directory \ .
188 RtlInitUnicodeString(&LinkName
, L
"GLOBALROOT");
189 RtlInitUnicodeString(&TargetName
, L
"");
190 InitializeObjectAttributes(&ObjectAttributes
,
195 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
196 SYMBOLIC_LINK_ALL_ACCESS
,
199 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
202 * Initialize the \??\Global symbolic link pointing to the global
203 * DosDevices directory \?? . It is used to access the global \??
204 * by user-mode components which, by default, use a per-session
205 * DosDevices directory.
207 RtlInitUnicodeString(&LinkName
, L
"Global");
208 InitializeObjectAttributes(&ObjectAttributes
,
213 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
214 SYMBOLIC_LINK_ALL_ACCESS
,
217 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
219 /* Close the directory handle */
221 if (!NT_SUCCESS(Status
)) return Status
;
224 * Initialize the \DosDevices symbolic link pointing to the global
225 * DosDevices directory \?? , for backward compatibility with
226 * Windows NT-2000 systems.
228 RtlCreateUnicodeString(&LinkName
, L
"\\DosDevices");
229 RtlInitUnicodeString(&RootName
, (PCWSTR
)&ObpDosDevicesShortNameRoot
);
230 InitializeObjectAttributes(&ObjectAttributes
,
235 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
236 SYMBOLIC_LINK_ALL_ACCESS
,
239 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
246 * @name ObpDeleteNameCheck
248 * The ObpDeleteNameCheck routine checks if a named object should be
249 * removed from the object directory namespace.
252 * Pointer to the object to check for possible removal.
256 * @remarks An object is removed if the following 4 criteria are met:
257 * 1) The object has 0 handles open
258 * 2) The object is in the directory namespace and has a name
259 * 3) The object is not permanent
264 ObpDeleteNameCheck(IN PVOID Object
)
266 POBJECT_HEADER ObjectHeader
;
267 OBP_LOOKUP_CONTEXT Context
;
268 POBJECT_HEADER_NAME_INFO ObjectNameInfo
;
269 POBJECT_TYPE ObjectType
;
270 PVOID Directory
= NULL
;
272 /* Get object structures */
273 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
274 ObjectNameInfo
= ObpReferenceNameInfo(ObjectHeader
);
275 ObjectType
= ObjectHeader
->Type
;
278 * Check if the handle count is 0, if the object is named,
279 * and if the object isn't a permanent object.
281 if (!(ObjectHeader
->HandleCount
) &&
283 (ObjectNameInfo
->Name
.Length
) &&
284 (ObjectNameInfo
->Directory
) &&
285 !(ObjectHeader
->Flags
& OB_FLAG_PERMANENT
))
287 /* Setup a lookup context */
288 ObpInitializeLookupContext(&Context
);
290 /* Lock the directory */
291 ObpAcquireDirectoryLockExclusive(ObjectNameInfo
->Directory
, &Context
);
294 Object
= ObpLookupEntryDirectory(ObjectNameInfo
->Directory
,
295 &ObjectNameInfo
->Name
,
301 /* Lock the object */
302 ObpAcquireObjectLock(ObjectHeader
);
304 /* Make sure we can still delete the object */
305 if (!(ObjectHeader
->HandleCount
) &&
306 !(ObjectHeader
->Flags
& OB_FLAG_PERMANENT
))
308 /* First delete it from the directory */
309 ObpDeleteEntryDirectory(&Context
);
311 /* Check if this is a symbolic link */
312 if (ObjectType
== ObpSymbolicLinkObjectType
)
314 /* Remove internal name */
315 ObpDeleteSymbolicLinkName(Object
);
318 /* Check if the kernel exclusive is set */
319 ObjectNameInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
320 if ((ObjectNameInfo
) &&
321 (ObjectNameInfo
->QueryReferences
& OB_FLAG_KERNEL_EXCLUSIVE
))
323 /* Remove protection flag */
324 InterlockedExchangeAdd((PLONG
)&ObjectNameInfo
->QueryReferences
,
325 -OB_FLAG_KERNEL_EXCLUSIVE
);
328 /* Get the directory */
329 Directory
= ObjectNameInfo
->Directory
;
332 /* Release the lock */
333 ObpReleaseObjectLock(ObjectHeader
);
336 /* Cleanup after lookup */
337 ObpReleaseLookupContext(&Context
);
339 /* Remove another query reference since we added one on top */
340 ObpDereferenceNameInfo(ObjectNameInfo
);
342 /* Check if we were inserted in a directory */
345 /* We were, so first remove the extra reference we had added */
346 ObpDereferenceNameInfo(ObjectNameInfo
);
348 /* Now dereference the object as well */
349 ObDereferenceObject(Object
);
354 /* Remove the reference we added */
355 ObpDereferenceNameInfo(ObjectNameInfo
);
361 ObpLookupObjectName(IN HANDLE RootHandle OPTIONAL
,
362 IN OUT PUNICODE_STRING ObjectName
,
364 IN POBJECT_TYPE ObjectType
,
365 IN KPROCESSOR_MODE AccessMode
,
366 IN OUT PVOID ParseContext
,
367 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
368 IN PVOID InsertObject OPTIONAL
,
369 IN OUT PACCESS_STATE AccessState
,
370 OUT POBP_LOOKUP_CONTEXT LookupContext
,
371 OUT PVOID
*FoundObject
)
374 POBJECT_HEADER ObjectHeader
;
375 UNICODE_STRING ComponentName
, RemainingName
;
376 BOOLEAN Reparse
= FALSE
, SymLink
= FALSE
;
377 POBJECT_DIRECTORY Directory
= NULL
, ParentDirectory
= NULL
, RootDirectory
;
378 POBJECT_DIRECTORY ReferencedDirectory
= NULL
, ReferencedParentDirectory
= NULL
;
380 OB_PARSE_METHOD ParseRoutine
;
382 KPROCESSOR_MODE AccessCheckMode
;
384 POBJECT_HEADER_NAME_INFO ObjectNameInfo
;
385 ULONG MaxReparse
= 30;
387 OBTRACE(OB_NAMESPACE_DEBUG
,
388 "%s - Finding Object: %wZ. Expecting: %p\n",
393 /* Initialize starting state */
394 ObpInitializeLookupContext(LookupContext
);
396 Status
= STATUS_SUCCESS
;
399 /* Check if case-insensitivity is checked */
400 if (ObpCaseInsensitive
)
402 /* Check if the object type requests this */
403 if (!(ObjectType
) || (ObjectType
->TypeInfo
.CaseInsensitive
))
405 /* Add the flag to disable case sensitivity */
406 Attributes
|= OBJ_CASE_INSENSITIVE
;
410 /* Check if this is a access checks are being forced */
411 AccessCheckMode
= (Attributes
& OBJ_FORCE_ACCESS_CHECK
) ?
412 UserMode
: AccessMode
;
414 /* Check if we got a Root Directory */
417 /* We did. Reference it */
418 Status
= ObReferenceObjectByHandle(RootHandle
,
422 (PVOID
*)&RootDirectory
,
424 if (!NT_SUCCESS(Status
)) return Status
;
427 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(RootDirectory
);
429 /* The name cannot start with a separator, unless this is a file */
430 if ((ObjectName
->Buffer
) &&
431 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
) &&
432 (ObjectHeader
->Type
!= IoFileObjectType
))
434 /* The syntax is bad, so fail this request */
435 ObDereferenceObject(RootDirectory
);
436 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
439 /* Don't parse a Directory */
440 if (ObjectHeader
->Type
!= ObpDirectoryObjectType
)
442 /* Make sure the Object Type has a parse routine */
443 ParseRoutine
= ObjectHeader
->Type
->TypeInfo
.ParseProcedure
;
446 /* We can't parse a name if we don't have a parse routine */
447 ObDereferenceObject(RootDirectory
);
448 return STATUS_INVALID_HANDLE
;
451 /* Set default parse count */
457 /* Start with the full name */
458 RemainingName
= *ObjectName
;
460 /* Call the Parse Procedure */
461 ObpCalloutStart(&CalloutIrql
);
462 Status
= ParseRoutine(RootDirectory
,
472 ObpCalloutEnd(CalloutIrql
, "Parse", ObjectHeader
->Type
, Object
);
474 /* Check for success or failure, so not reparse */
475 if ((Status
!= STATUS_REPARSE
) &&
476 (Status
!= STATUS_REPARSE_OBJECT
))
478 /* Check for failure */
479 if (!NT_SUCCESS(Status
))
481 /* Parse routine might not have cleared this, do it */
486 /* Modify status to reflect failure inside Ob */
487 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
490 /* We're done, return the status and object */
491 *FoundObject
= Object
;
492 ObDereferenceObject(RootDirectory
);
495 else if ((!ObjectName
->Length
) ||
496 (!ObjectName
->Buffer
) ||
497 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
499 /* Reparsed to the root directory, so start over */
500 ObDereferenceObject(RootDirectory
);
501 RootDirectory
= ObpRootDirectoryObject
;
503 /* Don't use this anymore, since we're starting at root */
507 else if (--MaxReparse
)
509 /* Try reparsing again */
514 /* Reparsed too many times */
515 ObDereferenceObject(RootDirectory
);
517 /* Return the object and normalized status */
518 *FoundObject
= Object
;
519 if (!Object
) Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
524 else if (!(ObjectName
->Length
) || !(ObjectName
->Buffer
))
526 /* Just return the Root Directory if we didn't get a name */
527 Status
= ObReferenceObjectByPointer(RootDirectory
,
531 if (NT_SUCCESS(Status
)) Object
= RootDirectory
;
533 /* Remove the first reference we added and return the object */
534 ObDereferenceObject(RootDirectory
);
535 *FoundObject
= Object
;
541 /* We did not get a Root Directory, so use the root */
542 RootDirectory
= ObpRootDirectoryObject
;
544 /* It must start with a path separator */
545 if (!(ObjectName
->Length
) ||
546 !(ObjectName
->Buffer
) ||
547 (ObjectName
->Buffer
[0] != OBJ_NAME_PATH_SEPARATOR
))
549 /* This name is invalid, so fail */
550 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
553 /* Check if the name is only the path separator */
554 if (ObjectName
->Length
== sizeof(OBJ_NAME_PATH_SEPARATOR
))
556 /* So the caller only wants the root directory; do we have one? */
559 /* This must be the first time we're creating it... right? */
562 /* Yes, so return it to ObInsert so that it can create it */
563 Status
= ObReferenceObjectByPointer(InsertObject
,
567 if (NT_SUCCESS(Status
)) *FoundObject
= InsertObject
;
572 /* This should never really happen */
574 return STATUS_INVALID_PARAMETER
;
579 /* We do have the root directory, so just return it */
580 Status
= ObReferenceObjectByPointer(RootDirectory
,
584 if (NT_SUCCESS(Status
)) *FoundObject
= RootDirectory
;
591 /* FIXME: Check if we have a device map */
593 /* Check if this is a possible DOS name */
594 if (!((ULONG_PTR
)(ObjectName
->Buffer
) & 7))
597 * This could be one. Does it match the prefix?
598 * Note that as an optimization, the match is done as 64-bit
599 * compare since the prefix is "\??\" which is exactly 8 bytes.
601 * In the second branch, we test for "\??" which is also valid.
602 * This time, we use a 32-bit compare followed by a Unicode
603 * character compare (16-bit), since the sum is 6 bytes.
605 if ((ObjectName
->Length
>= ObpDosDevicesShortName
.Length
) &&
606 (*(PULONGLONG
)(ObjectName
->Buffer
) ==
607 ObpDosDevicesShortNamePrefix
.Alignment
.QuadPart
))
611 else if ((ObjectName
->Length
== ObpDosDevicesShortName
.Length
-
613 (*(PULONG
)(ObjectName
->Buffer
) ==
614 ObpDosDevicesShortNameRoot
.Alignment
.LowPart
) &&
615 (*((PWCHAR
)(ObjectName
->Buffer
) + 2) ==
616 (WCHAR
)(ObpDosDevicesShortNameRoot
.Alignment
.HighPart
)))
624 /* Check if we were reparsing a symbolic link */
633 while (Reparse
&& MaxReparse
)
636 RemainingName
= *ObjectName
;
638 /* Disable reparsing again */
641 /* Start parse loop */
647 /* Check if the name starts with a path separator */
648 if ((RemainingName
.Length
) &&
649 (RemainingName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
651 /* Skip the path separator */
652 RemainingName
.Buffer
++;
653 RemainingName
.Length
-= sizeof(OBJ_NAME_PATH_SEPARATOR
);
656 /* Find the next Part Name */
657 ComponentName
= RemainingName
;
658 while (RemainingName
.Length
)
660 /* Break if we found the \ ending */
661 if (RemainingName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
) break;
664 RemainingName
.Buffer
++;
665 RemainingName
.Length
-= sizeof(OBJ_NAME_PATH_SEPARATOR
);
668 /* Get its size and make sure it's valid */
669 ComponentName
.Length
-= RemainingName
.Length
;
670 if (!ComponentName
.Length
)
672 /* Invalid size, fail */
673 Status
= STATUS_OBJECT_NAME_INVALID
;
677 /* Check if we're in the root */
678 if (!Directory
) Directory
= RootDirectory
;
680 /* Check if this is a user-mode call that needs to traverse */
681 if ((AccessCheckMode
!= KernelMode
) &&
682 !(AccessState
->Flags
& TOKEN_HAS_TRAVERSE_PRIVILEGE
))
684 /* We shouldn't have referenced a directory yet */
685 ASSERT(ReferencedDirectory
== NULL
);
687 /* Reference the directory */
688 ObReferenceObject(Directory
);
689 ReferencedDirectory
= Directory
;
691 /* Check if we have a parent directory */
694 /* Check for traverse access */
695 if (!ObpCheckTraverseAccess(ParentDirectory
,
702 /* We don't have it, fail */
708 /* Check if we don't have a remaining name yet */
709 if (!RemainingName
.Length
)
711 /* Check if we don't have a referenced directory yet */
712 if (!ReferencedDirectory
)
715 ObReferenceObject(Directory
);
716 ReferencedDirectory
= Directory
;
719 /* Check if we are inserting an object */
722 /* Lock the directory */
723 ObpAcquireDirectoryLockExclusive(Directory
, LookupContext
);
728 Object
= ObpLookupEntryDirectory(Directory
,
731 InsertObject
? FALSE
: TRUE
,
735 /* We didn't find it... do we still have a path? */
736 if (RemainingName
.Length
)
738 /* Then tell the caller the path wasn't found */
739 Status
= STATUS_OBJECT_PATH_NOT_FOUND
;
742 else if (!InsertObject
)
744 /* Otherwise, we have a path, but the name isn't valid */
745 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
749 /* Check create access for the object */
750 if (!ObCheckCreateObjectAccess(Directory
,
751 ObjectType
== ObpDirectoryObjectType
?
752 DIRECTORY_CREATE_SUBDIRECTORY
:
753 DIRECTORY_CREATE_OBJECT
,
760 /* We don't have create access, fail */
764 /* Get the object header */
765 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(InsertObject
);
767 /* FIXME: Check if this is a Section Object or Sym Link */
768 /* FIXME: If it is, then check if this isn't session 0 */
769 /* FIXME: If it isn't, check for SeCreateGlobalPrivilege */
770 /* FIXME: If privilege isn't there, check for unsecure name */
771 /* FIXME: If it isn't a known unsecure name, then fail */
773 /* Create Object Name */
774 NewName
= ExAllocatePoolWithTag(PagedPool
,
775 ComponentName
.Length
,
778 !(ObpInsertEntryDirectory(Directory
,
782 /* Either couldn't allocate the name, or insert failed */
783 if (NewName
) ExFreePoolWithTag(NewName
, OB_NAME_TAG
);
785 /* Fail due to memory reasons */
786 Status
= STATUS_INSUFFICIENT_RESOURCES
;
790 /* Reference newly to be inserted object */
791 ObReferenceObject(InsertObject
);
793 /* Get the name information */
794 ObjectNameInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
796 /* Reference the directory */
797 ObReferenceObject(Directory
);
800 RtlCopyMemory(NewName
,
801 ComponentName
.Buffer
,
802 ComponentName
.Length
);
804 /* Check if we had an old name */
805 if (ObjectNameInfo
->Name
.Buffer
)
808 ExFreePoolWithTag(ObjectNameInfo
->Name
.Buffer
, OB_NAME_TAG
);
812 ObjectNameInfo
->Name
.Buffer
= NewName
;
813 ObjectNameInfo
->Name
.Length
= ComponentName
.Length
;
814 ObjectNameInfo
->Name
.MaximumLength
= ComponentName
.Length
;
816 /* Return Status and the Expected Object */
817 Status
= STATUS_SUCCESS
;
818 Object
= InsertObject
;
820 /* Get out of here */
825 /* We found it, so now get its header */
826 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
829 * Check for a parse Procedure, but don't bother to parse for an insert
830 * unless it's a Symbolic Link, in which case we MUST parse
832 ParseRoutine
= ObjectHeader
->Type
->TypeInfo
.ParseProcedure
;
833 if ((ParseRoutine
) &&
834 (!(InsertObject
) || (ParseRoutine
== ObpParseSymbolicLink
)))
836 /* Use the Root Directory next time */
839 /* Increment the pointer count */
840 InterlockedExchangeAddSizeT(&ObjectHeader
->PointerCount
, 1);
842 /* Cleanup from the first lookup */
843 ObpReleaseLookupContext(LookupContext
);
845 /* Check if we have a referenced directory */
846 if (ReferencedDirectory
)
848 /* We do, dereference it */
849 ObDereferenceObject(ReferencedDirectory
);
850 ReferencedDirectory
= NULL
;
853 /* Check if we have a referenced parent directory */
854 if (ReferencedParentDirectory
)
856 /* We do, dereference it */
857 ObDereferenceObject(ReferencedParentDirectory
);
858 ReferencedParentDirectory
= NULL
;
861 /* Call the Parse Procedure */
862 ObpCalloutStart(&CalloutIrql
);
863 Status
= ParseRoutine(Object
,
873 ObpCalloutEnd(CalloutIrql
, "Parse", ObjectHeader
->Type
, Object
);
875 /* Remove our extra reference */
876 ObDereferenceObject(&ObjectHeader
->Body
);
878 /* Check if we have to reparse */
879 if ((Status
== STATUS_REPARSE
) ||
880 (Status
== STATUS_REPARSE_OBJECT
))
891 /* Start over from root if we got sent back there */
892 if ((Status
== STATUS_REPARSE_OBJECT
) ||
893 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
895 /* Check if we got a root directory */
898 /* Stop using it, because we have a new directory now */
899 ObDereferenceObject(RootDirectory
);
904 ParentDirectory
= NULL
;
905 RootDirectory
= ObpRootDirectoryObject
;
907 /* Check for reparse status */
908 if (Status
== STATUS_REPARSE_OBJECT
)
910 /* Don't reparse again */
913 /* Did we actually get an object to which to reparse? */
916 /* We didn't, so set a failure status */
917 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
921 /* We did, so we're free to parse the new object */
927 /* This is a symbolic link */
932 else if (RootDirectory
== ObpRootDirectoryObject
)
934 /* We got STATUS_REPARSE but are at the Root Directory */
936 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
940 else if (!NT_SUCCESS(Status
))
947 /* We didn't reparse but we didn't find the Object Either */
948 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
951 /* Break out of the loop */
956 /* No parse routine...do we still have a remaining name? */
957 if (!RemainingName
.Length
)
959 /* Are we creating an object? */
962 /* Check if this is a user-mode call that needs to traverse */
963 if ((AccessCheckMode
!= KernelMode
) &&
964 !(AccessState
->Flags
& TOKEN_HAS_TRAVERSE_PRIVILEGE
))
966 /* Check if we can get it */
967 if (!ObpCheckTraverseAccess(Directory
,
974 /* We don't have access, fail */
980 /* Reference the Object */
981 Status
= ObReferenceObjectByPointer(Object
,
985 if (!NT_SUCCESS(Status
)) Object
= NULL
;
988 /* And get out of the reparse loop */
993 /* We still have a name; check if this is a directory object */
994 if (ObjectHeader
->Type
== ObpDirectoryObjectType
)
996 /* Check if we have a referenced parent directory */
997 if (ReferencedParentDirectory
)
1000 ObDereferenceObject(ReferencedParentDirectory
);
1003 /* Restart the lookup from this directory */
1004 ReferencedParentDirectory
= ReferencedDirectory
;
1005 ParentDirectory
= Directory
;
1007 ReferencedDirectory
= NULL
;
1011 /* We still have a name, but no parse routine for it */
1012 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
1021 /* Check if we failed */
1022 if (!NT_SUCCESS(Status
))
1024 /* Cleanup after lookup */
1025 ObpReleaseLookupContext(LookupContext
);
1028 /* Check if we have a device map and dereference it if so */
1029 //if (DeviceMap) ObfDereferenceDeviceMap(DeviceMap);
1031 /* Check if we have a referenced directory and dereference it if so */
1032 if (ReferencedDirectory
) ObDereferenceObject(ReferencedDirectory
);
1034 /* Check if we have a referenced parent directory */
1035 if (ReferencedParentDirectory
)
1037 /* We do, dereference it */
1038 ObDereferenceObject(ReferencedParentDirectory
);
1041 /* Set the found object and check if we got one */
1042 *FoundObject
= Object
;
1045 /* Nothing was found. Did we reparse or get success? */
1046 if ((Status
== STATUS_REPARSE
) || (NT_SUCCESS(Status
)))
1048 /* Set correct failure */
1049 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1053 /* Check if we had a root directory */
1054 if (RootHandle
) ObDereferenceObject(RootDirectory
);
1056 /* Return status to caller */
1057 OBTRACE(OB_NAMESPACE_DEBUG
,
1058 "%s - Found Object: %p. Expected: %p\n",
1065 /* PUBLIC FUNCTIONS *********************************************************/
1069 ObQueryNameString(IN PVOID Object
,
1070 OUT POBJECT_NAME_INFORMATION ObjectNameInfo
,
1072 OUT PULONG ReturnLength
)
1074 POBJECT_HEADER_NAME_INFO LocalInfo
;
1075 POBJECT_HEADER ObjectHeader
;
1076 POBJECT_DIRECTORY ParentDirectory
;
1079 BOOLEAN ObjectIsNamed
;
1080 NTSTATUS Status
= STATUS_SUCCESS
;
1082 /* Get the Kernel Meta-Structures */
1083 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
1084 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
1086 /* Check if a Query Name Procedure is available */
1087 if (ObjectHeader
->Type
->TypeInfo
.QueryNameProcedure
)
1089 /* Call the procedure inside SEH */
1090 ObjectIsNamed
= ((LocalInfo
) && (LocalInfo
->Name
.Length
> 0));
1094 Status
= ObjectHeader
->Type
->TypeInfo
.QueryNameProcedure(Object
,
1101 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1103 /* Return the exception code */
1104 Status
= _SEH2_GetExceptionCode();
1111 /* Check if the object doesn't even have a name */
1112 if (!(LocalInfo
) || !(LocalInfo
->Name
.Buffer
))
1114 Status
= STATUS_SUCCESS
;
1118 /* We're returning the name structure */
1119 *ReturnLength
= sizeof(OBJECT_NAME_INFORMATION
);
1121 /* Check if we were given enough space */
1122 if (*ReturnLength
> Length
)
1124 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1128 /* Return an empty buffer */
1129 RtlInitEmptyUnicodeString(&ObjectNameInfo
->Name
, NULL
, 0);
1132 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1134 /* Return the exception code */
1135 Status
= _SEH2_GetExceptionCode();
1143 * Find the size needed for the name. We won't do
1144 * this during the Name Creation loop because we want
1145 * to let the caller know that the buffer isn't big
1146 * enough right at the beginning, not work our way through
1147 * and find out at the end
1151 if (Object
== ObpRootDirectoryObject
)
1153 /* Size of the '\' string */
1154 NameSize
= sizeof(OBJ_NAME_PATH_SEPARATOR
);
1158 /* Get the Object Directory and add name of Object */
1159 ParentDirectory
= LocalInfo
->Directory
;
1160 NameSize
= sizeof(OBJ_NAME_PATH_SEPARATOR
) + LocalInfo
->Name
.Length
;
1162 /* Loop inside the directory to get the top-most one (meaning root) */
1163 while ((ParentDirectory
!= ObpRootDirectoryObject
) && (ParentDirectory
))
1165 /* Get the Name Information */
1166 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(
1167 OBJECT_TO_OBJECT_HEADER(ParentDirectory
));
1169 /* Add the size of the Directory Name */
1170 if (LocalInfo
&& LocalInfo
->Directory
)
1172 /* Size of the '\' string + Directory Name */
1173 NameSize
+= sizeof(OBJ_NAME_PATH_SEPARATOR
) +
1174 LocalInfo
->Name
.Length
;
1176 /* Move to next parent Directory */
1177 ParentDirectory
= LocalInfo
->Directory
;
1181 /* Directory with no name. We append "...\" */
1182 NameSize
+= sizeof(L
"...") + sizeof(OBJ_NAME_PATH_SEPARATOR
);
1188 /* Finally, add the name of the structure and the null char */
1189 *ReturnLength
= NameSize
+
1190 sizeof(OBJECT_NAME_INFORMATION
) +
1191 sizeof(UNICODE_NULL
);
1193 /* Check if we were given enough space */
1194 if (*ReturnLength
> Length
) _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH
);
1197 * Now we will actually create the name. We work backwards because
1198 * it's easier to start off from the Name we have and walk up the
1199 * parent directories. We use the same logic as Name Length calculation.
1201 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
1202 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectNameInfo
+ *ReturnLength
);
1203 *--ObjectName
= UNICODE_NULL
;
1205 /* Check if the object is actually the Root directory */
1206 if (Object
== ObpRootDirectoryObject
)
1208 /* This is already the Root Directory, return "\\" */
1209 *--ObjectName
= OBJ_NAME_PATH_SEPARATOR
;
1210 ObjectNameInfo
->Name
.Length
= (USHORT
)NameSize
;
1211 ObjectNameInfo
->Name
.MaximumLength
= (USHORT
)(NameSize
+
1212 sizeof(UNICODE_NULL
));
1213 ObjectNameInfo
->Name
.Buffer
= ObjectName
;
1214 Status
= STATUS_SUCCESS
;
1218 /* Start by adding the Object's Name */
1219 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1220 LocalInfo
->Name
.Length
);
1221 RtlCopyMemory(ObjectName
,
1222 LocalInfo
->Name
.Buffer
,
1223 LocalInfo
->Name
.Length
);
1225 /* Now parse the Parent directories until we reach the top */
1226 ParentDirectory
= LocalInfo
->Directory
;
1227 while ((ParentDirectory
!= ObpRootDirectoryObject
) && (ParentDirectory
))
1229 /* Get the name information */
1230 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(
1231 OBJECT_TO_OBJECT_HEADER(ParentDirectory
));
1234 *(--ObjectName
) = OBJ_NAME_PATH_SEPARATOR
;
1236 /* Add the Parent Directory's Name */
1237 if (LocalInfo
&& LocalInfo
->Name
.Buffer
)
1240 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1241 LocalInfo
->Name
.Length
);
1242 RtlCopyMemory(ObjectName
,
1243 LocalInfo
->Name
.Buffer
,
1244 LocalInfo
->Name
.Length
);
1246 /* Move to next parent */
1247 ParentDirectory
= LocalInfo
->Directory
;
1251 /* Directory without a name, we add "..." */
1252 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1254 sizeof(UNICODE_NULL
));
1255 RtlCopyMemory(ObjectName
, L
"...", sizeof(L
"..."));
1260 /* Add Root Directory Name */
1261 *(--ObjectName
) = OBJ_NAME_PATH_SEPARATOR
;
1262 ObjectNameInfo
->Name
.Length
= (USHORT
)NameSize
;
1263 ObjectNameInfo
->Name
.MaximumLength
=
1264 (USHORT
)(NameSize
+ sizeof(UNICODE_NULL
));
1265 ObjectNameInfo
->Name
.Buffer
= ObjectName
;
1268 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1270 /* Return the exception code */
1271 Status
= _SEH2_GetExceptionCode();
1275 /* Return success */