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 ObpIsUnsecureName(IN PUNICODE_STRING ObjectName
,
362 IN BOOLEAN CaseInSensitive
)
365 PWSTR UnsecureBuffer
;
366 UNICODE_STRING UnsecureName
;
368 /* No unsecure names known, quit */
369 if (ObpUnsecureGlobalNamesBuffer
[0] == UNICODE_NULL
)
374 /* By default, we have a secure name */
376 /* We will browse the whole string */
377 UnsecureBuffer
= &ObpUnsecureGlobalNamesBuffer
[0];
380 /* Initialize the unicode string */
381 RtlInitUnicodeString(&UnsecureName
, UnsecureBuffer
);
382 /* We're at the end of the multisz string! */
383 if (UnsecureName
.Length
== 0)
389 * Does the unsecure name prefix the object name?
390 * If so, that's an unsecure name, and return so
392 if (RtlPrefixUnicodeString(&UnsecureName
, ObjectName
, CaseInSensitive
))
399 * Move to the next string. As a reminder, ObpUnsecureGlobalNamesBuffer is
400 * a multisz, so we move the string next to the current UNICODE_NULL char
402 UnsecureBuffer
= (PWSTR
)((ULONG_PTR
)UnsecureBuffer
+ UnsecureName
.Length
+ sizeof(UNICODE_NULL
));
405 /* Return our findings */
411 ObpLookupObjectName(IN HANDLE RootHandle OPTIONAL
,
412 IN OUT PUNICODE_STRING ObjectName
,
414 IN POBJECT_TYPE ObjectType
,
415 IN KPROCESSOR_MODE AccessMode
,
416 IN OUT PVOID ParseContext
,
417 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
418 IN PVOID InsertObject OPTIONAL
,
419 IN OUT PACCESS_STATE AccessState
,
420 OUT POBP_LOOKUP_CONTEXT LookupContext
,
421 OUT PVOID
*FoundObject
)
424 POBJECT_HEADER ObjectHeader
;
425 UNICODE_STRING ComponentName
, RemainingName
;
426 BOOLEAN Reparse
= FALSE
, SymLink
= FALSE
;
427 POBJECT_DIRECTORY Directory
= NULL
, ParentDirectory
= NULL
, RootDirectory
;
428 POBJECT_DIRECTORY ReferencedDirectory
= NULL
, ReferencedParentDirectory
= NULL
;
430 OB_PARSE_METHOD ParseRoutine
;
432 KPROCESSOR_MODE AccessCheckMode
;
434 POBJECT_HEADER_NAME_INFO ObjectNameInfo
;
435 ULONG MaxReparse
= 30;
437 OBTRACE(OB_NAMESPACE_DEBUG
,
438 "%s - Finding Object: %wZ. Expecting: %p\n",
443 /* Initialize starting state */
444 ObpInitializeLookupContext(LookupContext
);
446 Status
= STATUS_SUCCESS
;
449 /* Check if case-insensitivity is checked */
450 if (ObpCaseInsensitive
)
452 /* Check if the object type requests this */
453 if (!(ObjectType
) || (ObjectType
->TypeInfo
.CaseInsensitive
))
455 /* Add the flag to disable case sensitivity */
456 Attributes
|= OBJ_CASE_INSENSITIVE
;
460 /* Check if this is a access checks are being forced */
461 AccessCheckMode
= (Attributes
& OBJ_FORCE_ACCESS_CHECK
) ?
462 UserMode
: AccessMode
;
464 /* Check if we got a Root Directory */
467 /* We did. Reference it */
468 Status
= ObReferenceObjectByHandle(RootHandle
,
472 (PVOID
*)&RootDirectory
,
474 if (!NT_SUCCESS(Status
)) return Status
;
477 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(RootDirectory
);
479 /* The name cannot start with a separator, unless this is a file */
480 if ((ObjectName
->Buffer
) &&
481 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
) &&
482 (ObjectHeader
->Type
!= IoFileObjectType
))
484 /* The syntax is bad, so fail this request */
485 ObDereferenceObject(RootDirectory
);
486 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
489 /* Don't parse a Directory */
490 if (ObjectHeader
->Type
!= ObpDirectoryObjectType
)
492 /* Make sure the Object Type has a parse routine */
493 ParseRoutine
= ObjectHeader
->Type
->TypeInfo
.ParseProcedure
;
496 /* We can't parse a name if we don't have a parse routine */
497 ObDereferenceObject(RootDirectory
);
498 return STATUS_INVALID_HANDLE
;
501 /* Set default parse count */
507 /* Start with the full name */
508 RemainingName
= *ObjectName
;
510 /* Call the Parse Procedure */
511 ObpCalloutStart(&CalloutIrql
);
512 Status
= ParseRoutine(RootDirectory
,
522 ObpCalloutEnd(CalloutIrql
, "Parse", ObjectHeader
->Type
, Object
);
524 /* Check for success or failure, so not reparse */
525 if ((Status
!= STATUS_REPARSE
) &&
526 (Status
!= STATUS_REPARSE_OBJECT
))
528 /* Check for failure */
529 if (!NT_SUCCESS(Status
))
531 /* Parse routine might not have cleared this, do it */
536 /* Modify status to reflect failure inside Ob */
537 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
540 /* We're done, return the status and object */
541 *FoundObject
= Object
;
542 ObDereferenceObject(RootDirectory
);
545 else if ((!ObjectName
->Length
) ||
546 (!ObjectName
->Buffer
) ||
547 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
549 /* Reparsed to the root directory, so start over */
550 ObDereferenceObject(RootDirectory
);
551 RootDirectory
= ObpRootDirectoryObject
;
553 /* Don't use this anymore, since we're starting at root */
557 else if (--MaxReparse
)
559 /* Try reparsing again */
564 /* Reparsed too many times */
565 ObDereferenceObject(RootDirectory
);
567 /* Return the object and normalized status */
568 *FoundObject
= Object
;
569 if (!Object
) Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
574 else if (!(ObjectName
->Length
) || !(ObjectName
->Buffer
))
576 /* Just return the Root Directory if we didn't get a name */
577 Status
= ObReferenceObjectByPointer(RootDirectory
,
581 if (NT_SUCCESS(Status
)) Object
= RootDirectory
;
583 /* Remove the first reference we added and return the object */
584 ObDereferenceObject(RootDirectory
);
585 *FoundObject
= Object
;
591 /* We did not get a Root Directory, so use the root */
592 RootDirectory
= ObpRootDirectoryObject
;
594 /* It must start with a path separator */
595 if (!(ObjectName
->Length
) ||
596 !(ObjectName
->Buffer
) ||
597 (ObjectName
->Buffer
[0] != OBJ_NAME_PATH_SEPARATOR
))
599 /* This name is invalid, so fail */
600 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
603 /* Check if the name is only the path separator */
604 if (ObjectName
->Length
== sizeof(OBJ_NAME_PATH_SEPARATOR
))
606 /* So the caller only wants the root directory; do we have one? */
609 /* This must be the first time we're creating it... right? */
612 /* Yes, so return it to ObInsert so that it can create it */
613 Status
= ObReferenceObjectByPointer(InsertObject
,
617 if (NT_SUCCESS(Status
)) *FoundObject
= InsertObject
;
622 /* This should never really happen */
624 return STATUS_INVALID_PARAMETER
;
629 /* We do have the root directory, so just return it */
630 Status
= ObReferenceObjectByPointer(RootDirectory
,
634 if (NT_SUCCESS(Status
)) *FoundObject
= RootDirectory
;
641 /* FIXME: Check if we have a device map */
643 /* Check if this is a possible DOS name */
644 if (!((ULONG_PTR
)(ObjectName
->Buffer
) & 7))
647 * This could be one. Does it match the prefix?
648 * Note that as an optimization, the match is done as 64-bit
649 * compare since the prefix is "\??\" which is exactly 8 bytes.
651 * In the second branch, we test for "\??" which is also valid.
652 * This time, we use a 32-bit compare followed by a Unicode
653 * character compare (16-bit), since the sum is 6 bytes.
655 if ((ObjectName
->Length
>= ObpDosDevicesShortName
.Length
) &&
656 (*(PULONGLONG
)(ObjectName
->Buffer
) ==
657 ObpDosDevicesShortNamePrefix
.Alignment
.QuadPart
))
661 else if ((ObjectName
->Length
== ObpDosDevicesShortName
.Length
-
663 (*(PULONG
)(ObjectName
->Buffer
) ==
664 ObpDosDevicesShortNameRoot
.Alignment
.LowPart
) &&
665 (*((PWCHAR
)(ObjectName
->Buffer
) + 2) ==
666 (WCHAR
)(ObpDosDevicesShortNameRoot
.Alignment
.HighPart
)))
674 /* Check if we were reparsing a symbolic link */
683 while (Reparse
&& MaxReparse
)
686 RemainingName
= *ObjectName
;
688 /* Disable reparsing again */
691 /* Start parse loop */
697 /* Check if the name starts with a path separator */
698 if ((RemainingName
.Length
) &&
699 (RemainingName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
701 /* Skip the path separator */
702 RemainingName
.Buffer
++;
703 RemainingName
.Length
-= sizeof(OBJ_NAME_PATH_SEPARATOR
);
706 /* Find the next Part Name */
707 ComponentName
= RemainingName
;
708 while (RemainingName
.Length
)
710 /* Break if we found the \ ending */
711 if (RemainingName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
) break;
714 RemainingName
.Buffer
++;
715 RemainingName
.Length
-= sizeof(OBJ_NAME_PATH_SEPARATOR
);
718 /* Get its size and make sure it's valid */
719 ComponentName
.Length
-= RemainingName
.Length
;
720 if (!ComponentName
.Length
)
722 /* Invalid size, fail */
723 Status
= STATUS_OBJECT_NAME_INVALID
;
727 /* Check if we're in the root */
728 if (!Directory
) Directory
= RootDirectory
;
730 /* Check if this is a user-mode call that needs to traverse */
731 if ((AccessCheckMode
!= KernelMode
) &&
732 !(AccessState
->Flags
& TOKEN_HAS_TRAVERSE_PRIVILEGE
))
734 /* We shouldn't have referenced a directory yet */
735 ASSERT(ReferencedDirectory
== NULL
);
737 /* Reference the directory */
738 ObReferenceObject(Directory
);
739 ReferencedDirectory
= Directory
;
741 /* Check if we have a parent directory */
744 /* Check for traverse access */
745 if (!ObpCheckTraverseAccess(ParentDirectory
,
752 /* We don't have it, fail */
758 /* Check if we don't have a remaining name yet */
759 if (!RemainingName
.Length
)
761 /* Check if we don't have a referenced directory yet */
762 if (!ReferencedDirectory
)
765 ObReferenceObject(Directory
);
766 ReferencedDirectory
= Directory
;
769 /* Check if we are inserting an object */
772 /* Lock the directory */
773 ObpAcquireDirectoryLockExclusive(Directory
, LookupContext
);
778 Object
= ObpLookupEntryDirectory(Directory
,
781 InsertObject
? FALSE
: TRUE
,
785 /* We didn't find it... do we still have a path? */
786 if (RemainingName
.Length
)
788 /* Then tell the caller the path wasn't found */
789 Status
= STATUS_OBJECT_PATH_NOT_FOUND
;
792 else if (!InsertObject
)
794 /* Otherwise, we have a path, but the name isn't valid */
795 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
799 /* Check create access for the object */
800 if (!ObCheckCreateObjectAccess(Directory
,
801 ObjectType
== ObpDirectoryObjectType
?
802 DIRECTORY_CREATE_SUBDIRECTORY
:
803 DIRECTORY_CREATE_OBJECT
,
810 /* We don't have create access, fail */
814 /* Get the object header */
815 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(InsertObject
);
818 * Deny object creation if:
819 * That's a section object or a symbolic link
820 * Which isn't in the same section that root directory
821 * That doesn't have the SeCreateGlobalPrivilege
822 * And that is not a known unsecure name
824 if (RootDirectory
->SessionId
!= -1)
826 if (ObjectHeader
->Type
== MmSectionObjectType
||
827 ObjectHeader
->Type
== ObpSymbolicLinkObjectType
)
829 if (RootDirectory
->SessionId
!= PsGetCurrentProcessSessionId() &&
830 !SeSinglePrivilegeCheck(SeCreateGlobalPrivilege
, AccessCheckMode
) &&
831 !ObpIsUnsecureName(&ComponentName
, BooleanFlagOn(Attributes
, OBJ_CASE_INSENSITIVE
)))
833 Status
= STATUS_ACCESS_DENIED
;
839 /* Create Object Name */
840 NewName
= ExAllocatePoolWithTag(PagedPool
,
841 ComponentName
.Length
,
844 !(ObpInsertEntryDirectory(Directory
,
848 /* Either couldn't allocate the name, or insert failed */
849 if (NewName
) ExFreePoolWithTag(NewName
, OB_NAME_TAG
);
851 /* Fail due to memory reasons */
852 Status
= STATUS_INSUFFICIENT_RESOURCES
;
856 /* Reference newly to be inserted object */
857 ObReferenceObject(InsertObject
);
859 /* Get the name information */
860 ObjectNameInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
862 /* Reference the directory */
863 ObReferenceObject(Directory
);
866 RtlCopyMemory(NewName
,
867 ComponentName
.Buffer
,
868 ComponentName
.Length
);
870 /* Check if we had an old name */
871 if (ObjectNameInfo
->Name
.Buffer
)
874 ExFreePoolWithTag(ObjectNameInfo
->Name
.Buffer
, OB_NAME_TAG
);
878 ObjectNameInfo
->Name
.Buffer
= NewName
;
879 ObjectNameInfo
->Name
.Length
= ComponentName
.Length
;
880 ObjectNameInfo
->Name
.MaximumLength
= ComponentName
.Length
;
882 /* Return Status and the Expected Object */
883 Status
= STATUS_SUCCESS
;
884 Object
= InsertObject
;
886 /* Get out of here */
891 /* We found it, so now get its header */
892 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
895 * Check for a parse Procedure, but don't bother to parse for an insert
896 * unless it's a Symbolic Link, in which case we MUST parse
898 ParseRoutine
= ObjectHeader
->Type
->TypeInfo
.ParseProcedure
;
899 if ((ParseRoutine
) &&
900 (!(InsertObject
) || (ParseRoutine
== ObpParseSymbolicLink
)))
902 /* Use the Root Directory next time */
905 /* Increment the pointer count */
906 InterlockedExchangeAddSizeT(&ObjectHeader
->PointerCount
, 1);
908 /* Cleanup from the first lookup */
909 ObpReleaseLookupContext(LookupContext
);
911 /* Check if we have a referenced directory */
912 if (ReferencedDirectory
)
914 /* We do, dereference it */
915 ObDereferenceObject(ReferencedDirectory
);
916 ReferencedDirectory
= NULL
;
919 /* Check if we have a referenced parent directory */
920 if (ReferencedParentDirectory
)
922 /* We do, dereference it */
923 ObDereferenceObject(ReferencedParentDirectory
);
924 ReferencedParentDirectory
= NULL
;
927 /* Call the Parse Procedure */
928 ObpCalloutStart(&CalloutIrql
);
929 Status
= ParseRoutine(Object
,
939 ObpCalloutEnd(CalloutIrql
, "Parse", ObjectHeader
->Type
, Object
);
941 /* Remove our extra reference */
942 ObDereferenceObject(&ObjectHeader
->Body
);
944 /* Check if we have to reparse */
945 if ((Status
== STATUS_REPARSE
) ||
946 (Status
== STATUS_REPARSE_OBJECT
))
957 /* Start over from root if we got sent back there */
958 if ((Status
== STATUS_REPARSE_OBJECT
) ||
959 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
961 /* Check if we got a root directory */
964 /* Stop using it, because we have a new directory now */
965 ObDereferenceObject(RootDirectory
);
970 ParentDirectory
= NULL
;
971 RootDirectory
= ObpRootDirectoryObject
;
973 /* Check for reparse status */
974 if (Status
== STATUS_REPARSE_OBJECT
)
976 /* Don't reparse again */
979 /* Did we actually get an object to which to reparse? */
982 /* We didn't, so set a failure status */
983 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
987 /* We did, so we're free to parse the new object */
993 /* This is a symbolic link */
998 else if (RootDirectory
== ObpRootDirectoryObject
)
1000 /* We got STATUS_REPARSE but are at the Root Directory */
1002 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1006 else if (!NT_SUCCESS(Status
))
1013 /* We didn't reparse but we didn't find the Object Either */
1014 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1017 /* Break out of the loop */
1022 /* No parse routine...do we still have a remaining name? */
1023 if (!RemainingName
.Length
)
1025 /* Are we creating an object? */
1028 /* Check if this is a user-mode call that needs to traverse */
1029 if ((AccessCheckMode
!= KernelMode
) &&
1030 !(AccessState
->Flags
& TOKEN_HAS_TRAVERSE_PRIVILEGE
))
1032 /* Check if we can get it */
1033 if (!ObpCheckTraverseAccess(Directory
,
1040 /* We don't have access, fail */
1046 /* Reference the Object */
1047 Status
= ObReferenceObjectByPointer(Object
,
1051 if (!NT_SUCCESS(Status
)) Object
= NULL
;
1054 /* And get out of the reparse loop */
1059 /* We still have a name; check if this is a directory object */
1060 if (ObjectHeader
->Type
== ObpDirectoryObjectType
)
1062 /* Check if we have a referenced parent directory */
1063 if (ReferencedParentDirectory
)
1065 /* Dereference it */
1066 ObDereferenceObject(ReferencedParentDirectory
);
1069 /* Restart the lookup from this directory */
1070 ReferencedParentDirectory
= ReferencedDirectory
;
1071 ParentDirectory
= Directory
;
1073 ReferencedDirectory
= NULL
;
1077 /* We still have a name, but no parse routine for it */
1078 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
1087 /* Check if we failed */
1088 if (!NT_SUCCESS(Status
))
1090 /* Cleanup after lookup */
1091 ObpReleaseLookupContext(LookupContext
);
1094 /* Check if we have a device map and dereference it if so */
1095 //if (DeviceMap) ObfDereferenceDeviceMap(DeviceMap);
1097 /* Check if we have a referenced directory and dereference it if so */
1098 if (ReferencedDirectory
) ObDereferenceObject(ReferencedDirectory
);
1100 /* Check if we have a referenced parent directory */
1101 if (ReferencedParentDirectory
)
1103 /* We do, dereference it */
1104 ObDereferenceObject(ReferencedParentDirectory
);
1107 /* Set the found object and check if we got one */
1108 *FoundObject
= Object
;
1111 /* Nothing was found. Did we reparse or get success? */
1112 if ((Status
== STATUS_REPARSE
) || (NT_SUCCESS(Status
)))
1114 /* Set correct failure */
1115 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1119 /* Check if we had a root directory */
1120 if (RootHandle
) ObDereferenceObject(RootDirectory
);
1122 /* Return status to caller */
1123 OBTRACE(OB_NAMESPACE_DEBUG
,
1124 "%s - Found Object: %p. Expected: %p\n",
1131 /* PUBLIC FUNCTIONS *********************************************************/
1135 ObQueryNameString(IN PVOID Object
,
1136 OUT POBJECT_NAME_INFORMATION ObjectNameInfo
,
1138 OUT PULONG ReturnLength
)
1140 POBJECT_HEADER_NAME_INFO LocalInfo
;
1141 POBJECT_HEADER ObjectHeader
;
1142 POBJECT_DIRECTORY ParentDirectory
;
1145 BOOLEAN ObjectIsNamed
;
1146 NTSTATUS Status
= STATUS_SUCCESS
;
1148 /* Get the Kernel Meta-Structures */
1149 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
1150 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
1152 /* Check if a Query Name Procedure is available */
1153 if (ObjectHeader
->Type
->TypeInfo
.QueryNameProcedure
)
1155 /* Call the procedure inside SEH */
1156 ObjectIsNamed
= ((LocalInfo
) && (LocalInfo
->Name
.Length
> 0));
1160 Status
= ObjectHeader
->Type
->TypeInfo
.QueryNameProcedure(Object
,
1167 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1169 /* Return the exception code */
1170 Status
= _SEH2_GetExceptionCode();
1177 /* Check if the object doesn't even have a name */
1178 if (!(LocalInfo
) || !(LocalInfo
->Name
.Buffer
))
1180 Status
= STATUS_SUCCESS
;
1184 /* We're returning the name structure */
1185 *ReturnLength
= sizeof(OBJECT_NAME_INFORMATION
);
1187 /* Check if we were given enough space */
1188 if (*ReturnLength
> Length
)
1190 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1194 /* Return an empty buffer */
1195 RtlInitEmptyUnicodeString(&ObjectNameInfo
->Name
, NULL
, 0);
1198 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1200 /* Return the exception code */
1201 Status
= _SEH2_GetExceptionCode();
1209 * Find the size needed for the name. We won't do
1210 * this during the Name Creation loop because we want
1211 * to let the caller know that the buffer isn't big
1212 * enough right at the beginning, not work our way through
1213 * and find out at the end
1217 if (Object
== ObpRootDirectoryObject
)
1219 /* Size of the '\' string */
1220 NameSize
= sizeof(OBJ_NAME_PATH_SEPARATOR
);
1224 /* Get the Object Directory and add name of Object */
1225 ParentDirectory
= LocalInfo
->Directory
;
1226 NameSize
= sizeof(OBJ_NAME_PATH_SEPARATOR
) + LocalInfo
->Name
.Length
;
1228 /* Loop inside the directory to get the top-most one (meaning root) */
1229 while ((ParentDirectory
!= ObpRootDirectoryObject
) && (ParentDirectory
))
1231 /* Get the Name Information */
1232 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(
1233 OBJECT_TO_OBJECT_HEADER(ParentDirectory
));
1235 /* Add the size of the Directory Name */
1236 if (LocalInfo
&& LocalInfo
->Directory
)
1238 /* Size of the '\' string + Directory Name */
1239 NameSize
+= sizeof(OBJ_NAME_PATH_SEPARATOR
) +
1240 LocalInfo
->Name
.Length
;
1242 /* Move to next parent Directory */
1243 ParentDirectory
= LocalInfo
->Directory
;
1247 /* Directory with no name. We append "...\" */
1248 NameSize
+= sizeof(L
"...") + sizeof(OBJ_NAME_PATH_SEPARATOR
);
1254 /* Finally, add the name of the structure and the null char */
1255 *ReturnLength
= NameSize
+
1256 sizeof(OBJECT_NAME_INFORMATION
) +
1257 sizeof(UNICODE_NULL
);
1259 /* Check if we were given enough space */
1260 if (*ReturnLength
> Length
) _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH
);
1263 * Now we will actually create the name. We work backwards because
1264 * it's easier to start off from the Name we have and walk up the
1265 * parent directories. We use the same logic as Name Length calculation.
1267 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
1268 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectNameInfo
+ *ReturnLength
);
1269 *--ObjectName
= UNICODE_NULL
;
1271 /* Check if the object is actually the Root directory */
1272 if (Object
== ObpRootDirectoryObject
)
1274 /* This is already the Root Directory, return "\\" */
1275 *--ObjectName
= OBJ_NAME_PATH_SEPARATOR
;
1276 ObjectNameInfo
->Name
.Length
= (USHORT
)NameSize
;
1277 ObjectNameInfo
->Name
.MaximumLength
= (USHORT
)(NameSize
+
1278 sizeof(UNICODE_NULL
));
1279 ObjectNameInfo
->Name
.Buffer
= ObjectName
;
1280 Status
= STATUS_SUCCESS
;
1284 /* Start by adding the Object's Name */
1285 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1286 LocalInfo
->Name
.Length
);
1287 RtlCopyMemory(ObjectName
,
1288 LocalInfo
->Name
.Buffer
,
1289 LocalInfo
->Name
.Length
);
1291 /* Now parse the Parent directories until we reach the top */
1292 ParentDirectory
= LocalInfo
->Directory
;
1293 while ((ParentDirectory
!= ObpRootDirectoryObject
) && (ParentDirectory
))
1295 /* Get the name information */
1296 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(
1297 OBJECT_TO_OBJECT_HEADER(ParentDirectory
));
1300 *(--ObjectName
) = OBJ_NAME_PATH_SEPARATOR
;
1302 /* Add the Parent Directory's Name */
1303 if (LocalInfo
&& LocalInfo
->Name
.Buffer
)
1306 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1307 LocalInfo
->Name
.Length
);
1308 RtlCopyMemory(ObjectName
,
1309 LocalInfo
->Name
.Buffer
,
1310 LocalInfo
->Name
.Length
);
1312 /* Move to next parent */
1313 ParentDirectory
= LocalInfo
->Directory
;
1317 /* Directory without a name, we add "..." */
1318 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1320 sizeof(UNICODE_NULL
));
1321 RtlCopyMemory(ObjectName
, L
"...", sizeof(L
"..."));
1326 /* Add Root Directory Name */
1327 *(--ObjectName
) = OBJ_NAME_PATH_SEPARATOR
;
1328 ObjectNameInfo
->Name
.Length
= (USHORT
)NameSize
;
1329 ObjectNameInfo
->Name
.MaximumLength
=
1330 (USHORT
)(NameSize
+ sizeof(UNICODE_NULL
));
1331 ObjectNameInfo
->Name
.Buffer
= ObjectName
;
1334 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1336 /* Return the exception code */
1337 Status
= _SEH2_GetExceptionCode();
1341 /* Return success */