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 ObpGetDosDevicesProtection(OUT PSECURITY_DESCRIPTOR SecurityDescriptor
)
46 /* Initialize the SD */
47 Status
= RtlCreateSecurityDescriptor(SecurityDescriptor
, SECURITY_DESCRIPTOR_REVISION
);
48 ASSERT(NT_SUCCESS(Status
));
50 if (ObpProtectionMode
& 1)
52 AclSize
= sizeof(ACL
) +
53 sizeof(ACE
) + RtlLengthSid(SeWorldSid
) +
54 sizeof(ACE
) + RtlLengthSid(SeLocalSystemSid
) +
55 sizeof(ACE
) + RtlLengthSid(SeWorldSid
) +
56 sizeof(ACE
) + RtlLengthSid(SeAliasAdminsSid
) +
57 sizeof(ACE
) + RtlLengthSid(SeLocalSystemSid
) +
58 sizeof(ACE
) + RtlLengthSid(SeCreatorOwnerSid
);
60 /* Allocate the ACL */
61 Dacl
= ExAllocatePoolWithTag(PagedPool
, AclSize
, 'lcaD');
64 return STATUS_INSUFFICIENT_RESOURCES
;
67 /* Initialize the DACL */
68 Status
= RtlCreateAcl(Dacl
, AclSize
, ACL_REVISION
);
69 ASSERT(NT_SUCCESS(Status
));
72 Status
= RtlAddAccessAllowedAce(Dacl
,
74 GENERIC_READ
| GENERIC_EXECUTE
,
76 ASSERT(NT_SUCCESS(Status
));
78 Status
= RtlAddAccessAllowedAce(Dacl
,
82 ASSERT(NT_SUCCESS(Status
));
84 Status
= RtlAddAccessAllowedAceEx(Dacl
,
86 INHERIT_ONLY_ACE
| CONTAINER_INHERIT_ACE
| OBJECT_INHERIT_ACE
,
89 ASSERT(NT_SUCCESS(Status
));
91 Status
= RtlAddAccessAllowedAceEx(Dacl
,
93 INHERIT_ONLY_ACE
| CONTAINER_INHERIT_ACE
| OBJECT_INHERIT_ACE
,
96 ASSERT(NT_SUCCESS(Status
));
98 Status
= RtlAddAccessAllowedAceEx(Dacl
,
100 INHERIT_ONLY_ACE
| CONTAINER_INHERIT_ACE
| OBJECT_INHERIT_ACE
,
103 ASSERT(NT_SUCCESS(Status
));
105 Status
= RtlAddAccessAllowedAceEx(Dacl
,
107 INHERIT_ONLY_ACE
| CONTAINER_INHERIT_ACE
| OBJECT_INHERIT_ACE
,
110 ASSERT(NT_SUCCESS(Status
));
114 AclSize
= sizeof(ACL
) +
115 sizeof(ACE
) + RtlLengthSid(SeLocalSystemSid
) +
116 sizeof(ACE
) + RtlLengthSid(SeWorldSid
) +
117 sizeof(ACE
) + RtlLengthSid(SeLocalSystemSid
);
119 /* Allocate the ACL */
120 Dacl
= ExAllocatePoolWithTag(PagedPool
, AclSize
, 'lcaD');
123 return STATUS_INSUFFICIENT_RESOURCES
;
126 /* Initialize the DACL */
127 Status
= RtlCreateAcl(Dacl
, AclSize
, ACL_REVISION
);
128 ASSERT(NT_SUCCESS(Status
));
131 Status
= RtlAddAccessAllowedAce(Dacl
,
133 GENERIC_READ
| GENERIC_EXECUTE
| GENERIC_WRITE
,
135 ASSERT(NT_SUCCESS(Status
));
137 Status
= RtlAddAccessAllowedAce(Dacl
,
141 ASSERT(NT_SUCCESS(Status
));
143 Status
= RtlAddAccessAllowedAceEx(Dacl
,
145 INHERIT_ONLY_ACE
| CONTAINER_INHERIT_ACE
| OBJECT_INHERIT_ACE
,
148 ASSERT(NT_SUCCESS(Status
));
151 /* Attach the DACL to the SD */
152 Status
= RtlSetDaclSecurityDescriptor(SecurityDescriptor
, TRUE
, Dacl
, FALSE
);
153 ASSERT(NT_SUCCESS(Status
));
155 return STATUS_SUCCESS
;
161 ObpFreeDosDevicesProtection(OUT PSECURITY_DESCRIPTOR SecurityDescriptor
)
165 BOOLEAN DaclPresent
, DaclDefaulted
;
167 Status
= RtlGetDaclSecurityDescriptor(SecurityDescriptor
, &DaclPresent
, &Dacl
, &DaclDefaulted
);
168 ASSERT(NT_SUCCESS(Status
));
170 ASSERT(Dacl
!= NULL
);
171 ExFreePoolWithTag(Dacl
, 'lcaD');
177 ObpCreateDosDevicesDirectory(VOID
)
179 OBJECT_ATTRIBUTES ObjectAttributes
;
180 UNICODE_STRING RootName
, TargetName
, LinkName
;
181 HANDLE Handle
, SymHandle
;
182 SECURITY_DESCRIPTOR DosDevicesSD
;
186 * Enable LUID mappings only if not explicitely disabled
187 * and if protection mode is set
189 if (ObpProtectionMode
== 0 || ObpLUIDDeviceMapsDisabled
!= 0)
190 ObpLUIDDeviceMapsEnabled
= 0;
192 ObpLUIDDeviceMapsEnabled
= 1;
194 /* Create a custom security descriptor for the global DosDevices directory */
195 Status
= ObpGetDosDevicesProtection(&DosDevicesSD
);
196 if (!NT_SUCCESS(Status
))
199 /* Create the global DosDevices directory \?? */
200 RtlInitUnicodeString(&RootName
, L
"\\GLOBAL??");
201 InitializeObjectAttributes(&ObjectAttributes
,
206 Status
= NtCreateDirectoryObject(&Handle
,
207 DIRECTORY_ALL_ACCESS
,
209 if (!NT_SUCCESS(Status
))
212 /* Create the system device map */
213 Status
= ObSetDeviceMap(NULL
, Handle
);
214 if (!NT_SUCCESS(Status
))
217 /*********************************************\
218 |*** HACK until we support device mappings ***|
219 |*** Add a symlink \??\ <--> \GLOBAL??\ ***|
220 \*********************************************/
221 RtlInitUnicodeString(&LinkName
, L
"\\??");
222 InitializeObjectAttributes(&ObjectAttributes
,
227 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
228 SYMBOLIC_LINK_ALL_ACCESS
,
231 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
232 /*********************************************\
233 \*********************************************/
235 // FIXME: Create a device mapping for the global \?? directory
238 * Initialize the \??\GLOBALROOT symbolic link
239 * pointing to the root directory \ .
241 RtlInitUnicodeString(&LinkName
, L
"GLOBALROOT");
242 RtlInitUnicodeString(&TargetName
, L
"");
243 InitializeObjectAttributes(&ObjectAttributes
,
248 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
249 SYMBOLIC_LINK_ALL_ACCESS
,
252 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
255 * Initialize the \??\Global symbolic link pointing to the global
256 * DosDevices directory \?? . It is used to access the global \??
257 * by user-mode components which, by default, use a per-session
258 * DosDevices directory.
260 RtlInitUnicodeString(&LinkName
, L
"Global");
261 InitializeObjectAttributes(&ObjectAttributes
,
266 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
267 SYMBOLIC_LINK_ALL_ACCESS
,
270 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
272 /* Close the directory handle */
274 if (!NT_SUCCESS(Status
))
278 * Initialize the \DosDevices symbolic link pointing to the global
279 * DosDevices directory \?? , for backward compatibility with
280 * Windows NT-2000 systems.
282 RtlCreateUnicodeString(&LinkName
, L
"\\DosDevices");
283 RtlInitUnicodeString(&RootName
, (PCWSTR
)&ObpDosDevicesShortNameRoot
);
284 InitializeObjectAttributes(&ObjectAttributes
,
289 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
290 SYMBOLIC_LINK_ALL_ACCESS
,
293 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
296 ObpFreeDosDevicesProtection(&DosDevicesSD
);
303 * @name ObpDeleteNameCheck
305 * The ObpDeleteNameCheck routine checks if a named object should be
306 * removed from the object directory namespace.
309 * Pointer to the object to check for possible removal.
313 * @remarks An object is removed if the following 4 criteria are met:
314 * 1) The object has 0 handles open
315 * 2) The object is in the directory namespace and has a name
316 * 3) The object is not permanent
321 ObpDeleteNameCheck(IN PVOID Object
)
323 POBJECT_HEADER ObjectHeader
;
324 OBP_LOOKUP_CONTEXT Context
;
325 POBJECT_HEADER_NAME_INFO ObjectNameInfo
;
326 POBJECT_TYPE ObjectType
;
327 PVOID Directory
= NULL
;
329 /* Get object structures */
330 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
331 ObjectNameInfo
= ObpReferenceNameInfo(ObjectHeader
);
332 ObjectType
= ObjectHeader
->Type
;
335 * Check if the handle count is 0, if the object is named,
336 * and if the object isn't a permanent object.
338 if (!(ObjectHeader
->HandleCount
) &&
340 (ObjectNameInfo
->Name
.Length
) &&
341 (ObjectNameInfo
->Directory
) &&
342 !(ObjectHeader
->Flags
& OB_FLAG_PERMANENT
))
344 /* Setup a lookup context */
345 ObpInitializeLookupContext(&Context
);
347 /* Lock the directory */
348 ObpAcquireDirectoryLockExclusive(ObjectNameInfo
->Directory
, &Context
);
351 Object
= ObpLookupEntryDirectory(ObjectNameInfo
->Directory
,
352 &ObjectNameInfo
->Name
,
358 /* Lock the object */
359 ObpAcquireObjectLock(ObjectHeader
);
361 /* Make sure we can still delete the object */
362 if (!(ObjectHeader
->HandleCount
) &&
363 !(ObjectHeader
->Flags
& OB_FLAG_PERMANENT
))
365 /* First delete it from the directory */
366 ObpDeleteEntryDirectory(&Context
);
368 /* Check if this is a symbolic link */
369 if (ObjectType
== ObpSymbolicLinkObjectType
)
371 /* Remove internal name */
372 ObpDeleteSymbolicLinkName(Object
);
375 /* Check if the kernel exclusive is set */
376 ObjectNameInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
377 if ((ObjectNameInfo
) &&
378 (ObjectNameInfo
->QueryReferences
& OB_FLAG_KERNEL_EXCLUSIVE
))
380 /* Remove protection flag */
381 InterlockedExchangeAdd((PLONG
)&ObjectNameInfo
->QueryReferences
,
382 -OB_FLAG_KERNEL_EXCLUSIVE
);
385 /* Get the directory */
386 Directory
= ObjectNameInfo
->Directory
;
389 /* Release the lock */
390 ObpReleaseObjectLock(ObjectHeader
);
393 /* Cleanup after lookup */
394 ObpReleaseLookupContext(&Context
);
396 /* Remove another query reference since we added one on top */
397 ObpDereferenceNameInfo(ObjectNameInfo
);
399 /* Check if we were inserted in a directory */
402 /* We were, so first remove the extra reference we had added */
403 ObpDereferenceNameInfo(ObjectNameInfo
);
405 /* Now dereference the object as well */
406 ObDereferenceObject(Object
);
411 /* Remove the reference we added */
412 ObpDereferenceNameInfo(ObjectNameInfo
);
418 ObpIsUnsecureName(IN PUNICODE_STRING ObjectName
,
419 IN BOOLEAN CaseInSensitive
)
422 PWSTR UnsecureBuffer
;
423 UNICODE_STRING UnsecureName
;
425 /* No unsecure names known, quit */
426 if (ObpUnsecureGlobalNamesBuffer
[0] == UNICODE_NULL
)
431 /* By default, we have a secure name */
433 /* We will browse the whole string */
434 UnsecureBuffer
= &ObpUnsecureGlobalNamesBuffer
[0];
437 /* Initialize the unicode string */
438 RtlInitUnicodeString(&UnsecureName
, UnsecureBuffer
);
439 /* We're at the end of the multisz string! */
440 if (UnsecureName
.Length
== 0)
446 * Does the unsecure name prefix the object name?
447 * If so, that's an unsecure name, and return so
449 if (RtlPrefixUnicodeString(&UnsecureName
, ObjectName
, CaseInSensitive
))
456 * Move to the next string. As a reminder, ObpUnsecureGlobalNamesBuffer is
457 * a multisz, so we move the string next to the current UNICODE_NULL char
459 UnsecureBuffer
= (PWSTR
)((ULONG_PTR
)UnsecureBuffer
+ UnsecureName
.Length
+ sizeof(UNICODE_NULL
));
462 /* Return our findings */
468 ObpLookupObjectName(IN HANDLE RootHandle OPTIONAL
,
469 IN OUT PUNICODE_STRING ObjectName
,
471 IN POBJECT_TYPE ObjectType
,
472 IN KPROCESSOR_MODE AccessMode
,
473 IN OUT PVOID ParseContext
,
474 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
475 IN PVOID InsertObject OPTIONAL
,
476 IN OUT PACCESS_STATE AccessState
,
477 OUT POBP_LOOKUP_CONTEXT LookupContext
,
478 OUT PVOID
*FoundObject
)
481 POBJECT_HEADER ObjectHeader
;
482 UNICODE_STRING ComponentName
, RemainingName
;
483 BOOLEAN Reparse
= FALSE
, SymLink
= FALSE
;
484 POBJECT_DIRECTORY Directory
= NULL
, ParentDirectory
= NULL
, RootDirectory
;
485 POBJECT_DIRECTORY ReferencedDirectory
= NULL
, ReferencedParentDirectory
= NULL
;
487 OB_PARSE_METHOD ParseRoutine
;
489 KPROCESSOR_MODE AccessCheckMode
;
491 POBJECT_HEADER_NAME_INFO ObjectNameInfo
;
492 ULONG MaxReparse
= 30;
494 OBTRACE(OB_NAMESPACE_DEBUG
,
495 "%s - Finding Object: %wZ. Expecting: %p\n",
500 /* Initialize starting state */
501 ObpInitializeLookupContext(LookupContext
);
503 Status
= STATUS_SUCCESS
;
506 /* Check if case-insensitivity is checked */
507 if (ObpCaseInsensitive
)
509 /* Check if the object type requests this */
510 if (!(ObjectType
) || (ObjectType
->TypeInfo
.CaseInsensitive
))
512 /* Add the flag to disable case sensitivity */
513 Attributes
|= OBJ_CASE_INSENSITIVE
;
517 /* Check if this is a access checks are being forced */
518 AccessCheckMode
= (Attributes
& OBJ_FORCE_ACCESS_CHECK
) ?
519 UserMode
: AccessMode
;
521 /* Check if we got a Root Directory */
524 /* We did. Reference it */
525 Status
= ObReferenceObjectByHandle(RootHandle
,
529 (PVOID
*)&RootDirectory
,
531 if (!NT_SUCCESS(Status
)) return Status
;
534 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(RootDirectory
);
536 /* The name cannot start with a separator, unless this is a file */
537 if ((ObjectName
->Buffer
) &&
538 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
) &&
539 (ObjectHeader
->Type
!= IoFileObjectType
))
541 /* The syntax is bad, so fail this request */
542 ObDereferenceObject(RootDirectory
);
543 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
546 /* Don't parse a Directory */
547 if (ObjectHeader
->Type
!= ObpDirectoryObjectType
)
549 /* Make sure the Object Type has a parse routine */
550 ParseRoutine
= ObjectHeader
->Type
->TypeInfo
.ParseProcedure
;
553 /* We can't parse a name if we don't have a parse routine */
554 ObDereferenceObject(RootDirectory
);
555 return STATUS_INVALID_HANDLE
;
558 /* Set default parse count */
564 /* Start with the full name */
565 RemainingName
= *ObjectName
;
567 /* Call the Parse Procedure */
568 ObpCalloutStart(&CalloutIrql
);
569 Status
= ParseRoutine(RootDirectory
,
579 ObpCalloutEnd(CalloutIrql
, "Parse", ObjectHeader
->Type
, Object
);
581 /* Check for success or failure, so not reparse */
582 if ((Status
!= STATUS_REPARSE
) &&
583 (Status
!= STATUS_REPARSE_OBJECT
))
585 /* Check for failure */
586 if (!NT_SUCCESS(Status
))
588 /* Parse routine might not have cleared this, do it */
593 /* Modify status to reflect failure inside Ob */
594 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
597 /* We're done, return the status and object */
598 *FoundObject
= Object
;
599 ObDereferenceObject(RootDirectory
);
602 else if ((!ObjectName
->Length
) ||
603 (!ObjectName
->Buffer
) ||
604 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
606 /* Reparsed to the root directory, so start over */
607 ObDereferenceObject(RootDirectory
);
608 RootDirectory
= ObpRootDirectoryObject
;
610 /* Don't use this anymore, since we're starting at root */
614 else if (--MaxReparse
)
616 /* Try reparsing again */
621 /* Reparsed too many times */
622 ObDereferenceObject(RootDirectory
);
624 /* Return the object and normalized status */
625 *FoundObject
= Object
;
626 if (!Object
) Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
631 else if (!(ObjectName
->Length
) || !(ObjectName
->Buffer
))
633 /* Just return the Root Directory if we didn't get a name */
634 Status
= ObReferenceObjectByPointer(RootDirectory
,
638 if (NT_SUCCESS(Status
)) Object
= RootDirectory
;
640 /* Remove the first reference we added and return the object */
641 ObDereferenceObject(RootDirectory
);
642 *FoundObject
= Object
;
648 /* We did not get a Root Directory, so use the root */
649 RootDirectory
= ObpRootDirectoryObject
;
651 /* It must start with a path separator */
652 if (!(ObjectName
->Length
) ||
653 !(ObjectName
->Buffer
) ||
654 (ObjectName
->Buffer
[0] != OBJ_NAME_PATH_SEPARATOR
))
656 /* This name is invalid, so fail */
657 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
660 /* Check if the name is only the path separator */
661 if (ObjectName
->Length
== sizeof(OBJ_NAME_PATH_SEPARATOR
))
663 /* So the caller only wants the root directory; do we have one? */
666 /* This must be the first time we're creating it... right? */
669 /* Yes, so return it to ObInsert so that it can create it */
670 Status
= ObReferenceObjectByPointer(InsertObject
,
674 if (NT_SUCCESS(Status
)) *FoundObject
= InsertObject
;
679 /* This should never really happen */
681 return STATUS_INVALID_PARAMETER
;
686 /* We do have the root directory, so just return it */
687 Status
= ObReferenceObjectByPointer(RootDirectory
,
691 if (NT_SUCCESS(Status
)) *FoundObject
= RootDirectory
;
698 /* FIXME: Check if we have a device map */
700 /* Check if this is a possible DOS name */
701 if (!((ULONG_PTR
)(ObjectName
->Buffer
) & 7))
704 * This could be one. Does it match the prefix?
705 * Note that as an optimization, the match is done as 64-bit
706 * compare since the prefix is "\??\" which is exactly 8 bytes.
708 * In the second branch, we test for "\??" which is also valid.
709 * This time, we use a 32-bit compare followed by a Unicode
710 * character compare (16-bit), since the sum is 6 bytes.
712 if ((ObjectName
->Length
>= ObpDosDevicesShortName
.Length
) &&
713 (*(PULONGLONG
)(ObjectName
->Buffer
) ==
714 ObpDosDevicesShortNamePrefix
.Alignment
.QuadPart
))
718 else if ((ObjectName
->Length
== ObpDosDevicesShortName
.Length
-
720 (*(PULONG
)(ObjectName
->Buffer
) ==
721 ObpDosDevicesShortNameRoot
.Alignment
.LowPart
) &&
722 (*((PWCHAR
)(ObjectName
->Buffer
) + 2) ==
723 (WCHAR
)(ObpDosDevicesShortNameRoot
.Alignment
.HighPart
)))
731 /* Check if we were reparsing a symbolic link */
740 while (Reparse
&& MaxReparse
)
743 RemainingName
= *ObjectName
;
745 /* Disable reparsing again */
748 /* Start parse loop */
754 /* Check if the name starts with a path separator */
755 if ((RemainingName
.Length
) &&
756 (RemainingName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
758 /* Skip the path separator */
759 RemainingName
.Buffer
++;
760 RemainingName
.Length
-= sizeof(OBJ_NAME_PATH_SEPARATOR
);
763 /* Find the next Part Name */
764 ComponentName
= RemainingName
;
765 while (RemainingName
.Length
)
767 /* Break if we found the \ ending */
768 if (RemainingName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
) break;
771 RemainingName
.Buffer
++;
772 RemainingName
.Length
-= sizeof(OBJ_NAME_PATH_SEPARATOR
);
775 /* Get its size and make sure it's valid */
776 ComponentName
.Length
-= RemainingName
.Length
;
777 if (!ComponentName
.Length
)
779 /* Invalid size, fail */
780 Status
= STATUS_OBJECT_NAME_INVALID
;
784 /* Check if we're in the root */
785 if (!Directory
) Directory
= RootDirectory
;
787 /* Check if this is a user-mode call that needs to traverse */
788 if ((AccessCheckMode
!= KernelMode
) &&
789 !(AccessState
->Flags
& TOKEN_HAS_TRAVERSE_PRIVILEGE
))
791 /* We shouldn't have referenced a directory yet */
792 ASSERT(ReferencedDirectory
== NULL
);
794 /* Reference the directory */
795 ObReferenceObject(Directory
);
796 ReferencedDirectory
= Directory
;
798 /* Check if we have a parent directory */
801 /* Check for traverse access */
802 if (!ObpCheckTraverseAccess(ParentDirectory
,
809 /* We don't have it, fail */
815 /* Check if we don't have a remaining name yet */
816 if (!RemainingName
.Length
)
818 /* Check if we don't have a referenced directory yet */
819 if (!ReferencedDirectory
)
822 ObReferenceObject(Directory
);
823 ReferencedDirectory
= Directory
;
826 /* Check if we are inserting an object */
829 /* Lock the directory */
830 ObpAcquireDirectoryLockExclusive(Directory
, LookupContext
);
835 Object
= ObpLookupEntryDirectory(Directory
,
838 InsertObject
? FALSE
: TRUE
,
842 /* We didn't find it... do we still have a path? */
843 if (RemainingName
.Length
)
845 /* Then tell the caller the path wasn't found */
846 Status
= STATUS_OBJECT_PATH_NOT_FOUND
;
849 else if (!InsertObject
)
851 /* Otherwise, we have a path, but the name isn't valid */
852 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
856 /* Check create access for the object */
857 if (!ObCheckCreateObjectAccess(Directory
,
858 ObjectType
== ObpDirectoryObjectType
?
859 DIRECTORY_CREATE_SUBDIRECTORY
:
860 DIRECTORY_CREATE_OBJECT
,
867 /* We don't have create access, fail */
871 /* Get the object header */
872 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(InsertObject
);
875 * Deny object creation if:
876 * That's a section object or a symbolic link
877 * Which isn't in the same section that root directory
878 * That doesn't have the SeCreateGlobalPrivilege
879 * And that is not a known unsecure name
881 if (RootDirectory
->SessionId
!= -1)
883 if (ObjectHeader
->Type
== MmSectionObjectType
||
884 ObjectHeader
->Type
== ObpSymbolicLinkObjectType
)
886 if (RootDirectory
->SessionId
!= PsGetCurrentProcessSessionId() &&
887 !SeSinglePrivilegeCheck(SeCreateGlobalPrivilege
, AccessCheckMode
) &&
888 !ObpIsUnsecureName(&ComponentName
, BooleanFlagOn(Attributes
, OBJ_CASE_INSENSITIVE
)))
890 Status
= STATUS_ACCESS_DENIED
;
896 /* Create Object Name */
897 NewName
= ExAllocatePoolWithTag(PagedPool
,
898 ComponentName
.Length
,
901 !(ObpInsertEntryDirectory(Directory
,
905 /* Either couldn't allocate the name, or insert failed */
906 if (NewName
) ExFreePoolWithTag(NewName
, OB_NAME_TAG
);
908 /* Fail due to memory reasons */
909 Status
= STATUS_INSUFFICIENT_RESOURCES
;
913 /* Reference newly to be inserted object */
914 ObReferenceObject(InsertObject
);
916 /* Get the name information */
917 ObjectNameInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
919 /* Reference the directory */
920 ObReferenceObject(Directory
);
923 RtlCopyMemory(NewName
,
924 ComponentName
.Buffer
,
925 ComponentName
.Length
);
927 /* Check if we had an old name */
928 if (ObjectNameInfo
->Name
.Buffer
)
931 ExFreePoolWithTag(ObjectNameInfo
->Name
.Buffer
, OB_NAME_TAG
);
935 ObjectNameInfo
->Name
.Buffer
= NewName
;
936 ObjectNameInfo
->Name
.Length
= ComponentName
.Length
;
937 ObjectNameInfo
->Name
.MaximumLength
= ComponentName
.Length
;
939 /* Return Status and the Expected Object */
940 Status
= STATUS_SUCCESS
;
941 Object
= InsertObject
;
943 /* Get out of here */
948 /* We found it, so now get its header */
949 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
952 * Check for a parse Procedure, but don't bother to parse for an insert
953 * unless it's a Symbolic Link, in which case we MUST parse
955 ParseRoutine
= ObjectHeader
->Type
->TypeInfo
.ParseProcedure
;
956 if ((ParseRoutine
) &&
957 (!(InsertObject
) || (ParseRoutine
== ObpParseSymbolicLink
)))
959 /* Use the Root Directory next time */
962 /* Increment the pointer count */
963 InterlockedExchangeAddSizeT(&ObjectHeader
->PointerCount
, 1);
965 /* Cleanup from the first lookup */
966 ObpReleaseLookupContext(LookupContext
);
968 /* Check if we have a referenced directory */
969 if (ReferencedDirectory
)
971 /* We do, dereference it */
972 ObDereferenceObject(ReferencedDirectory
);
973 ReferencedDirectory
= NULL
;
976 /* Check if we have a referenced parent directory */
977 if (ReferencedParentDirectory
)
979 /* We do, dereference it */
980 ObDereferenceObject(ReferencedParentDirectory
);
981 ReferencedParentDirectory
= NULL
;
984 /* Call the Parse Procedure */
985 ObpCalloutStart(&CalloutIrql
);
986 Status
= ParseRoutine(Object
,
996 ObpCalloutEnd(CalloutIrql
, "Parse", ObjectHeader
->Type
, Object
);
998 /* Remove our extra reference */
999 ObDereferenceObject(&ObjectHeader
->Body
);
1001 /* Check if we have to reparse */
1002 if ((Status
== STATUS_REPARSE
) ||
1003 (Status
== STATUS_REPARSE_OBJECT
))
1008 if (MaxReparse
== 0)
1014 /* Start over from root if we got sent back there */
1015 if ((Status
== STATUS_REPARSE_OBJECT
) ||
1016 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
1018 /* Check if we got a root directory */
1021 /* Stop using it, because we have a new directory now */
1022 ObDereferenceObject(RootDirectory
);
1027 ParentDirectory
= NULL
;
1028 RootDirectory
= ObpRootDirectoryObject
;
1030 /* Check for reparse status */
1031 if (Status
== STATUS_REPARSE_OBJECT
)
1033 /* Don't reparse again */
1036 /* Did we actually get an object to which to reparse? */
1039 /* We didn't, so set a failure status */
1040 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1044 /* We did, so we're free to parse the new object */
1050 /* This is a symbolic link */
1055 else if (RootDirectory
== ObpRootDirectoryObject
)
1057 /* We got STATUS_REPARSE but are at the Root Directory */
1059 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1063 else if (!NT_SUCCESS(Status
))
1070 /* We didn't reparse but we didn't find the Object Either */
1071 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1074 /* Break out of the loop */
1079 /* No parse routine...do we still have a remaining name? */
1080 if (!RemainingName
.Length
)
1082 /* Are we creating an object? */
1085 /* Check if this is a user-mode call that needs to traverse */
1086 if ((AccessCheckMode
!= KernelMode
) &&
1087 !(AccessState
->Flags
& TOKEN_HAS_TRAVERSE_PRIVILEGE
))
1089 /* Check if we can get it */
1090 if (!ObpCheckTraverseAccess(Directory
,
1097 /* We don't have access, fail */
1103 /* Reference the Object */
1104 Status
= ObReferenceObjectByPointer(Object
,
1108 if (!NT_SUCCESS(Status
)) Object
= NULL
;
1111 /* And get out of the reparse loop */
1116 /* We still have a name; check if this is a directory object */
1117 if (ObjectHeader
->Type
== ObpDirectoryObjectType
)
1119 /* Check if we have a referenced parent directory */
1120 if (ReferencedParentDirectory
)
1122 /* Dereference it */
1123 ObDereferenceObject(ReferencedParentDirectory
);
1126 /* Restart the lookup from this directory */
1127 ReferencedParentDirectory
= ReferencedDirectory
;
1128 ParentDirectory
= Directory
;
1130 ReferencedDirectory
= NULL
;
1134 /* We still have a name, but no parse routine for it */
1135 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
1144 /* Check if we failed */
1145 if (!NT_SUCCESS(Status
))
1147 /* Cleanup after lookup */
1148 ObpReleaseLookupContext(LookupContext
);
1151 /* Check if we have a device map and dereference it if so */
1152 //if (DeviceMap) ObfDereferenceDeviceMap(DeviceMap);
1154 /* Check if we have a referenced directory and dereference it if so */
1155 if (ReferencedDirectory
) ObDereferenceObject(ReferencedDirectory
);
1157 /* Check if we have a referenced parent directory */
1158 if (ReferencedParentDirectory
)
1160 /* We do, dereference it */
1161 ObDereferenceObject(ReferencedParentDirectory
);
1164 /* Set the found object and check if we got one */
1165 *FoundObject
= Object
;
1168 /* Nothing was found. Did we reparse or get success? */
1169 if ((Status
== STATUS_REPARSE
) || (NT_SUCCESS(Status
)))
1171 /* Set correct failure */
1172 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1176 /* Check if we had a root directory */
1177 if (RootHandle
) ObDereferenceObject(RootDirectory
);
1179 /* Return status to caller */
1180 OBTRACE(OB_NAMESPACE_DEBUG
,
1181 "%s - Found Object: %p. Expected: %p\n",
1188 /* PUBLIC FUNCTIONS *********************************************************/
1192 ObQueryNameString(IN PVOID Object
,
1193 OUT POBJECT_NAME_INFORMATION ObjectNameInfo
,
1195 OUT PULONG ReturnLength
)
1197 POBJECT_HEADER_NAME_INFO LocalInfo
;
1198 POBJECT_HEADER ObjectHeader
;
1199 POBJECT_DIRECTORY ParentDirectory
;
1202 BOOLEAN ObjectIsNamed
;
1203 NTSTATUS Status
= STATUS_SUCCESS
;
1205 /* Get the Kernel Meta-Structures */
1206 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
1207 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
1209 /* Check if a Query Name Procedure is available */
1210 if (ObjectHeader
->Type
->TypeInfo
.QueryNameProcedure
)
1212 /* Call the procedure inside SEH */
1213 ObjectIsNamed
= ((LocalInfo
) && (LocalInfo
->Name
.Length
> 0));
1217 Status
= ObjectHeader
->Type
->TypeInfo
.QueryNameProcedure(Object
,
1224 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1226 /* Return the exception code */
1227 Status
= _SEH2_GetExceptionCode();
1234 /* Check if the object doesn't even have a name */
1235 if (!(LocalInfo
) || !(LocalInfo
->Name
.Buffer
))
1237 Status
= STATUS_SUCCESS
;
1241 /* We're returning the name structure */
1242 *ReturnLength
= sizeof(OBJECT_NAME_INFORMATION
);
1244 /* Check if we were given enough space */
1245 if (*ReturnLength
> Length
)
1247 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1251 /* Return an empty buffer */
1252 RtlInitEmptyUnicodeString(&ObjectNameInfo
->Name
, NULL
, 0);
1255 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1257 /* Return the exception code */
1258 Status
= _SEH2_GetExceptionCode();
1266 * Find the size needed for the name. We won't do
1267 * this during the Name Creation loop because we want
1268 * to let the caller know that the buffer isn't big
1269 * enough right at the beginning, not work our way through
1270 * and find out at the end
1274 if (Object
== ObpRootDirectoryObject
)
1276 /* Size of the '\' string */
1277 NameSize
= sizeof(OBJ_NAME_PATH_SEPARATOR
);
1281 /* Get the Object Directory and add name of Object */
1282 ParentDirectory
= LocalInfo
->Directory
;
1283 NameSize
= sizeof(OBJ_NAME_PATH_SEPARATOR
) + LocalInfo
->Name
.Length
;
1285 /* Loop inside the directory to get the top-most one (meaning root) */
1286 while ((ParentDirectory
!= ObpRootDirectoryObject
) && (ParentDirectory
))
1288 /* Get the Name Information */
1289 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(
1290 OBJECT_TO_OBJECT_HEADER(ParentDirectory
));
1292 /* Add the size of the Directory Name */
1293 if (LocalInfo
&& LocalInfo
->Directory
)
1295 /* Size of the '\' string + Directory Name */
1296 NameSize
+= sizeof(OBJ_NAME_PATH_SEPARATOR
) +
1297 LocalInfo
->Name
.Length
;
1299 /* Move to next parent Directory */
1300 ParentDirectory
= LocalInfo
->Directory
;
1304 /* Directory with no name. We append "...\" */
1305 NameSize
+= sizeof(L
"...") + sizeof(OBJ_NAME_PATH_SEPARATOR
);
1311 /* Finally, add the name of the structure and the null char */
1312 *ReturnLength
= NameSize
+
1313 sizeof(OBJECT_NAME_INFORMATION
) +
1314 sizeof(UNICODE_NULL
);
1316 /* Check if we were given enough space */
1317 if (*ReturnLength
> Length
) _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH
);
1320 * Now we will actually create the name. We work backwards because
1321 * it's easier to start off from the Name we have and walk up the
1322 * parent directories. We use the same logic as Name Length calculation.
1324 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
1325 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectNameInfo
+ *ReturnLength
);
1326 *--ObjectName
= UNICODE_NULL
;
1328 /* Check if the object is actually the Root directory */
1329 if (Object
== ObpRootDirectoryObject
)
1331 /* This is already the Root Directory, return "\\" */
1332 *--ObjectName
= OBJ_NAME_PATH_SEPARATOR
;
1333 ObjectNameInfo
->Name
.Length
= (USHORT
)NameSize
;
1334 ObjectNameInfo
->Name
.MaximumLength
= (USHORT
)(NameSize
+
1335 sizeof(UNICODE_NULL
));
1336 ObjectNameInfo
->Name
.Buffer
= ObjectName
;
1337 Status
= STATUS_SUCCESS
;
1341 /* Start by adding the Object's Name */
1342 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1343 LocalInfo
->Name
.Length
);
1344 RtlCopyMemory(ObjectName
,
1345 LocalInfo
->Name
.Buffer
,
1346 LocalInfo
->Name
.Length
);
1348 /* Now parse the Parent directories until we reach the top */
1349 ParentDirectory
= LocalInfo
->Directory
;
1350 while ((ParentDirectory
!= ObpRootDirectoryObject
) && (ParentDirectory
))
1352 /* Get the name information */
1353 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(
1354 OBJECT_TO_OBJECT_HEADER(ParentDirectory
));
1357 *(--ObjectName
) = OBJ_NAME_PATH_SEPARATOR
;
1359 /* Add the Parent Directory's Name */
1360 if (LocalInfo
&& LocalInfo
->Name
.Buffer
)
1363 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1364 LocalInfo
->Name
.Length
);
1365 RtlCopyMemory(ObjectName
,
1366 LocalInfo
->Name
.Buffer
,
1367 LocalInfo
->Name
.Length
);
1369 /* Move to next parent */
1370 ParentDirectory
= LocalInfo
->Directory
;
1374 /* Directory without a name, we add "..." */
1375 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1377 sizeof(UNICODE_NULL
));
1378 RtlCopyMemory(ObjectName
, L
"...", sizeof(L
"..."));
1383 /* Add Root Directory Name */
1384 *(--ObjectName
) = OBJ_NAME_PATH_SEPARATOR
;
1385 ObjectNameInfo
->Name
.Length
= (USHORT
)NameSize
;
1386 ObjectNameInfo
->Name
.MaximumLength
=
1387 (USHORT
)(NameSize
+ sizeof(UNICODE_NULL
));
1388 ObjectNameInfo
->Name
.Buffer
= ObjectName
;
1391 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1393 /* Return the exception code */
1394 Status
= _SEH2_GetExceptionCode();
1398 /* Return success */