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
)
45 /* Initialize the SD */
46 RtlCreateSecurityDescriptor(SecurityDescriptor
, SECURITY_DESCRIPTOR_REVISION
);
48 if (ObpProtectionMode
& 1)
50 AclSize
= sizeof(ACL
) +
51 sizeof(ACE
) + RtlLengthSid(SeWorldSid
) +
52 sizeof(ACE
) + RtlLengthSid(SeLocalSystemSid
) +
53 sizeof(ACE
) + RtlLengthSid(SeWorldSid
) +
54 sizeof(ACE
) + RtlLengthSid(SeAliasAdminsSid
) +
55 sizeof(ACE
) + RtlLengthSid(SeLocalSystemSid
) +
56 sizeof(ACE
) + RtlLengthSid(SeCreatorOwnerSid
);
58 /* Allocate the ACL */
59 Dacl
= ExAllocatePoolWithTag(PagedPool
, AclSize
, 'lcaD');
62 return STATUS_INSUFFICIENT_RESOURCES
;
65 /* Initialize the DACL */
66 RtlCreateAcl(Dacl
, AclSize
, ACL_REVISION
);
69 RtlAddAccessAllowedAce(Dacl
,
71 GENERIC_READ
| GENERIC_EXECUTE
,
74 RtlAddAccessAllowedAce(Dacl
,
79 RtlAddAccessAllowedAceEx(Dacl
,
81 INHERIT_ONLY_ACE
| CONTAINER_INHERIT_ACE
| OBJECT_INHERIT_ACE
,
85 RtlAddAccessAllowedAceEx(Dacl
,
87 INHERIT_ONLY_ACE
| CONTAINER_INHERIT_ACE
| OBJECT_INHERIT_ACE
,
91 RtlAddAccessAllowedAceEx(Dacl
,
93 INHERIT_ONLY_ACE
| CONTAINER_INHERIT_ACE
| OBJECT_INHERIT_ACE
,
97 RtlAddAccessAllowedAceEx(Dacl
,
99 INHERIT_ONLY_ACE
| CONTAINER_INHERIT_ACE
| OBJECT_INHERIT_ACE
,
105 AclSize
= sizeof(ACL
) +
106 sizeof(ACE
) + RtlLengthSid(SeLocalSystemSid
) +
107 sizeof(ACE
) + RtlLengthSid(SeWorldSid
) +
108 sizeof(ACE
) + RtlLengthSid(SeLocalSystemSid
);
110 /* Allocate the ACL */
111 Dacl
= ExAllocatePoolWithTag(PagedPool
, AclSize
, 'lcaD');
114 return STATUS_INSUFFICIENT_RESOURCES
;
117 /* Initialize the DACL */
118 RtlCreateAcl(Dacl
, AclSize
, ACL_REVISION
);
121 RtlAddAccessAllowedAce(Dacl
,
123 GENERIC_READ
| GENERIC_EXECUTE
| GENERIC_WRITE
,
126 RtlAddAccessAllowedAce(Dacl
,
131 RtlAddAccessAllowedAceEx(Dacl
,
133 INHERIT_ONLY_ACE
| CONTAINER_INHERIT_ACE
| OBJECT_INHERIT_ACE
,
138 /* Attach the DACL to the SD */
139 RtlSetDaclSecurityDescriptor(SecurityDescriptor
, TRUE
, Dacl
, FALSE
);
141 return STATUS_SUCCESS
;
147 ObpCreateDosDevicesDirectory(VOID
)
149 OBJECT_ATTRIBUTES ObjectAttributes
;
150 UNICODE_STRING RootName
, TargetName
, LinkName
;
151 HANDLE Handle
, SymHandle
;
152 SECURITY_DESCRIPTOR DosDevicesSD
;
155 BOOLEAN DaclPresent
, DaclDefaulted
;
157 /* Create a custom security descriptor for the global DosDevices directory */
158 Status
= ObpGetDosDevicesProtection(&DosDevicesSD
);
159 if (!NT_SUCCESS(Status
))
162 /* Create the global DosDevices directory \?? */
163 RtlInitUnicodeString(&RootName
, L
"\\GLOBAL??");
164 InitializeObjectAttributes(&ObjectAttributes
,
169 Status
= NtCreateDirectoryObject(&Handle
,
170 DIRECTORY_ALL_ACCESS
,
172 if (!NT_SUCCESS(Status
))
175 /* Create the system device map */
176 Status
= ObpCreateDeviceMap(Handle
);
177 if (!NT_SUCCESS(Status
))
180 /*********************************************\
181 |*** HACK until we support device mappings ***|
182 |*** Add a symlink \??\ <--> \GLOBAL??\ ***|
183 \*********************************************/
184 RtlInitUnicodeString(&LinkName
, L
"\\??");
185 InitializeObjectAttributes(&ObjectAttributes
,
190 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
191 SYMBOLIC_LINK_ALL_ACCESS
,
194 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
195 /*********************************************\
196 \*********************************************/
198 // FIXME: Create a device mapping for the global \?? directory
201 * Initialize the \??\GLOBALROOT symbolic link
202 * pointing to the root directory \ .
204 RtlInitUnicodeString(&LinkName
, L
"GLOBALROOT");
205 RtlInitUnicodeString(&TargetName
, L
"");
206 InitializeObjectAttributes(&ObjectAttributes
,
211 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
212 SYMBOLIC_LINK_ALL_ACCESS
,
215 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
218 * Initialize the \??\Global symbolic link pointing to the global
219 * DosDevices directory \?? . It is used to access the global \??
220 * by user-mode components which, by default, use a per-session
221 * DosDevices directory.
223 RtlInitUnicodeString(&LinkName
, L
"Global");
224 InitializeObjectAttributes(&ObjectAttributes
,
229 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
230 SYMBOLIC_LINK_ALL_ACCESS
,
233 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
235 /* Close the directory handle */
237 if (!NT_SUCCESS(Status
))
241 * Initialize the \DosDevices symbolic link pointing to the global
242 * DosDevices directory \?? , for backward compatibility with
243 * Windows NT-2000 systems.
245 RtlCreateUnicodeString(&LinkName
, L
"\\DosDevices");
246 RtlInitUnicodeString(&RootName
, (PCWSTR
)&ObpDosDevicesShortNameRoot
);
247 InitializeObjectAttributes(&ObjectAttributes
,
252 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
253 SYMBOLIC_LINK_ALL_ACCESS
,
256 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
259 RtlGetDaclSecurityDescriptor(&DosDevicesSD
, &DaclPresent
, &Dacl
, &DaclDefaulted
);
260 ExFreePoolWithTag(Dacl
, 'lcaD');
267 * @name ObpDeleteNameCheck
269 * The ObpDeleteNameCheck routine checks if a named object should be
270 * removed from the object directory namespace.
273 * Pointer to the object to check for possible removal.
277 * @remarks An object is removed if the following 4 criteria are met:
278 * 1) The object has 0 handles open
279 * 2) The object is in the directory namespace and has a name
280 * 3) The object is not permanent
285 ObpDeleteNameCheck(IN PVOID Object
)
287 POBJECT_HEADER ObjectHeader
;
288 OBP_LOOKUP_CONTEXT Context
;
289 POBJECT_HEADER_NAME_INFO ObjectNameInfo
;
290 POBJECT_TYPE ObjectType
;
291 PVOID Directory
= NULL
;
293 /* Get object structures */
294 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
295 ObjectNameInfo
= ObpReferenceNameInfo(ObjectHeader
);
296 ObjectType
= ObjectHeader
->Type
;
299 * Check if the handle count is 0, if the object is named,
300 * and if the object isn't a permanent object.
302 if (!(ObjectHeader
->HandleCount
) &&
304 (ObjectNameInfo
->Name
.Length
) &&
305 (ObjectNameInfo
->Directory
) &&
306 !(ObjectHeader
->Flags
& OB_FLAG_PERMANENT
))
308 /* Setup a lookup context */
309 ObpInitializeLookupContext(&Context
);
311 /* Lock the directory */
312 ObpAcquireDirectoryLockExclusive(ObjectNameInfo
->Directory
, &Context
);
315 Object
= ObpLookupEntryDirectory(ObjectNameInfo
->Directory
,
316 &ObjectNameInfo
->Name
,
322 /* Lock the object */
323 ObpAcquireObjectLock(ObjectHeader
);
325 /* Make sure we can still delete the object */
326 if (!(ObjectHeader
->HandleCount
) &&
327 !(ObjectHeader
->Flags
& OB_FLAG_PERMANENT
))
329 /* First delete it from the directory */
330 ObpDeleteEntryDirectory(&Context
);
332 /* Check if this is a symbolic link */
333 if (ObjectType
== ObpSymbolicLinkObjectType
)
335 /* Remove internal name */
336 ObpDeleteSymbolicLinkName(Object
);
339 /* Check if the kernel exclusive is set */
340 ObjectNameInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
341 if ((ObjectNameInfo
) &&
342 (ObjectNameInfo
->QueryReferences
& OB_FLAG_KERNEL_EXCLUSIVE
))
344 /* Remove protection flag */
345 InterlockedExchangeAdd((PLONG
)&ObjectNameInfo
->QueryReferences
,
346 -OB_FLAG_KERNEL_EXCLUSIVE
);
349 /* Get the directory */
350 Directory
= ObjectNameInfo
->Directory
;
353 /* Release the lock */
354 ObpReleaseObjectLock(ObjectHeader
);
357 /* Cleanup after lookup */
358 ObpReleaseLookupContext(&Context
);
360 /* Remove another query reference since we added one on top */
361 ObpDereferenceNameInfo(ObjectNameInfo
);
363 /* Check if we were inserted in a directory */
366 /* We were, so first remove the extra reference we had added */
367 ObpDereferenceNameInfo(ObjectNameInfo
);
369 /* Now dereference the object as well */
370 ObDereferenceObject(Object
);
375 /* Remove the reference we added */
376 ObpDereferenceNameInfo(ObjectNameInfo
);
382 ObpIsUnsecureName(IN PUNICODE_STRING ObjectName
,
383 IN BOOLEAN CaseInSensitive
)
386 PWSTR UnsecureBuffer
;
387 UNICODE_STRING UnsecureName
;
389 /* No unsecure names known, quit */
390 if (ObpUnsecureGlobalNamesBuffer
[0] == UNICODE_NULL
)
395 /* By default, we have a secure name */
397 /* We will browse the whole string */
398 UnsecureBuffer
= &ObpUnsecureGlobalNamesBuffer
[0];
401 /* Initialize the unicode string */
402 RtlInitUnicodeString(&UnsecureName
, UnsecureBuffer
);
403 /* We're at the end of the multisz string! */
404 if (UnsecureName
.Length
== 0)
410 * Does the unsecure name prefix the object name?
411 * If so, that's an unsecure name, and return so
413 if (RtlPrefixUnicodeString(&UnsecureName
, ObjectName
, CaseInSensitive
))
420 * Move to the next string. As a reminder, ObpUnsecureGlobalNamesBuffer is
421 * a multisz, so we move the string next to the current UNICODE_NULL char
423 UnsecureBuffer
= (PWSTR
)((ULONG_PTR
)UnsecureBuffer
+ UnsecureName
.Length
+ sizeof(UNICODE_NULL
));
426 /* Return our findings */
432 ObpLookupObjectName(IN HANDLE RootHandle OPTIONAL
,
433 IN OUT PUNICODE_STRING ObjectName
,
435 IN POBJECT_TYPE ObjectType
,
436 IN KPROCESSOR_MODE AccessMode
,
437 IN OUT PVOID ParseContext
,
438 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
439 IN PVOID InsertObject OPTIONAL
,
440 IN OUT PACCESS_STATE AccessState
,
441 OUT POBP_LOOKUP_CONTEXT LookupContext
,
442 OUT PVOID
*FoundObject
)
445 POBJECT_HEADER ObjectHeader
;
446 UNICODE_STRING ComponentName
, RemainingName
;
447 BOOLEAN Reparse
= FALSE
, SymLink
= FALSE
;
448 POBJECT_DIRECTORY Directory
= NULL
, ParentDirectory
= NULL
, RootDirectory
;
449 POBJECT_DIRECTORY ReferencedDirectory
= NULL
, ReferencedParentDirectory
= NULL
;
451 OB_PARSE_METHOD ParseRoutine
;
453 KPROCESSOR_MODE AccessCheckMode
;
455 POBJECT_HEADER_NAME_INFO ObjectNameInfo
;
456 ULONG MaxReparse
= 30;
458 OBTRACE(OB_NAMESPACE_DEBUG
,
459 "%s - Finding Object: %wZ. Expecting: %p\n",
464 /* Initialize starting state */
465 ObpInitializeLookupContext(LookupContext
);
467 Status
= STATUS_SUCCESS
;
470 /* Check if case-insensitivity is checked */
471 if (ObpCaseInsensitive
)
473 /* Check if the object type requests this */
474 if (!(ObjectType
) || (ObjectType
->TypeInfo
.CaseInsensitive
))
476 /* Add the flag to disable case sensitivity */
477 Attributes
|= OBJ_CASE_INSENSITIVE
;
481 /* Check if this is a access checks are being forced */
482 AccessCheckMode
= (Attributes
& OBJ_FORCE_ACCESS_CHECK
) ?
483 UserMode
: AccessMode
;
485 /* Check if we got a Root Directory */
488 /* We did. Reference it */
489 Status
= ObReferenceObjectByHandle(RootHandle
,
493 (PVOID
*)&RootDirectory
,
495 if (!NT_SUCCESS(Status
)) return Status
;
498 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(RootDirectory
);
500 /* The name cannot start with a separator, unless this is a file */
501 if ((ObjectName
->Buffer
) &&
502 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
) &&
503 (ObjectHeader
->Type
!= IoFileObjectType
))
505 /* The syntax is bad, so fail this request */
506 ObDereferenceObject(RootDirectory
);
507 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
510 /* Don't parse a Directory */
511 if (ObjectHeader
->Type
!= ObpDirectoryObjectType
)
513 /* Make sure the Object Type has a parse routine */
514 ParseRoutine
= ObjectHeader
->Type
->TypeInfo
.ParseProcedure
;
517 /* We can't parse a name if we don't have a parse routine */
518 ObDereferenceObject(RootDirectory
);
519 return STATUS_INVALID_HANDLE
;
522 /* Set default parse count */
528 /* Start with the full name */
529 RemainingName
= *ObjectName
;
531 /* Call the Parse Procedure */
532 ObpCalloutStart(&CalloutIrql
);
533 Status
= ParseRoutine(RootDirectory
,
543 ObpCalloutEnd(CalloutIrql
, "Parse", ObjectHeader
->Type
, Object
);
545 /* Check for success or failure, so not reparse */
546 if ((Status
!= STATUS_REPARSE
) &&
547 (Status
!= STATUS_REPARSE_OBJECT
))
549 /* Check for failure */
550 if (!NT_SUCCESS(Status
))
552 /* Parse routine might not have cleared this, do it */
557 /* Modify status to reflect failure inside Ob */
558 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
561 /* We're done, return the status and object */
562 *FoundObject
= Object
;
563 ObDereferenceObject(RootDirectory
);
566 else if ((!ObjectName
->Length
) ||
567 (!ObjectName
->Buffer
) ||
568 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
570 /* Reparsed to the root directory, so start over */
571 ObDereferenceObject(RootDirectory
);
572 RootDirectory
= ObpRootDirectoryObject
;
574 /* Don't use this anymore, since we're starting at root */
578 else if (--MaxReparse
)
580 /* Try reparsing again */
585 /* Reparsed too many times */
586 ObDereferenceObject(RootDirectory
);
588 /* Return the object and normalized status */
589 *FoundObject
= Object
;
590 if (!Object
) Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
595 else if (!(ObjectName
->Length
) || !(ObjectName
->Buffer
))
597 /* Just return the Root Directory if we didn't get a name */
598 Status
= ObReferenceObjectByPointer(RootDirectory
,
602 if (NT_SUCCESS(Status
)) Object
= RootDirectory
;
604 /* Remove the first reference we added and return the object */
605 ObDereferenceObject(RootDirectory
);
606 *FoundObject
= Object
;
612 /* We did not get a Root Directory, so use the root */
613 RootDirectory
= ObpRootDirectoryObject
;
615 /* It must start with a path separator */
616 if (!(ObjectName
->Length
) ||
617 !(ObjectName
->Buffer
) ||
618 (ObjectName
->Buffer
[0] != OBJ_NAME_PATH_SEPARATOR
))
620 /* This name is invalid, so fail */
621 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
624 /* Check if the name is only the path separator */
625 if (ObjectName
->Length
== sizeof(OBJ_NAME_PATH_SEPARATOR
))
627 /* So the caller only wants the root directory; do we have one? */
630 /* This must be the first time we're creating it... right? */
633 /* Yes, so return it to ObInsert so that it can create it */
634 Status
= ObReferenceObjectByPointer(InsertObject
,
638 if (NT_SUCCESS(Status
)) *FoundObject
= InsertObject
;
643 /* This should never really happen */
645 return STATUS_INVALID_PARAMETER
;
650 /* We do have the root directory, so just return it */
651 Status
= ObReferenceObjectByPointer(RootDirectory
,
655 if (NT_SUCCESS(Status
)) *FoundObject
= RootDirectory
;
662 /* FIXME: Check if we have a device map */
664 /* Check if this is a possible DOS name */
665 if (!((ULONG_PTR
)(ObjectName
->Buffer
) & 7))
668 * This could be one. Does it match the prefix?
669 * Note that as an optimization, the match is done as 64-bit
670 * compare since the prefix is "\??\" which is exactly 8 bytes.
672 * In the second branch, we test for "\??" which is also valid.
673 * This time, we use a 32-bit compare followed by a Unicode
674 * character compare (16-bit), since the sum is 6 bytes.
676 if ((ObjectName
->Length
>= ObpDosDevicesShortName
.Length
) &&
677 (*(PULONGLONG
)(ObjectName
->Buffer
) ==
678 ObpDosDevicesShortNamePrefix
.Alignment
.QuadPart
))
682 else if ((ObjectName
->Length
== ObpDosDevicesShortName
.Length
-
684 (*(PULONG
)(ObjectName
->Buffer
) ==
685 ObpDosDevicesShortNameRoot
.Alignment
.LowPart
) &&
686 (*((PWCHAR
)(ObjectName
->Buffer
) + 2) ==
687 (WCHAR
)(ObpDosDevicesShortNameRoot
.Alignment
.HighPart
)))
695 /* Check if we were reparsing a symbolic link */
704 while (Reparse
&& MaxReparse
)
707 RemainingName
= *ObjectName
;
709 /* Disable reparsing again */
712 /* Start parse loop */
718 /* Check if the name starts with a path separator */
719 if ((RemainingName
.Length
) &&
720 (RemainingName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
722 /* Skip the path separator */
723 RemainingName
.Buffer
++;
724 RemainingName
.Length
-= sizeof(OBJ_NAME_PATH_SEPARATOR
);
727 /* Find the next Part Name */
728 ComponentName
= RemainingName
;
729 while (RemainingName
.Length
)
731 /* Break if we found the \ ending */
732 if (RemainingName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
) break;
735 RemainingName
.Buffer
++;
736 RemainingName
.Length
-= sizeof(OBJ_NAME_PATH_SEPARATOR
);
739 /* Get its size and make sure it's valid */
740 ComponentName
.Length
-= RemainingName
.Length
;
741 if (!ComponentName
.Length
)
743 /* Invalid size, fail */
744 Status
= STATUS_OBJECT_NAME_INVALID
;
748 /* Check if we're in the root */
749 if (!Directory
) Directory
= RootDirectory
;
751 /* Check if this is a user-mode call that needs to traverse */
752 if ((AccessCheckMode
!= KernelMode
) &&
753 !(AccessState
->Flags
& TOKEN_HAS_TRAVERSE_PRIVILEGE
))
755 /* We shouldn't have referenced a directory yet */
756 ASSERT(ReferencedDirectory
== NULL
);
758 /* Reference the directory */
759 ObReferenceObject(Directory
);
760 ReferencedDirectory
= Directory
;
762 /* Check if we have a parent directory */
765 /* Check for traverse access */
766 if (!ObpCheckTraverseAccess(ParentDirectory
,
773 /* We don't have it, fail */
779 /* Check if we don't have a remaining name yet */
780 if (!RemainingName
.Length
)
782 /* Check if we don't have a referenced directory yet */
783 if (!ReferencedDirectory
)
786 ObReferenceObject(Directory
);
787 ReferencedDirectory
= Directory
;
790 /* Check if we are inserting an object */
793 /* Lock the directory */
794 ObpAcquireDirectoryLockExclusive(Directory
, LookupContext
);
799 Object
= ObpLookupEntryDirectory(Directory
,
802 InsertObject
? FALSE
: TRUE
,
806 /* We didn't find it... do we still have a path? */
807 if (RemainingName
.Length
)
809 /* Then tell the caller the path wasn't found */
810 Status
= STATUS_OBJECT_PATH_NOT_FOUND
;
813 else if (!InsertObject
)
815 /* Otherwise, we have a path, but the name isn't valid */
816 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
820 /* Check create access for the object */
821 if (!ObCheckCreateObjectAccess(Directory
,
822 ObjectType
== ObpDirectoryObjectType
?
823 DIRECTORY_CREATE_SUBDIRECTORY
:
824 DIRECTORY_CREATE_OBJECT
,
831 /* We don't have create access, fail */
835 /* Get the object header */
836 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(InsertObject
);
839 * Deny object creation if:
840 * That's a section object or a symbolic link
841 * Which isn't in the same section that root directory
842 * That doesn't have the SeCreateGlobalPrivilege
843 * And that is not a known unsecure name
845 if (RootDirectory
->SessionId
!= -1)
847 if (ObjectHeader
->Type
== MmSectionObjectType
||
848 ObjectHeader
->Type
== ObpSymbolicLinkObjectType
)
850 if (RootDirectory
->SessionId
!= PsGetCurrentProcessSessionId() &&
851 !SeSinglePrivilegeCheck(SeCreateGlobalPrivilege
, AccessCheckMode
) &&
852 !ObpIsUnsecureName(&ComponentName
, BooleanFlagOn(Attributes
, OBJ_CASE_INSENSITIVE
)))
854 Status
= STATUS_ACCESS_DENIED
;
860 /* Create Object Name */
861 NewName
= ExAllocatePoolWithTag(PagedPool
,
862 ComponentName
.Length
,
865 !(ObpInsertEntryDirectory(Directory
,
869 /* Either couldn't allocate the name, or insert failed */
870 if (NewName
) ExFreePoolWithTag(NewName
, OB_NAME_TAG
);
872 /* Fail due to memory reasons */
873 Status
= STATUS_INSUFFICIENT_RESOURCES
;
877 /* Reference newly to be inserted object */
878 ObReferenceObject(InsertObject
);
880 /* Get the name information */
881 ObjectNameInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
883 /* Reference the directory */
884 ObReferenceObject(Directory
);
887 RtlCopyMemory(NewName
,
888 ComponentName
.Buffer
,
889 ComponentName
.Length
);
891 /* Check if we had an old name */
892 if (ObjectNameInfo
->Name
.Buffer
)
895 ExFreePoolWithTag(ObjectNameInfo
->Name
.Buffer
, OB_NAME_TAG
);
899 ObjectNameInfo
->Name
.Buffer
= NewName
;
900 ObjectNameInfo
->Name
.Length
= ComponentName
.Length
;
901 ObjectNameInfo
->Name
.MaximumLength
= ComponentName
.Length
;
903 /* Return Status and the Expected Object */
904 Status
= STATUS_SUCCESS
;
905 Object
= InsertObject
;
907 /* Get out of here */
912 /* We found it, so now get its header */
913 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
916 * Check for a parse Procedure, but don't bother to parse for an insert
917 * unless it's a Symbolic Link, in which case we MUST parse
919 ParseRoutine
= ObjectHeader
->Type
->TypeInfo
.ParseProcedure
;
920 if ((ParseRoutine
) &&
921 (!(InsertObject
) || (ParseRoutine
== ObpParseSymbolicLink
)))
923 /* Use the Root Directory next time */
926 /* Increment the pointer count */
927 InterlockedExchangeAddSizeT(&ObjectHeader
->PointerCount
, 1);
929 /* Cleanup from the first lookup */
930 ObpReleaseLookupContext(LookupContext
);
932 /* Check if we have a referenced directory */
933 if (ReferencedDirectory
)
935 /* We do, dereference it */
936 ObDereferenceObject(ReferencedDirectory
);
937 ReferencedDirectory
= NULL
;
940 /* Check if we have a referenced parent directory */
941 if (ReferencedParentDirectory
)
943 /* We do, dereference it */
944 ObDereferenceObject(ReferencedParentDirectory
);
945 ReferencedParentDirectory
= NULL
;
948 /* Call the Parse Procedure */
949 ObpCalloutStart(&CalloutIrql
);
950 Status
= ParseRoutine(Object
,
960 ObpCalloutEnd(CalloutIrql
, "Parse", ObjectHeader
->Type
, Object
);
962 /* Remove our extra reference */
963 ObDereferenceObject(&ObjectHeader
->Body
);
965 /* Check if we have to reparse */
966 if ((Status
== STATUS_REPARSE
) ||
967 (Status
== STATUS_REPARSE_OBJECT
))
978 /* Start over from root if we got sent back there */
979 if ((Status
== STATUS_REPARSE_OBJECT
) ||
980 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
982 /* Check if we got a root directory */
985 /* Stop using it, because we have a new directory now */
986 ObDereferenceObject(RootDirectory
);
991 ParentDirectory
= NULL
;
992 RootDirectory
= ObpRootDirectoryObject
;
994 /* Check for reparse status */
995 if (Status
== STATUS_REPARSE_OBJECT
)
997 /* Don't reparse again */
1000 /* Did we actually get an object to which to reparse? */
1003 /* We didn't, so set a failure status */
1004 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1008 /* We did, so we're free to parse the new object */
1014 /* This is a symbolic link */
1019 else if (RootDirectory
== ObpRootDirectoryObject
)
1021 /* We got STATUS_REPARSE but are at the Root Directory */
1023 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1027 else if (!NT_SUCCESS(Status
))
1034 /* We didn't reparse but we didn't find the Object Either */
1035 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1038 /* Break out of the loop */
1043 /* No parse routine...do we still have a remaining name? */
1044 if (!RemainingName
.Length
)
1046 /* Are we creating an object? */
1049 /* Check if this is a user-mode call that needs to traverse */
1050 if ((AccessCheckMode
!= KernelMode
) &&
1051 !(AccessState
->Flags
& TOKEN_HAS_TRAVERSE_PRIVILEGE
))
1053 /* Check if we can get it */
1054 if (!ObpCheckTraverseAccess(Directory
,
1061 /* We don't have access, fail */
1067 /* Reference the Object */
1068 Status
= ObReferenceObjectByPointer(Object
,
1072 if (!NT_SUCCESS(Status
)) Object
= NULL
;
1075 /* And get out of the reparse loop */
1080 /* We still have a name; check if this is a directory object */
1081 if (ObjectHeader
->Type
== ObpDirectoryObjectType
)
1083 /* Check if we have a referenced parent directory */
1084 if (ReferencedParentDirectory
)
1086 /* Dereference it */
1087 ObDereferenceObject(ReferencedParentDirectory
);
1090 /* Restart the lookup from this directory */
1091 ReferencedParentDirectory
= ReferencedDirectory
;
1092 ParentDirectory
= Directory
;
1094 ReferencedDirectory
= NULL
;
1098 /* We still have a name, but no parse routine for it */
1099 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
1108 /* Check if we failed */
1109 if (!NT_SUCCESS(Status
))
1111 /* Cleanup after lookup */
1112 ObpReleaseLookupContext(LookupContext
);
1115 /* Check if we have a device map and dereference it if so */
1116 //if (DeviceMap) ObfDereferenceDeviceMap(DeviceMap);
1118 /* Check if we have a referenced directory and dereference it if so */
1119 if (ReferencedDirectory
) ObDereferenceObject(ReferencedDirectory
);
1121 /* Check if we have a referenced parent directory */
1122 if (ReferencedParentDirectory
)
1124 /* We do, dereference it */
1125 ObDereferenceObject(ReferencedParentDirectory
);
1128 /* Set the found object and check if we got one */
1129 *FoundObject
= Object
;
1132 /* Nothing was found. Did we reparse or get success? */
1133 if ((Status
== STATUS_REPARSE
) || (NT_SUCCESS(Status
)))
1135 /* Set correct failure */
1136 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1140 /* Check if we had a root directory */
1141 if (RootHandle
) ObDereferenceObject(RootDirectory
);
1143 /* Return status to caller */
1144 OBTRACE(OB_NAMESPACE_DEBUG
,
1145 "%s - Found Object: %p. Expected: %p\n",
1152 /* PUBLIC FUNCTIONS *********************************************************/
1156 ObQueryNameString(IN PVOID Object
,
1157 OUT POBJECT_NAME_INFORMATION ObjectNameInfo
,
1159 OUT PULONG ReturnLength
)
1161 POBJECT_HEADER_NAME_INFO LocalInfo
;
1162 POBJECT_HEADER ObjectHeader
;
1163 POBJECT_DIRECTORY ParentDirectory
;
1166 BOOLEAN ObjectIsNamed
;
1167 NTSTATUS Status
= STATUS_SUCCESS
;
1169 /* Get the Kernel Meta-Structures */
1170 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
1171 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
1173 /* Check if a Query Name Procedure is available */
1174 if (ObjectHeader
->Type
->TypeInfo
.QueryNameProcedure
)
1176 /* Call the procedure inside SEH */
1177 ObjectIsNamed
= ((LocalInfo
) && (LocalInfo
->Name
.Length
> 0));
1181 Status
= ObjectHeader
->Type
->TypeInfo
.QueryNameProcedure(Object
,
1188 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1190 /* Return the exception code */
1191 Status
= _SEH2_GetExceptionCode();
1198 /* Check if the object doesn't even have a name */
1199 if (!(LocalInfo
) || !(LocalInfo
->Name
.Buffer
))
1201 Status
= STATUS_SUCCESS
;
1205 /* We're returning the name structure */
1206 *ReturnLength
= sizeof(OBJECT_NAME_INFORMATION
);
1208 /* Check if we were given enough space */
1209 if (*ReturnLength
> Length
)
1211 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1215 /* Return an empty buffer */
1216 RtlInitEmptyUnicodeString(&ObjectNameInfo
->Name
, NULL
, 0);
1219 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1221 /* Return the exception code */
1222 Status
= _SEH2_GetExceptionCode();
1230 * Find the size needed for the name. We won't do
1231 * this during the Name Creation loop because we want
1232 * to let the caller know that the buffer isn't big
1233 * enough right at the beginning, not work our way through
1234 * and find out at the end
1238 if (Object
== ObpRootDirectoryObject
)
1240 /* Size of the '\' string */
1241 NameSize
= sizeof(OBJ_NAME_PATH_SEPARATOR
);
1245 /* Get the Object Directory and add name of Object */
1246 ParentDirectory
= LocalInfo
->Directory
;
1247 NameSize
= sizeof(OBJ_NAME_PATH_SEPARATOR
) + LocalInfo
->Name
.Length
;
1249 /* Loop inside the directory to get the top-most one (meaning root) */
1250 while ((ParentDirectory
!= ObpRootDirectoryObject
) && (ParentDirectory
))
1252 /* Get the Name Information */
1253 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(
1254 OBJECT_TO_OBJECT_HEADER(ParentDirectory
));
1256 /* Add the size of the Directory Name */
1257 if (LocalInfo
&& LocalInfo
->Directory
)
1259 /* Size of the '\' string + Directory Name */
1260 NameSize
+= sizeof(OBJ_NAME_PATH_SEPARATOR
) +
1261 LocalInfo
->Name
.Length
;
1263 /* Move to next parent Directory */
1264 ParentDirectory
= LocalInfo
->Directory
;
1268 /* Directory with no name. We append "...\" */
1269 NameSize
+= sizeof(L
"...") + sizeof(OBJ_NAME_PATH_SEPARATOR
);
1275 /* Finally, add the name of the structure and the null char */
1276 *ReturnLength
= NameSize
+
1277 sizeof(OBJECT_NAME_INFORMATION
) +
1278 sizeof(UNICODE_NULL
);
1280 /* Check if we were given enough space */
1281 if (*ReturnLength
> Length
) _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH
);
1284 * Now we will actually create the name. We work backwards because
1285 * it's easier to start off from the Name we have and walk up the
1286 * parent directories. We use the same logic as Name Length calculation.
1288 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
1289 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectNameInfo
+ *ReturnLength
);
1290 *--ObjectName
= UNICODE_NULL
;
1292 /* Check if the object is actually the Root directory */
1293 if (Object
== ObpRootDirectoryObject
)
1295 /* This is already the Root Directory, return "\\" */
1296 *--ObjectName
= OBJ_NAME_PATH_SEPARATOR
;
1297 ObjectNameInfo
->Name
.Length
= (USHORT
)NameSize
;
1298 ObjectNameInfo
->Name
.MaximumLength
= (USHORT
)(NameSize
+
1299 sizeof(UNICODE_NULL
));
1300 ObjectNameInfo
->Name
.Buffer
= ObjectName
;
1301 Status
= STATUS_SUCCESS
;
1305 /* Start by adding the Object's Name */
1306 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1307 LocalInfo
->Name
.Length
);
1308 RtlCopyMemory(ObjectName
,
1309 LocalInfo
->Name
.Buffer
,
1310 LocalInfo
->Name
.Length
);
1312 /* Now parse the Parent directories until we reach the top */
1313 ParentDirectory
= LocalInfo
->Directory
;
1314 while ((ParentDirectory
!= ObpRootDirectoryObject
) && (ParentDirectory
))
1316 /* Get the name information */
1317 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(
1318 OBJECT_TO_OBJECT_HEADER(ParentDirectory
));
1321 *(--ObjectName
) = OBJ_NAME_PATH_SEPARATOR
;
1323 /* Add the Parent Directory's Name */
1324 if (LocalInfo
&& LocalInfo
->Name
.Buffer
)
1327 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1328 LocalInfo
->Name
.Length
);
1329 RtlCopyMemory(ObjectName
,
1330 LocalInfo
->Name
.Buffer
,
1331 LocalInfo
->Name
.Length
);
1333 /* Move to next parent */
1334 ParentDirectory
= LocalInfo
->Directory
;
1338 /* Directory without a name, we add "..." */
1339 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1341 sizeof(UNICODE_NULL
));
1342 RtlCopyMemory(ObjectName
, L
"...", sizeof(L
"..."));
1347 /* Add Root Directory Name */
1348 *(--ObjectName
) = OBJ_NAME_PATH_SEPARATOR
;
1349 ObjectNameInfo
->Name
.Length
= (USHORT
)NameSize
;
1350 ObjectNameInfo
->Name
.MaximumLength
=
1351 (USHORT
)(NameSize
+ sizeof(UNICODE_NULL
));
1352 ObjectNameInfo
->Name
.Buffer
= ObjectName
;
1355 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1357 /* Return the exception code */
1358 Status
= _SEH2_GetExceptionCode();
1362 /* Return success */