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
))
218 * Initialize the \??\GLOBALROOT symbolic link
219 * pointing to the root directory \ .
221 RtlInitUnicodeString(&LinkName
, L
"GLOBALROOT");
222 RtlInitUnicodeString(&TargetName
, L
"");
223 InitializeObjectAttributes(&ObjectAttributes
,
228 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
229 SYMBOLIC_LINK_ALL_ACCESS
,
232 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
235 * Initialize the \??\Global symbolic link pointing to the global
236 * DosDevices directory \?? . It is used to access the global \??
237 * by user-mode components which, by default, use a per-session
238 * DosDevices directory.
240 RtlInitUnicodeString(&LinkName
, L
"Global");
241 InitializeObjectAttributes(&ObjectAttributes
,
246 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
247 SYMBOLIC_LINK_ALL_ACCESS
,
250 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
252 /* Close the directory handle */
254 if (!NT_SUCCESS(Status
))
258 * Initialize the \DosDevices symbolic link pointing to the global
259 * DosDevices directory \?? , for backward compatibility with
260 * Windows NT-2000 systems.
262 RtlCreateUnicodeString(&LinkName
, L
"\\DosDevices");
263 RtlInitUnicodeString(&RootName
, (PCWSTR
)&ObpDosDevicesShortNameRoot
);
264 InitializeObjectAttributes(&ObjectAttributes
,
269 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
270 SYMBOLIC_LINK_ALL_ACCESS
,
273 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
276 ObpFreeDosDevicesProtection(&DosDevicesSD
);
283 * @name ObpDeleteNameCheck
285 * The ObpDeleteNameCheck routine checks if a named object should be
286 * removed from the object directory namespace.
289 * Pointer to the object to check for possible removal.
293 * @remarks An object is removed if the following 4 criteria are met:
294 * 1) The object has 0 handles open
295 * 2) The object is in the directory namespace and has a name
296 * 3) The object is not permanent
301 ObpDeleteNameCheck(IN PVOID Object
)
303 POBJECT_HEADER ObjectHeader
;
304 OBP_LOOKUP_CONTEXT Context
;
305 POBJECT_HEADER_NAME_INFO ObjectNameInfo
;
306 POBJECT_TYPE ObjectType
;
307 PVOID Directory
= NULL
;
309 /* Get object structures */
310 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
311 ObjectNameInfo
= ObpReferenceNameInfo(ObjectHeader
);
312 ObjectType
= ObjectHeader
->Type
;
315 * Check if the handle count is 0, if the object is named,
316 * and if the object isn't a permanent object.
318 if (!(ObjectHeader
->HandleCount
) &&
320 (ObjectNameInfo
->Name
.Length
) &&
321 (ObjectNameInfo
->Directory
) &&
322 !(ObjectHeader
->Flags
& OB_FLAG_PERMANENT
))
324 /* Setup a lookup context */
325 ObpInitializeLookupContext(&Context
);
327 /* Lock the directory */
328 ObpAcquireDirectoryLockExclusive(ObjectNameInfo
->Directory
, &Context
);
331 Object
= ObpLookupEntryDirectory(ObjectNameInfo
->Directory
,
332 &ObjectNameInfo
->Name
,
338 /* Lock the object */
339 ObpAcquireObjectLock(ObjectHeader
);
341 /* Make sure we can still delete the object */
342 if (!(ObjectHeader
->HandleCount
) &&
343 !(ObjectHeader
->Flags
& OB_FLAG_PERMANENT
))
345 /* First delete it from the directory */
346 ObpDeleteEntryDirectory(&Context
);
348 /* Check if this is a symbolic link */
349 if (ObjectType
== ObpSymbolicLinkObjectType
)
351 /* Remove internal name */
352 ObpDeleteSymbolicLinkName(Object
);
355 /* Check if the kernel exclusive is set */
356 ObjectNameInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
357 if ((ObjectNameInfo
) &&
358 (ObjectNameInfo
->QueryReferences
& OB_FLAG_KERNEL_EXCLUSIVE
))
360 /* Remove protection flag */
361 InterlockedExchangeAdd((PLONG
)&ObjectNameInfo
->QueryReferences
,
362 -OB_FLAG_KERNEL_EXCLUSIVE
);
365 /* Get the directory */
366 Directory
= ObjectNameInfo
->Directory
;
369 /* Release the lock */
370 ObpReleaseObjectLock(ObjectHeader
);
373 /* Cleanup after lookup */
374 ObpReleaseLookupContext(&Context
);
376 /* Remove another query reference since we added one on top */
377 ObpDereferenceNameInfo(ObjectNameInfo
);
379 /* Check if we were inserted in a directory */
382 /* We were, so first remove the extra reference we had added */
383 ObpDereferenceNameInfo(ObjectNameInfo
);
385 /* Now dereference the object as well */
386 ObDereferenceObject(Object
);
391 /* Remove the reference we added */
392 ObpDereferenceNameInfo(ObjectNameInfo
);
398 ObpIsUnsecureName(IN PUNICODE_STRING ObjectName
,
399 IN BOOLEAN CaseInSensitive
)
402 PWSTR UnsecureBuffer
;
403 UNICODE_STRING UnsecureName
;
405 /* No unsecure names known, quit */
406 if (ObpUnsecureGlobalNamesBuffer
[0] == UNICODE_NULL
)
411 /* By default, we have a secure name */
413 /* We will browse the whole string */
414 UnsecureBuffer
= &ObpUnsecureGlobalNamesBuffer
[0];
417 /* Initialize the unicode string */
418 RtlInitUnicodeString(&UnsecureName
, UnsecureBuffer
);
419 /* We're at the end of the multisz string! */
420 if (UnsecureName
.Length
== 0)
426 * Does the unsecure name prefix the object name?
427 * If so, that's an unsecure name, and return so
429 if (RtlPrefixUnicodeString(&UnsecureName
, ObjectName
, CaseInSensitive
))
436 * Move to the next string. As a reminder, ObpUnsecureGlobalNamesBuffer is
437 * a multisz, so we move the string next to the current UNICODE_NULL char
439 UnsecureBuffer
= (PWSTR
)((ULONG_PTR
)UnsecureBuffer
+ UnsecureName
.Length
+ sizeof(UNICODE_NULL
));
442 /* Return our findings */
448 ObpLookupObjectName(IN HANDLE RootHandle OPTIONAL
,
449 IN OUT PUNICODE_STRING ObjectName
,
451 IN POBJECT_TYPE ObjectType
,
452 IN KPROCESSOR_MODE AccessMode
,
453 IN OUT PVOID ParseContext
,
454 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
455 IN PVOID InsertObject OPTIONAL
,
456 IN OUT PACCESS_STATE AccessState
,
457 OUT POBP_LOOKUP_CONTEXT LookupContext
,
458 OUT PVOID
*FoundObject
)
461 POBJECT_HEADER ObjectHeader
;
462 UNICODE_STRING ComponentName
, RemainingName
;
463 BOOLEAN Reparse
= FALSE
, SymLink
= FALSE
;
464 POBJECT_DIRECTORY Directory
= NULL
, ParentDirectory
= NULL
, RootDirectory
;
465 POBJECT_DIRECTORY ReferencedDirectory
= NULL
, ReferencedParentDirectory
= NULL
;
467 OB_PARSE_METHOD ParseRoutine
;
469 KPROCESSOR_MODE AccessCheckMode
;
471 POBJECT_HEADER_NAME_INFO ObjectNameInfo
;
472 ULONG MaxReparse
= 30;
473 PDEVICE_MAP DeviceMap
= NULL
;
474 UNICODE_STRING LocalName
;
476 OBTRACE(OB_NAMESPACE_DEBUG
,
477 "%s - Finding Object: %wZ. Expecting: %p\n",
482 /* Initialize starting state */
483 ObpInitializeLookupContext(LookupContext
);
485 Status
= STATUS_SUCCESS
;
488 /* Check if case-insensitivity is checked */
489 if (ObpCaseInsensitive
)
491 /* Check if the object type requests this */
492 if (!(ObjectType
) || (ObjectType
->TypeInfo
.CaseInsensitive
))
494 /* Add the flag to disable case sensitivity */
495 Attributes
|= OBJ_CASE_INSENSITIVE
;
499 /* Check if this is a access checks are being forced */
500 AccessCheckMode
= (Attributes
& OBJ_FORCE_ACCESS_CHECK
) ?
501 UserMode
: AccessMode
;
503 /* Check if we got a Root Directory */
506 /* We did. Reference it */
507 Status
= ObReferenceObjectByHandle(RootHandle
,
511 (PVOID
*)&RootDirectory
,
513 if (!NT_SUCCESS(Status
)) return Status
;
516 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(RootDirectory
);
518 /* The name cannot start with a separator, unless this is a file */
519 if ((ObjectName
->Buffer
) &&
520 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
) &&
521 (ObjectHeader
->Type
!= IoFileObjectType
))
523 /* The syntax is bad, so fail this request */
524 ObDereferenceObject(RootDirectory
);
525 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
528 /* Don't parse a Directory */
529 if (ObjectHeader
->Type
!= ObpDirectoryObjectType
)
531 /* Make sure the Object Type has a parse routine */
532 ParseRoutine
= ObjectHeader
->Type
->TypeInfo
.ParseProcedure
;
535 /* We can't parse a name if we don't have a parse routine */
536 ObDereferenceObject(RootDirectory
);
537 return STATUS_INVALID_HANDLE
;
540 /* Set default parse count */
546 /* Start with the full name */
547 RemainingName
= *ObjectName
;
549 /* Call the Parse Procedure */
550 ObpCalloutStart(&CalloutIrql
);
551 Status
= ParseRoutine(RootDirectory
,
561 ObpCalloutEnd(CalloutIrql
, "Parse", ObjectHeader
->Type
, Object
);
563 /* Check for success or failure, so not reparse */
564 if ((Status
!= STATUS_REPARSE
) &&
565 (Status
!= STATUS_REPARSE_OBJECT
))
567 /* Check for failure */
568 if (!NT_SUCCESS(Status
))
570 /* Parse routine might not have cleared this, do it */
575 /* Modify status to reflect failure inside Ob */
576 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
579 /* We're done, return the status and object */
580 *FoundObject
= Object
;
581 ObDereferenceObject(RootDirectory
);
584 else if ((!ObjectName
->Length
) ||
585 (!ObjectName
->Buffer
) ||
586 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
588 /* Reparsed to the root directory, so start over */
589 ObDereferenceObject(RootDirectory
);
590 RootDirectory
= ObpRootDirectoryObject
;
592 /* Don't use this anymore, since we're starting at root */
596 else if (--MaxReparse
)
598 /* Try reparsing again */
603 /* Reparsed too many times */
604 ObDereferenceObject(RootDirectory
);
606 /* Return the object and normalized status */
607 *FoundObject
= Object
;
608 if (!Object
) Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
613 else if (!(ObjectName
->Length
) || !(ObjectName
->Buffer
))
615 /* Just return the Root Directory if we didn't get a name */
616 Status
= ObReferenceObjectByPointer(RootDirectory
,
620 if (NT_SUCCESS(Status
)) Object
= RootDirectory
;
622 /* Remove the first reference we added and return the object */
623 ObDereferenceObject(RootDirectory
);
624 *FoundObject
= Object
;
628 LocalName
= *ObjectName
;
632 /* We did not get a Root Directory, so use the root */
633 RootDirectory
= ObpRootDirectoryObject
;
635 /* It must start with a path separator */
636 if (!(ObjectName
->Length
) ||
637 !(ObjectName
->Buffer
) ||
638 (ObjectName
->Buffer
[0] != OBJ_NAME_PATH_SEPARATOR
))
640 /* This name is invalid, so fail */
641 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
644 /* Check if the name is only the path separator */
645 if (ObjectName
->Length
== sizeof(OBJ_NAME_PATH_SEPARATOR
))
647 /* So the caller only wants the root directory; do we have one? */
650 /* This must be the first time we're creating it... right? */
653 /* Yes, so return it to ObInsert so that it can create it */
654 Status
= ObReferenceObjectByPointer(InsertObject
,
658 if (NT_SUCCESS(Status
)) *FoundObject
= InsertObject
;
663 /* This should never really happen */
665 return STATUS_INVALID_PARAMETER
;
670 /* We do have the root directory, so just return it */
671 Status
= ObReferenceObjectByPointer(RootDirectory
,
675 if (NT_SUCCESS(Status
)) *FoundObject
= RootDirectory
;
682 LocalName
= *ObjectName
;
684 /* Deference the device map if we already have one */
685 if (DeviceMap
!= NULL
)
687 ObfDereferenceDeviceMap(DeviceMap
);
691 /* Check if this is a possible DOS name */
692 if (!((ULONG_PTR
)(ObjectName
->Buffer
) & 7))
695 * This could be one. Does it match the prefix?
696 * Note that as an optimization, the match is done as 64-bit
697 * compare since the prefix is "\??\" which is exactly 8 bytes.
699 * In the second branch, we test for "\??" which is also valid.
700 * This time, we use a 32-bit compare followed by a Unicode
701 * character compare (16-bit), since the sum is 6 bytes.
703 if ((ObjectName
->Length
>= ObpDosDevicesShortName
.Length
) &&
704 (*(PULONGLONG
)(ObjectName
->Buffer
) ==
705 ObpDosDevicesShortNamePrefix
.Alignment
.QuadPart
))
707 DeviceMap
= ObpReferenceDeviceMap();
708 /* We have a local mapping, drop the ?? prefix */
709 if (DeviceMap
!= NULL
&& DeviceMap
->DosDevicesDirectory
!= NULL
)
711 LocalName
.Length
-= ObpDosDevicesShortName
.Length
;
712 LocalName
.MaximumLength
-= ObpDosDevicesShortName
.Length
;
713 LocalName
.Buffer
+= (ObpDosDevicesShortName
.Length
/ sizeof(WCHAR
));
715 /* We'll browse that local directory */
716 Directory
= DeviceMap
->DosDevicesDirectory
;
719 else if ((ObjectName
->Length
== ObpDosDevicesShortName
.Length
-
721 (*(PULONG
)(ObjectName
->Buffer
) ==
722 ObpDosDevicesShortNameRoot
.Alignment
.LowPart
) &&
723 (*((PWCHAR
)(ObjectName
->Buffer
) + 2) ==
724 (WCHAR
)(ObpDosDevicesShortNameRoot
.Alignment
.HighPart
)))
726 DeviceMap
= ObpReferenceDeviceMap();
728 /* Caller is looking for the directory itself */
729 if (DeviceMap
!= NULL
&& DeviceMap
->DosDevicesDirectory
!= NULL
)
731 Status
= ObReferenceObjectByPointer(DeviceMap
->DosDevicesDirectory
,
735 if (NT_SUCCESS(Status
))
737 *FoundObject
= DeviceMap
->DosDevicesDirectory
;
740 ObfDereferenceDeviceMap(DeviceMap
);
748 /* Check if we were reparsing a symbolic link */
757 while (Reparse
&& MaxReparse
)
760 RemainingName
= LocalName
;
762 /* Disable reparsing again */
765 /* Start parse loop */
771 /* Check if the name starts with a path separator */
772 if ((RemainingName
.Length
) &&
773 (RemainingName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
775 /* Skip the path separator */
776 RemainingName
.Buffer
++;
777 RemainingName
.Length
-= sizeof(OBJ_NAME_PATH_SEPARATOR
);
780 /* Find the next Part Name */
781 ComponentName
= RemainingName
;
782 while (RemainingName
.Length
)
784 /* Break if we found the \ ending */
785 if (RemainingName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
) break;
788 RemainingName
.Buffer
++;
789 RemainingName
.Length
-= sizeof(OBJ_NAME_PATH_SEPARATOR
);
792 /* Get its size and make sure it's valid */
793 ComponentName
.Length
-= RemainingName
.Length
;
794 if (!ComponentName
.Length
)
796 /* Invalid size, fail */
797 Status
= STATUS_OBJECT_NAME_INVALID
;
801 /* Check if we're in the root */
802 if (!Directory
) Directory
= RootDirectory
;
804 /* Check if this is a user-mode call that needs to traverse */
805 if ((AccessCheckMode
!= KernelMode
) &&
806 !(AccessState
->Flags
& TOKEN_HAS_TRAVERSE_PRIVILEGE
))
808 /* We shouldn't have referenced a directory yet */
809 ASSERT(ReferencedDirectory
== NULL
);
811 /* Reference the directory */
812 ObReferenceObject(Directory
);
813 ReferencedDirectory
= Directory
;
815 /* Check if we have a parent directory */
818 /* Check for traverse access */
819 if (!ObpCheckTraverseAccess(ParentDirectory
,
826 /* We don't have it, fail */
832 /* Check if we don't have a remaining name yet */
833 if (!RemainingName
.Length
)
835 /* Check if we don't have a referenced directory yet */
836 if (!ReferencedDirectory
)
839 ObReferenceObject(Directory
);
840 ReferencedDirectory
= Directory
;
843 /* Check if we are inserting an object */
846 /* Lock the directory */
847 ObpAcquireDirectoryLockExclusive(Directory
, LookupContext
);
852 Object
= ObpLookupEntryDirectory(Directory
,
855 InsertObject
? FALSE
: TRUE
,
859 /* We didn't find it... do we still have a path? */
860 if (RemainingName
.Length
)
862 /* Then tell the caller the path wasn't found */
863 Status
= STATUS_OBJECT_PATH_NOT_FOUND
;
866 else if (!InsertObject
)
868 /* Otherwise, we have a path, but the name isn't valid */
869 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
873 /* Check create access for the object */
874 if (!ObCheckCreateObjectAccess(Directory
,
875 ObjectType
== ObpDirectoryObjectType
?
876 DIRECTORY_CREATE_SUBDIRECTORY
:
877 DIRECTORY_CREATE_OBJECT
,
884 /* We don't have create access, fail */
888 /* Get the object header */
889 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(InsertObject
);
892 * Deny object creation if:
893 * That's a section object or a symbolic link
894 * Which isn't in the same section that root directory
895 * That doesn't have the SeCreateGlobalPrivilege
896 * And that is not a known unsecure name
898 if (RootDirectory
->SessionId
!= -1)
900 if (ObjectHeader
->Type
== MmSectionObjectType
||
901 ObjectHeader
->Type
== ObpSymbolicLinkObjectType
)
903 if (RootDirectory
->SessionId
!= PsGetCurrentProcessSessionId() &&
904 !SeSinglePrivilegeCheck(SeCreateGlobalPrivilege
, AccessCheckMode
) &&
905 !ObpIsUnsecureName(&ComponentName
, BooleanFlagOn(Attributes
, OBJ_CASE_INSENSITIVE
)))
907 Status
= STATUS_ACCESS_DENIED
;
913 /* Create Object Name */
914 NewName
= ExAllocatePoolWithTag(PagedPool
,
915 ComponentName
.Length
,
918 !(ObpInsertEntryDirectory(Directory
,
922 /* Either couldn't allocate the name, or insert failed */
923 if (NewName
) ExFreePoolWithTag(NewName
, OB_NAME_TAG
);
925 /* Fail due to memory reasons */
926 Status
= STATUS_INSUFFICIENT_RESOURCES
;
930 /* Reference newly to be inserted object */
931 ObReferenceObject(InsertObject
);
933 /* Get the name information */
934 ObjectNameInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
936 /* Reference the directory */
937 ObReferenceObject(Directory
);
940 RtlCopyMemory(NewName
,
941 ComponentName
.Buffer
,
942 ComponentName
.Length
);
944 /* Check if we had an old name */
945 if (ObjectNameInfo
->Name
.Buffer
)
948 ExFreePoolWithTag(ObjectNameInfo
->Name
.Buffer
, OB_NAME_TAG
);
952 ObjectNameInfo
->Name
.Buffer
= NewName
;
953 ObjectNameInfo
->Name
.Length
= ComponentName
.Length
;
954 ObjectNameInfo
->Name
.MaximumLength
= ComponentName
.Length
;
956 /* Return Status and the Expected Object */
957 Status
= STATUS_SUCCESS
;
958 Object
= InsertObject
;
960 /* Get out of here */
965 /* We found it, so now get its header */
966 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
969 * Check for a parse Procedure, but don't bother to parse for an insert
970 * unless it's a Symbolic Link, in which case we MUST parse
972 ParseRoutine
= ObjectHeader
->Type
->TypeInfo
.ParseProcedure
;
973 if ((ParseRoutine
) &&
974 (!(InsertObject
) || (ParseRoutine
== ObpParseSymbolicLink
)))
976 /* Use the Root Directory next time */
979 /* Increment the pointer count */
980 InterlockedExchangeAddSizeT(&ObjectHeader
->PointerCount
, 1);
982 /* Cleanup from the first lookup */
983 ObpReleaseLookupContext(LookupContext
);
985 /* Check if we have a referenced directory */
986 if (ReferencedDirectory
)
988 /* We do, dereference it */
989 ObDereferenceObject(ReferencedDirectory
);
990 ReferencedDirectory
= NULL
;
993 /* Check if we have a referenced parent directory */
994 if (ReferencedParentDirectory
)
996 /* We do, dereference it */
997 ObDereferenceObject(ReferencedParentDirectory
);
998 ReferencedParentDirectory
= NULL
;
1001 /* Call the Parse Procedure */
1002 ObpCalloutStart(&CalloutIrql
);
1003 Status
= ParseRoutine(Object
,
1013 ObpCalloutEnd(CalloutIrql
, "Parse", ObjectHeader
->Type
, Object
);
1015 /* Remove our extra reference */
1016 ObDereferenceObject(&ObjectHeader
->Body
);
1018 /* Check if we have to reparse */
1019 if ((Status
== STATUS_REPARSE
) ||
1020 (Status
== STATUS_REPARSE_OBJECT
))
1025 if (MaxReparse
== 0)
1031 /* Start over from root if we got sent back there */
1032 if ((Status
== STATUS_REPARSE_OBJECT
) ||
1033 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
1035 /* Check if we got a root directory */
1038 /* Stop using it, because we have a new directory now */
1039 ObDereferenceObject(RootDirectory
);
1044 ParentDirectory
= NULL
;
1045 RootDirectory
= ObpRootDirectoryObject
;
1047 /* Check for reparse status */
1048 if (Status
== STATUS_REPARSE_OBJECT
)
1050 /* Don't reparse again */
1053 /* Did we actually get an object to which to reparse? */
1056 /* We didn't, so set a failure status */
1057 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1061 /* We did, so we're free to parse the new object */
1067 /* This is a symbolic link */
1072 else if (RootDirectory
== ObpRootDirectoryObject
)
1074 /* We got STATUS_REPARSE but are at the Root Directory */
1076 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1080 else if (!NT_SUCCESS(Status
))
1087 /* We didn't reparse but we didn't find the Object Either */
1088 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1091 /* Break out of the loop */
1096 /* No parse routine...do we still have a remaining name? */
1097 if (!RemainingName
.Length
)
1099 /* Are we creating an object? */
1102 /* Check if this is a user-mode call that needs to traverse */
1103 if ((AccessCheckMode
!= KernelMode
) &&
1104 !(AccessState
->Flags
& TOKEN_HAS_TRAVERSE_PRIVILEGE
))
1106 /* Check if we can get it */
1107 if (!ObpCheckTraverseAccess(Directory
,
1114 /* We don't have access, fail */
1120 /* Reference the Object */
1121 Status
= ObReferenceObjectByPointer(Object
,
1125 if (!NT_SUCCESS(Status
)) Object
= NULL
;
1128 /* And get out of the reparse loop */
1133 /* We still have a name; check if this is a directory object */
1134 if (ObjectHeader
->Type
== ObpDirectoryObjectType
)
1136 /* Check if we have a referenced parent directory */
1137 if (ReferencedParentDirectory
)
1139 /* Dereference it */
1140 ObDereferenceObject(ReferencedParentDirectory
);
1143 /* Restart the lookup from this directory */
1144 ReferencedParentDirectory
= ReferencedDirectory
;
1145 ParentDirectory
= Directory
;
1147 ReferencedDirectory
= NULL
;
1151 /* We still have a name, but no parse routine for it */
1152 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
1161 /* Check if we failed */
1162 if (!NT_SUCCESS(Status
))
1164 /* Cleanup after lookup */
1165 ObpReleaseLookupContext(LookupContext
);
1168 /* Check if we have a device map and dereference it if so */
1169 if (DeviceMap
) ObfDereferenceDeviceMap(DeviceMap
);
1171 /* Check if we have a referenced directory and dereference it if so */
1172 if (ReferencedDirectory
) ObDereferenceObject(ReferencedDirectory
);
1174 /* Check if we have a referenced parent directory */
1175 if (ReferencedParentDirectory
)
1177 /* We do, dereference it */
1178 ObDereferenceObject(ReferencedParentDirectory
);
1181 /* Set the found object and check if we got one */
1182 *FoundObject
= Object
;
1185 /* Nothing was found. Did we reparse or get success? */
1186 if ((Status
== STATUS_REPARSE
) || (NT_SUCCESS(Status
)))
1188 /* Set correct failure */
1189 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1193 /* Check if we had a root directory */
1194 if (RootHandle
) ObDereferenceObject(RootDirectory
);
1196 /* Return status to caller */
1197 OBTRACE(OB_NAMESPACE_DEBUG
,
1198 "%s - Found Object: %p. Expected: %p\n",
1205 /* PUBLIC FUNCTIONS *********************************************************/
1209 ObQueryNameString(IN PVOID Object
,
1210 OUT POBJECT_NAME_INFORMATION ObjectNameInfo
,
1212 OUT PULONG ReturnLength
)
1214 POBJECT_HEADER_NAME_INFO LocalInfo
;
1215 POBJECT_HEADER ObjectHeader
;
1216 POBJECT_DIRECTORY ParentDirectory
;
1219 BOOLEAN ObjectIsNamed
;
1220 NTSTATUS Status
= STATUS_SUCCESS
;
1222 /* Get the Kernel Meta-Structures */
1223 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
1224 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
1226 /* Check if a Query Name Procedure is available */
1227 if (ObjectHeader
->Type
->TypeInfo
.QueryNameProcedure
)
1229 /* Call the procedure inside SEH */
1230 ObjectIsNamed
= ((LocalInfo
) && (LocalInfo
->Name
.Length
> 0));
1234 Status
= ObjectHeader
->Type
->TypeInfo
.QueryNameProcedure(Object
,
1241 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1243 /* Return the exception code */
1244 Status
= _SEH2_GetExceptionCode();
1251 /* Check if the object doesn't even have a name */
1252 if (!(LocalInfo
) || !(LocalInfo
->Name
.Buffer
))
1254 Status
= STATUS_SUCCESS
;
1258 /* We're returning the name structure */
1259 *ReturnLength
= sizeof(OBJECT_NAME_INFORMATION
);
1261 /* Check if we were given enough space */
1262 if (*ReturnLength
> Length
)
1264 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1268 /* Return an empty buffer */
1269 RtlInitEmptyUnicodeString(&ObjectNameInfo
->Name
, NULL
, 0);
1272 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1274 /* Return the exception code */
1275 Status
= _SEH2_GetExceptionCode();
1283 * Find the size needed for the name. We won't do
1284 * this during the Name Creation loop because we want
1285 * to let the caller know that the buffer isn't big
1286 * enough right at the beginning, not work our way through
1287 * and find out at the end
1291 if (Object
== ObpRootDirectoryObject
)
1293 /* Size of the '\' string */
1294 NameSize
= sizeof(OBJ_NAME_PATH_SEPARATOR
);
1298 /* Get the Object Directory and add name of Object */
1299 ParentDirectory
= LocalInfo
->Directory
;
1300 NameSize
= sizeof(OBJ_NAME_PATH_SEPARATOR
) + LocalInfo
->Name
.Length
;
1302 /* Loop inside the directory to get the top-most one (meaning root) */
1303 while ((ParentDirectory
!= ObpRootDirectoryObject
) && (ParentDirectory
))
1305 /* Get the Name Information */
1306 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(
1307 OBJECT_TO_OBJECT_HEADER(ParentDirectory
));
1309 /* Add the size of the Directory Name */
1310 if (LocalInfo
&& LocalInfo
->Directory
)
1312 /* Size of the '\' string + Directory Name */
1313 NameSize
+= sizeof(OBJ_NAME_PATH_SEPARATOR
) +
1314 LocalInfo
->Name
.Length
;
1316 /* Move to next parent Directory */
1317 ParentDirectory
= LocalInfo
->Directory
;
1321 /* Directory with no name. We append "...\" */
1322 NameSize
+= sizeof(L
"...") + sizeof(OBJ_NAME_PATH_SEPARATOR
);
1328 /* Finally, add the name of the structure and the null char */
1329 *ReturnLength
= NameSize
+
1330 sizeof(OBJECT_NAME_INFORMATION
) +
1331 sizeof(UNICODE_NULL
);
1333 /* Check if we were given enough space */
1334 if (*ReturnLength
> Length
) _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH
);
1337 * Now we will actually create the name. We work backwards because
1338 * it's easier to start off from the Name we have and walk up the
1339 * parent directories. We use the same logic as Name Length calculation.
1341 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
1342 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectNameInfo
+ *ReturnLength
);
1343 *--ObjectName
= UNICODE_NULL
;
1345 /* Check if the object is actually the Root directory */
1346 if (Object
== ObpRootDirectoryObject
)
1348 /* This is already the Root Directory, return "\\" */
1349 *--ObjectName
= OBJ_NAME_PATH_SEPARATOR
;
1350 ObjectNameInfo
->Name
.Length
= (USHORT
)NameSize
;
1351 ObjectNameInfo
->Name
.MaximumLength
= (USHORT
)(NameSize
+
1352 sizeof(UNICODE_NULL
));
1353 ObjectNameInfo
->Name
.Buffer
= ObjectName
;
1354 Status
= STATUS_SUCCESS
;
1358 /* Start by adding the Object's Name */
1359 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1360 LocalInfo
->Name
.Length
);
1361 RtlCopyMemory(ObjectName
,
1362 LocalInfo
->Name
.Buffer
,
1363 LocalInfo
->Name
.Length
);
1365 /* Now parse the Parent directories until we reach the top */
1366 ParentDirectory
= LocalInfo
->Directory
;
1367 while ((ParentDirectory
!= ObpRootDirectoryObject
) && (ParentDirectory
))
1369 /* Get the name information */
1370 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(
1371 OBJECT_TO_OBJECT_HEADER(ParentDirectory
));
1374 *(--ObjectName
) = OBJ_NAME_PATH_SEPARATOR
;
1376 /* Add the Parent Directory's Name */
1377 if (LocalInfo
&& LocalInfo
->Name
.Buffer
)
1380 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1381 LocalInfo
->Name
.Length
);
1382 RtlCopyMemory(ObjectName
,
1383 LocalInfo
->Name
.Buffer
,
1384 LocalInfo
->Name
.Length
);
1386 /* Move to next parent */
1387 ParentDirectory
= LocalInfo
->Directory
;
1391 /* Directory without a name, we add "..." */
1392 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1394 sizeof(UNICODE_NULL
));
1395 RtlCopyMemory(ObjectName
, L
"...", sizeof(L
"..."));
1400 /* Add Root Directory Name */
1401 *(--ObjectName
) = OBJ_NAME_PATH_SEPARATOR
;
1402 ObjectNameInfo
->Name
.Length
= (USHORT
)NameSize
;
1403 ObjectNameInfo
->Name
.MaximumLength
=
1404 (USHORT
)(NameSize
+ sizeof(UNICODE_NULL
));
1405 ObjectNameInfo
->Name
.Buffer
= ObjectName
;
1408 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1410 /* Return the exception code */
1411 Status
= _SEH2_GetExceptionCode();
1415 /* Return success */