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 /* Create a custom security descriptor for the global DosDevices directory */
193 Status
= ObpGetDosDevicesProtection(&DosDevicesSD
);
194 if (!NT_SUCCESS(Status
))
197 /* Create the global DosDevices directory \?? */
198 RtlInitUnicodeString(&RootName
, L
"\\GLOBAL??");
199 InitializeObjectAttributes(&ObjectAttributes
,
204 Status
= NtCreateDirectoryObject(&Handle
,
205 DIRECTORY_ALL_ACCESS
,
207 if (!NT_SUCCESS(Status
))
210 /* Create the system device map */
211 Status
= ObSetDeviceMap(NULL
, Handle
);
212 if (!NT_SUCCESS(Status
))
215 /*********************************************\
216 |*** HACK until we support device mappings ***|
217 |*** Add a symlink \??\ <--> \GLOBAL??\ ***|
218 \*********************************************/
219 RtlInitUnicodeString(&LinkName
, L
"\\??");
220 InitializeObjectAttributes(&ObjectAttributes
,
225 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
226 SYMBOLIC_LINK_ALL_ACCESS
,
229 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
230 /*********************************************\
231 \*********************************************/
233 // FIXME: Create a device mapping for the global \?? directory
236 * Initialize the \??\GLOBALROOT symbolic link
237 * pointing to the root directory \ .
239 RtlInitUnicodeString(&LinkName
, L
"GLOBALROOT");
240 RtlInitUnicodeString(&TargetName
, L
"");
241 InitializeObjectAttributes(&ObjectAttributes
,
246 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
247 SYMBOLIC_LINK_ALL_ACCESS
,
250 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
253 * Initialize the \??\Global symbolic link pointing to the global
254 * DosDevices directory \?? . It is used to access the global \??
255 * by user-mode components which, by default, use a per-session
256 * DosDevices directory.
258 RtlInitUnicodeString(&LinkName
, L
"Global");
259 InitializeObjectAttributes(&ObjectAttributes
,
264 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
265 SYMBOLIC_LINK_ALL_ACCESS
,
268 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
270 /* Close the directory handle */
272 if (!NT_SUCCESS(Status
))
276 * Initialize the \DosDevices symbolic link pointing to the global
277 * DosDevices directory \?? , for backward compatibility with
278 * Windows NT-2000 systems.
280 RtlCreateUnicodeString(&LinkName
, L
"\\DosDevices");
281 RtlInitUnicodeString(&RootName
, (PCWSTR
)&ObpDosDevicesShortNameRoot
);
282 InitializeObjectAttributes(&ObjectAttributes
,
287 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
288 SYMBOLIC_LINK_ALL_ACCESS
,
291 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
294 ObpFreeDosDevicesProtection(&DosDevicesSD
);
301 * @name ObpDeleteNameCheck
303 * The ObpDeleteNameCheck routine checks if a named object should be
304 * removed from the object directory namespace.
307 * Pointer to the object to check for possible removal.
311 * @remarks An object is removed if the following 4 criteria are met:
312 * 1) The object has 0 handles open
313 * 2) The object is in the directory namespace and has a name
314 * 3) The object is not permanent
319 ObpDeleteNameCheck(IN PVOID Object
)
321 POBJECT_HEADER ObjectHeader
;
322 OBP_LOOKUP_CONTEXT Context
;
323 POBJECT_HEADER_NAME_INFO ObjectNameInfo
;
324 POBJECT_TYPE ObjectType
;
325 PVOID Directory
= NULL
;
327 /* Get object structures */
328 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
329 ObjectNameInfo
= ObpReferenceNameInfo(ObjectHeader
);
330 ObjectType
= ObjectHeader
->Type
;
333 * Check if the handle count is 0, if the object is named,
334 * and if the object isn't a permanent object.
336 if (!(ObjectHeader
->HandleCount
) &&
338 (ObjectNameInfo
->Name
.Length
) &&
339 (ObjectNameInfo
->Directory
) &&
340 !(ObjectHeader
->Flags
& OB_FLAG_PERMANENT
))
342 /* Setup a lookup context */
343 ObpInitializeLookupContext(&Context
);
345 /* Lock the directory */
346 ObpAcquireDirectoryLockExclusive(ObjectNameInfo
->Directory
, &Context
);
349 Object
= ObpLookupEntryDirectory(ObjectNameInfo
->Directory
,
350 &ObjectNameInfo
->Name
,
356 /* Lock the object */
357 ObpAcquireObjectLock(ObjectHeader
);
359 /* Make sure we can still delete the object */
360 if (!(ObjectHeader
->HandleCount
) &&
361 !(ObjectHeader
->Flags
& OB_FLAG_PERMANENT
))
363 /* First delete it from the directory */
364 ObpDeleteEntryDirectory(&Context
);
366 /* Check if this is a symbolic link */
367 if (ObjectType
== ObpSymbolicLinkObjectType
)
369 /* Remove internal name */
370 ObpDeleteSymbolicLinkName(Object
);
373 /* Check if the kernel exclusive is set */
374 ObjectNameInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
375 if ((ObjectNameInfo
) &&
376 (ObjectNameInfo
->QueryReferences
& OB_FLAG_KERNEL_EXCLUSIVE
))
378 /* Remove protection flag */
379 InterlockedExchangeAdd((PLONG
)&ObjectNameInfo
->QueryReferences
,
380 -OB_FLAG_KERNEL_EXCLUSIVE
);
383 /* Get the directory */
384 Directory
= ObjectNameInfo
->Directory
;
387 /* Release the lock */
388 ObpReleaseObjectLock(ObjectHeader
);
391 /* Cleanup after lookup */
392 ObpReleaseLookupContext(&Context
);
394 /* Remove another query reference since we added one on top */
395 ObpDereferenceNameInfo(ObjectNameInfo
);
397 /* Check if we were inserted in a directory */
400 /* We were, so first remove the extra reference we had added */
401 ObpDereferenceNameInfo(ObjectNameInfo
);
403 /* Now dereference the object as well */
404 ObDereferenceObject(Object
);
409 /* Remove the reference we added */
410 ObpDereferenceNameInfo(ObjectNameInfo
);
416 ObpIsUnsecureName(IN PUNICODE_STRING ObjectName
,
417 IN BOOLEAN CaseInSensitive
)
420 PWSTR UnsecureBuffer
;
421 UNICODE_STRING UnsecureName
;
423 /* No unsecure names known, quit */
424 if (ObpUnsecureGlobalNamesBuffer
[0] == UNICODE_NULL
)
429 /* By default, we have a secure name */
431 /* We will browse the whole string */
432 UnsecureBuffer
= &ObpUnsecureGlobalNamesBuffer
[0];
435 /* Initialize the unicode string */
436 RtlInitUnicodeString(&UnsecureName
, UnsecureBuffer
);
437 /* We're at the end of the multisz string! */
438 if (UnsecureName
.Length
== 0)
444 * Does the unsecure name prefix the object name?
445 * If so, that's an unsecure name, and return so
447 if (RtlPrefixUnicodeString(&UnsecureName
, ObjectName
, CaseInSensitive
))
454 * Move to the next string. As a reminder, ObpUnsecureGlobalNamesBuffer is
455 * a multisz, so we move the string next to the current UNICODE_NULL char
457 UnsecureBuffer
= (PWSTR
)((ULONG_PTR
)UnsecureBuffer
+ UnsecureName
.Length
+ sizeof(UNICODE_NULL
));
460 /* Return our findings */
466 ObpLookupObjectName(IN HANDLE RootHandle OPTIONAL
,
467 IN OUT PUNICODE_STRING ObjectName
,
469 IN POBJECT_TYPE ObjectType
,
470 IN KPROCESSOR_MODE AccessMode
,
471 IN OUT PVOID ParseContext
,
472 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
473 IN PVOID InsertObject OPTIONAL
,
474 IN OUT PACCESS_STATE AccessState
,
475 OUT POBP_LOOKUP_CONTEXT LookupContext
,
476 OUT PVOID
*FoundObject
)
479 POBJECT_HEADER ObjectHeader
;
480 UNICODE_STRING ComponentName
, RemainingName
;
481 BOOLEAN Reparse
= FALSE
, SymLink
= FALSE
;
482 POBJECT_DIRECTORY Directory
= NULL
, ParentDirectory
= NULL
, RootDirectory
;
483 POBJECT_DIRECTORY ReferencedDirectory
= NULL
, ReferencedParentDirectory
= NULL
;
485 OB_PARSE_METHOD ParseRoutine
;
487 KPROCESSOR_MODE AccessCheckMode
;
489 POBJECT_HEADER_NAME_INFO ObjectNameInfo
;
490 ULONG MaxReparse
= 30;
492 OBTRACE(OB_NAMESPACE_DEBUG
,
493 "%s - Finding Object: %wZ. Expecting: %p\n",
498 /* Initialize starting state */
499 ObpInitializeLookupContext(LookupContext
);
501 Status
= STATUS_SUCCESS
;
504 /* Check if case-insensitivity is checked */
505 if (ObpCaseInsensitive
)
507 /* Check if the object type requests this */
508 if (!(ObjectType
) || (ObjectType
->TypeInfo
.CaseInsensitive
))
510 /* Add the flag to disable case sensitivity */
511 Attributes
|= OBJ_CASE_INSENSITIVE
;
515 /* Check if this is a access checks are being forced */
516 AccessCheckMode
= (Attributes
& OBJ_FORCE_ACCESS_CHECK
) ?
517 UserMode
: AccessMode
;
519 /* Check if we got a Root Directory */
522 /* We did. Reference it */
523 Status
= ObReferenceObjectByHandle(RootHandle
,
527 (PVOID
*)&RootDirectory
,
529 if (!NT_SUCCESS(Status
)) return Status
;
532 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(RootDirectory
);
534 /* The name cannot start with a separator, unless this is a file */
535 if ((ObjectName
->Buffer
) &&
536 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
) &&
537 (ObjectHeader
->Type
!= IoFileObjectType
))
539 /* The syntax is bad, so fail this request */
540 ObDereferenceObject(RootDirectory
);
541 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
544 /* Don't parse a Directory */
545 if (ObjectHeader
->Type
!= ObpDirectoryObjectType
)
547 /* Make sure the Object Type has a parse routine */
548 ParseRoutine
= ObjectHeader
->Type
->TypeInfo
.ParseProcedure
;
551 /* We can't parse a name if we don't have a parse routine */
552 ObDereferenceObject(RootDirectory
);
553 return STATUS_INVALID_HANDLE
;
556 /* Set default parse count */
562 /* Start with the full name */
563 RemainingName
= *ObjectName
;
565 /* Call the Parse Procedure */
566 ObpCalloutStart(&CalloutIrql
);
567 Status
= ParseRoutine(RootDirectory
,
577 ObpCalloutEnd(CalloutIrql
, "Parse", ObjectHeader
->Type
, Object
);
579 /* Check for success or failure, so not reparse */
580 if ((Status
!= STATUS_REPARSE
) &&
581 (Status
!= STATUS_REPARSE_OBJECT
))
583 /* Check for failure */
584 if (!NT_SUCCESS(Status
))
586 /* Parse routine might not have cleared this, do it */
591 /* Modify status to reflect failure inside Ob */
592 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
595 /* We're done, return the status and object */
596 *FoundObject
= Object
;
597 ObDereferenceObject(RootDirectory
);
600 else if ((!ObjectName
->Length
) ||
601 (!ObjectName
->Buffer
) ||
602 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
604 /* Reparsed to the root directory, so start over */
605 ObDereferenceObject(RootDirectory
);
606 RootDirectory
= ObpRootDirectoryObject
;
608 /* Don't use this anymore, since we're starting at root */
612 else if (--MaxReparse
)
614 /* Try reparsing again */
619 /* Reparsed too many times */
620 ObDereferenceObject(RootDirectory
);
622 /* Return the object and normalized status */
623 *FoundObject
= Object
;
624 if (!Object
) Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
629 else if (!(ObjectName
->Length
) || !(ObjectName
->Buffer
))
631 /* Just return the Root Directory if we didn't get a name */
632 Status
= ObReferenceObjectByPointer(RootDirectory
,
636 if (NT_SUCCESS(Status
)) Object
= RootDirectory
;
638 /* Remove the first reference we added and return the object */
639 ObDereferenceObject(RootDirectory
);
640 *FoundObject
= Object
;
646 /* We did not get a Root Directory, so use the root */
647 RootDirectory
= ObpRootDirectoryObject
;
649 /* It must start with a path separator */
650 if (!(ObjectName
->Length
) ||
651 !(ObjectName
->Buffer
) ||
652 (ObjectName
->Buffer
[0] != OBJ_NAME_PATH_SEPARATOR
))
654 /* This name is invalid, so fail */
655 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
658 /* Check if the name is only the path separator */
659 if (ObjectName
->Length
== sizeof(OBJ_NAME_PATH_SEPARATOR
))
661 /* So the caller only wants the root directory; do we have one? */
664 /* This must be the first time we're creating it... right? */
667 /* Yes, so return it to ObInsert so that it can create it */
668 Status
= ObReferenceObjectByPointer(InsertObject
,
672 if (NT_SUCCESS(Status
)) *FoundObject
= InsertObject
;
677 /* This should never really happen */
679 return STATUS_INVALID_PARAMETER
;
684 /* We do have the root directory, so just return it */
685 Status
= ObReferenceObjectByPointer(RootDirectory
,
689 if (NT_SUCCESS(Status
)) *FoundObject
= RootDirectory
;
696 /* FIXME: Check if we have a device map */
698 /* Check if this is a possible DOS name */
699 if (!((ULONG_PTR
)(ObjectName
->Buffer
) & 7))
702 * This could be one. Does it match the prefix?
703 * Note that as an optimization, the match is done as 64-bit
704 * compare since the prefix is "\??\" which is exactly 8 bytes.
706 * In the second branch, we test for "\??" which is also valid.
707 * This time, we use a 32-bit compare followed by a Unicode
708 * character compare (16-bit), since the sum is 6 bytes.
710 if ((ObjectName
->Length
>= ObpDosDevicesShortName
.Length
) &&
711 (*(PULONGLONG
)(ObjectName
->Buffer
) ==
712 ObpDosDevicesShortNamePrefix
.Alignment
.QuadPart
))
716 else if ((ObjectName
->Length
== ObpDosDevicesShortName
.Length
-
718 (*(PULONG
)(ObjectName
->Buffer
) ==
719 ObpDosDevicesShortNameRoot
.Alignment
.LowPart
) &&
720 (*((PWCHAR
)(ObjectName
->Buffer
) + 2) ==
721 (WCHAR
)(ObpDosDevicesShortNameRoot
.Alignment
.HighPart
)))
729 /* Check if we were reparsing a symbolic link */
738 while (Reparse
&& MaxReparse
)
741 RemainingName
= *ObjectName
;
743 /* Disable reparsing again */
746 /* Start parse loop */
752 /* Check if the name starts with a path separator */
753 if ((RemainingName
.Length
) &&
754 (RemainingName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
756 /* Skip the path separator */
757 RemainingName
.Buffer
++;
758 RemainingName
.Length
-= sizeof(OBJ_NAME_PATH_SEPARATOR
);
761 /* Find the next Part Name */
762 ComponentName
= RemainingName
;
763 while (RemainingName
.Length
)
765 /* Break if we found the \ ending */
766 if (RemainingName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
) break;
769 RemainingName
.Buffer
++;
770 RemainingName
.Length
-= sizeof(OBJ_NAME_PATH_SEPARATOR
);
773 /* Get its size and make sure it's valid */
774 ComponentName
.Length
-= RemainingName
.Length
;
775 if (!ComponentName
.Length
)
777 /* Invalid size, fail */
778 Status
= STATUS_OBJECT_NAME_INVALID
;
782 /* Check if we're in the root */
783 if (!Directory
) Directory
= RootDirectory
;
785 /* Check if this is a user-mode call that needs to traverse */
786 if ((AccessCheckMode
!= KernelMode
) &&
787 !(AccessState
->Flags
& TOKEN_HAS_TRAVERSE_PRIVILEGE
))
789 /* We shouldn't have referenced a directory yet */
790 ASSERT(ReferencedDirectory
== NULL
);
792 /* Reference the directory */
793 ObReferenceObject(Directory
);
794 ReferencedDirectory
= Directory
;
796 /* Check if we have a parent directory */
799 /* Check for traverse access */
800 if (!ObpCheckTraverseAccess(ParentDirectory
,
807 /* We don't have it, fail */
813 /* Check if we don't have a remaining name yet */
814 if (!RemainingName
.Length
)
816 /* Check if we don't have a referenced directory yet */
817 if (!ReferencedDirectory
)
820 ObReferenceObject(Directory
);
821 ReferencedDirectory
= Directory
;
824 /* Check if we are inserting an object */
827 /* Lock the directory */
828 ObpAcquireDirectoryLockExclusive(Directory
, LookupContext
);
833 Object
= ObpLookupEntryDirectory(Directory
,
836 InsertObject
? FALSE
: TRUE
,
840 /* We didn't find it... do we still have a path? */
841 if (RemainingName
.Length
)
843 /* Then tell the caller the path wasn't found */
844 Status
= STATUS_OBJECT_PATH_NOT_FOUND
;
847 else if (!InsertObject
)
849 /* Otherwise, we have a path, but the name isn't valid */
850 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
854 /* Check create access for the object */
855 if (!ObCheckCreateObjectAccess(Directory
,
856 ObjectType
== ObpDirectoryObjectType
?
857 DIRECTORY_CREATE_SUBDIRECTORY
:
858 DIRECTORY_CREATE_OBJECT
,
865 /* We don't have create access, fail */
869 /* Get the object header */
870 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(InsertObject
);
873 * Deny object creation if:
874 * That's a section object or a symbolic link
875 * Which isn't in the same section that root directory
876 * That doesn't have the SeCreateGlobalPrivilege
877 * And that is not a known unsecure name
879 if (RootDirectory
->SessionId
!= -1)
881 if (ObjectHeader
->Type
== MmSectionObjectType
||
882 ObjectHeader
->Type
== ObpSymbolicLinkObjectType
)
884 if (RootDirectory
->SessionId
!= PsGetCurrentProcessSessionId() &&
885 !SeSinglePrivilegeCheck(SeCreateGlobalPrivilege
, AccessCheckMode
) &&
886 !ObpIsUnsecureName(&ComponentName
, BooleanFlagOn(Attributes
, OBJ_CASE_INSENSITIVE
)))
888 Status
= STATUS_ACCESS_DENIED
;
894 /* Create Object Name */
895 NewName
= ExAllocatePoolWithTag(PagedPool
,
896 ComponentName
.Length
,
899 !(ObpInsertEntryDirectory(Directory
,
903 /* Either couldn't allocate the name, or insert failed */
904 if (NewName
) ExFreePoolWithTag(NewName
, OB_NAME_TAG
);
906 /* Fail due to memory reasons */
907 Status
= STATUS_INSUFFICIENT_RESOURCES
;
911 /* Reference newly to be inserted object */
912 ObReferenceObject(InsertObject
);
914 /* Get the name information */
915 ObjectNameInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
917 /* Reference the directory */
918 ObReferenceObject(Directory
);
921 RtlCopyMemory(NewName
,
922 ComponentName
.Buffer
,
923 ComponentName
.Length
);
925 /* Check if we had an old name */
926 if (ObjectNameInfo
->Name
.Buffer
)
929 ExFreePoolWithTag(ObjectNameInfo
->Name
.Buffer
, OB_NAME_TAG
);
933 ObjectNameInfo
->Name
.Buffer
= NewName
;
934 ObjectNameInfo
->Name
.Length
= ComponentName
.Length
;
935 ObjectNameInfo
->Name
.MaximumLength
= ComponentName
.Length
;
937 /* Return Status and the Expected Object */
938 Status
= STATUS_SUCCESS
;
939 Object
= InsertObject
;
941 /* Get out of here */
946 /* We found it, so now get its header */
947 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
950 * Check for a parse Procedure, but don't bother to parse for an insert
951 * unless it's a Symbolic Link, in which case we MUST parse
953 ParseRoutine
= ObjectHeader
->Type
->TypeInfo
.ParseProcedure
;
954 if ((ParseRoutine
) &&
955 (!(InsertObject
) || (ParseRoutine
== ObpParseSymbolicLink
)))
957 /* Use the Root Directory next time */
960 /* Increment the pointer count */
961 InterlockedExchangeAddSizeT(&ObjectHeader
->PointerCount
, 1);
963 /* Cleanup from the first lookup */
964 ObpReleaseLookupContext(LookupContext
);
966 /* Check if we have a referenced directory */
967 if (ReferencedDirectory
)
969 /* We do, dereference it */
970 ObDereferenceObject(ReferencedDirectory
);
971 ReferencedDirectory
= NULL
;
974 /* Check if we have a referenced parent directory */
975 if (ReferencedParentDirectory
)
977 /* We do, dereference it */
978 ObDereferenceObject(ReferencedParentDirectory
);
979 ReferencedParentDirectory
= NULL
;
982 /* Call the Parse Procedure */
983 ObpCalloutStart(&CalloutIrql
);
984 Status
= ParseRoutine(Object
,
994 ObpCalloutEnd(CalloutIrql
, "Parse", ObjectHeader
->Type
, Object
);
996 /* Remove our extra reference */
997 ObDereferenceObject(&ObjectHeader
->Body
);
999 /* Check if we have to reparse */
1000 if ((Status
== STATUS_REPARSE
) ||
1001 (Status
== STATUS_REPARSE_OBJECT
))
1006 if (MaxReparse
== 0)
1012 /* Start over from root if we got sent back there */
1013 if ((Status
== STATUS_REPARSE_OBJECT
) ||
1014 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
1016 /* Check if we got a root directory */
1019 /* Stop using it, because we have a new directory now */
1020 ObDereferenceObject(RootDirectory
);
1025 ParentDirectory
= NULL
;
1026 RootDirectory
= ObpRootDirectoryObject
;
1028 /* Check for reparse status */
1029 if (Status
== STATUS_REPARSE_OBJECT
)
1031 /* Don't reparse again */
1034 /* Did we actually get an object to which to reparse? */
1037 /* We didn't, so set a failure status */
1038 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1042 /* We did, so we're free to parse the new object */
1048 /* This is a symbolic link */
1053 else if (RootDirectory
== ObpRootDirectoryObject
)
1055 /* We got STATUS_REPARSE but are at the Root Directory */
1057 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1061 else if (!NT_SUCCESS(Status
))
1068 /* We didn't reparse but we didn't find the Object Either */
1069 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1072 /* Break out of the loop */
1077 /* No parse routine...do we still have a remaining name? */
1078 if (!RemainingName
.Length
)
1080 /* Are we creating an object? */
1083 /* Check if this is a user-mode call that needs to traverse */
1084 if ((AccessCheckMode
!= KernelMode
) &&
1085 !(AccessState
->Flags
& TOKEN_HAS_TRAVERSE_PRIVILEGE
))
1087 /* Check if we can get it */
1088 if (!ObpCheckTraverseAccess(Directory
,
1095 /* We don't have access, fail */
1101 /* Reference the Object */
1102 Status
= ObReferenceObjectByPointer(Object
,
1106 if (!NT_SUCCESS(Status
)) Object
= NULL
;
1109 /* And get out of the reparse loop */
1114 /* We still have a name; check if this is a directory object */
1115 if (ObjectHeader
->Type
== ObpDirectoryObjectType
)
1117 /* Check if we have a referenced parent directory */
1118 if (ReferencedParentDirectory
)
1120 /* Dereference it */
1121 ObDereferenceObject(ReferencedParentDirectory
);
1124 /* Restart the lookup from this directory */
1125 ReferencedParentDirectory
= ReferencedDirectory
;
1126 ParentDirectory
= Directory
;
1128 ReferencedDirectory
= NULL
;
1132 /* We still have a name, but no parse routine for it */
1133 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
1142 /* Check if we failed */
1143 if (!NT_SUCCESS(Status
))
1145 /* Cleanup after lookup */
1146 ObpReleaseLookupContext(LookupContext
);
1149 /* Check if we have a device map and dereference it if so */
1150 //if (DeviceMap) ObfDereferenceDeviceMap(DeviceMap);
1152 /* Check if we have a referenced directory and dereference it if so */
1153 if (ReferencedDirectory
) ObDereferenceObject(ReferencedDirectory
);
1155 /* Check if we have a referenced parent directory */
1156 if (ReferencedParentDirectory
)
1158 /* We do, dereference it */
1159 ObDereferenceObject(ReferencedParentDirectory
);
1162 /* Set the found object and check if we got one */
1163 *FoundObject
= Object
;
1166 /* Nothing was found. Did we reparse or get success? */
1167 if ((Status
== STATUS_REPARSE
) || (NT_SUCCESS(Status
)))
1169 /* Set correct failure */
1170 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1174 /* Check if we had a root directory */
1175 if (RootHandle
) ObDereferenceObject(RootDirectory
);
1177 /* Return status to caller */
1178 OBTRACE(OB_NAMESPACE_DEBUG
,
1179 "%s - Found Object: %p. Expected: %p\n",
1186 /* PUBLIC FUNCTIONS *********************************************************/
1190 ObQueryNameString(IN PVOID Object
,
1191 OUT POBJECT_NAME_INFORMATION ObjectNameInfo
,
1193 OUT PULONG ReturnLength
)
1195 POBJECT_HEADER_NAME_INFO LocalInfo
;
1196 POBJECT_HEADER ObjectHeader
;
1197 POBJECT_DIRECTORY ParentDirectory
;
1200 BOOLEAN ObjectIsNamed
;
1201 NTSTATUS Status
= STATUS_SUCCESS
;
1203 /* Get the Kernel Meta-Structures */
1204 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
1205 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
1207 /* Check if a Query Name Procedure is available */
1208 if (ObjectHeader
->Type
->TypeInfo
.QueryNameProcedure
)
1210 /* Call the procedure inside SEH */
1211 ObjectIsNamed
= ((LocalInfo
) && (LocalInfo
->Name
.Length
> 0));
1215 Status
= ObjectHeader
->Type
->TypeInfo
.QueryNameProcedure(Object
,
1222 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1224 /* Return the exception code */
1225 Status
= _SEH2_GetExceptionCode();
1232 /* Check if the object doesn't even have a name */
1233 if (!(LocalInfo
) || !(LocalInfo
->Name
.Buffer
))
1235 Status
= STATUS_SUCCESS
;
1239 /* We're returning the name structure */
1240 *ReturnLength
= sizeof(OBJECT_NAME_INFORMATION
);
1242 /* Check if we were given enough space */
1243 if (*ReturnLength
> Length
)
1245 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1249 /* Return an empty buffer */
1250 RtlInitEmptyUnicodeString(&ObjectNameInfo
->Name
, NULL
, 0);
1253 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1255 /* Return the exception code */
1256 Status
= _SEH2_GetExceptionCode();
1264 * Find the size needed for the name. We won't do
1265 * this during the Name Creation loop because we want
1266 * to let the caller know that the buffer isn't big
1267 * enough right at the beginning, not work our way through
1268 * and find out at the end
1272 if (Object
== ObpRootDirectoryObject
)
1274 /* Size of the '\' string */
1275 NameSize
= sizeof(OBJ_NAME_PATH_SEPARATOR
);
1279 /* Get the Object Directory and add name of Object */
1280 ParentDirectory
= LocalInfo
->Directory
;
1281 NameSize
= sizeof(OBJ_NAME_PATH_SEPARATOR
) + LocalInfo
->Name
.Length
;
1283 /* Loop inside the directory to get the top-most one (meaning root) */
1284 while ((ParentDirectory
!= ObpRootDirectoryObject
) && (ParentDirectory
))
1286 /* Get the Name Information */
1287 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(
1288 OBJECT_TO_OBJECT_HEADER(ParentDirectory
));
1290 /* Add the size of the Directory Name */
1291 if (LocalInfo
&& LocalInfo
->Directory
)
1293 /* Size of the '\' string + Directory Name */
1294 NameSize
+= sizeof(OBJ_NAME_PATH_SEPARATOR
) +
1295 LocalInfo
->Name
.Length
;
1297 /* Move to next parent Directory */
1298 ParentDirectory
= LocalInfo
->Directory
;
1302 /* Directory with no name. We append "...\" */
1303 NameSize
+= sizeof(L
"...") + sizeof(OBJ_NAME_PATH_SEPARATOR
);
1309 /* Finally, add the name of the structure and the null char */
1310 *ReturnLength
= NameSize
+
1311 sizeof(OBJECT_NAME_INFORMATION
) +
1312 sizeof(UNICODE_NULL
);
1314 /* Check if we were given enough space */
1315 if (*ReturnLength
> Length
) _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH
);
1318 * Now we will actually create the name. We work backwards because
1319 * it's easier to start off from the Name we have and walk up the
1320 * parent directories. We use the same logic as Name Length calculation.
1322 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
1323 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectNameInfo
+ *ReturnLength
);
1324 *--ObjectName
= UNICODE_NULL
;
1326 /* Check if the object is actually the Root directory */
1327 if (Object
== ObpRootDirectoryObject
)
1329 /* This is already the Root Directory, return "\\" */
1330 *--ObjectName
= OBJ_NAME_PATH_SEPARATOR
;
1331 ObjectNameInfo
->Name
.Length
= (USHORT
)NameSize
;
1332 ObjectNameInfo
->Name
.MaximumLength
= (USHORT
)(NameSize
+
1333 sizeof(UNICODE_NULL
));
1334 ObjectNameInfo
->Name
.Buffer
= ObjectName
;
1335 Status
= STATUS_SUCCESS
;
1339 /* Start by adding the Object's Name */
1340 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1341 LocalInfo
->Name
.Length
);
1342 RtlCopyMemory(ObjectName
,
1343 LocalInfo
->Name
.Buffer
,
1344 LocalInfo
->Name
.Length
);
1346 /* Now parse the Parent directories until we reach the top */
1347 ParentDirectory
= LocalInfo
->Directory
;
1348 while ((ParentDirectory
!= ObpRootDirectoryObject
) && (ParentDirectory
))
1350 /* Get the name information */
1351 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(
1352 OBJECT_TO_OBJECT_HEADER(ParentDirectory
));
1355 *(--ObjectName
) = OBJ_NAME_PATH_SEPARATOR
;
1357 /* Add the Parent Directory's Name */
1358 if (LocalInfo
&& LocalInfo
->Name
.Buffer
)
1361 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1362 LocalInfo
->Name
.Length
);
1363 RtlCopyMemory(ObjectName
,
1364 LocalInfo
->Name
.Buffer
,
1365 LocalInfo
->Name
.Length
);
1367 /* Move to next parent */
1368 ParentDirectory
= LocalInfo
->Directory
;
1372 /* Directory without a name, we add "..." */
1373 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1375 sizeof(UNICODE_NULL
));
1376 RtlCopyMemory(ObjectName
, L
"...", sizeof(L
"..."));
1381 /* Add Root Directory Name */
1382 *(--ObjectName
) = OBJ_NAME_PATH_SEPARATOR
;
1383 ObjectNameInfo
->Name
.Length
= (USHORT
)NameSize
;
1384 ObjectNameInfo
->Name
.MaximumLength
=
1385 (USHORT
)(NameSize
+ sizeof(UNICODE_NULL
));
1386 ObjectNameInfo
->Name
.Buffer
= ObjectName
;
1389 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1391 /* Return the exception code */
1392 Status
= _SEH2_GetExceptionCode();
1396 /* Return success */