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 ObpFreeDosDevicesProtection(OUT PSECURITY_DESCRIPTOR SecurityDescriptor
)
151 BOOLEAN DaclPresent
, DaclDefaulted
;
153 Status
= RtlGetDaclSecurityDescriptor(SecurityDescriptor
, &DaclPresent
, &Dacl
, &DaclDefaulted
);
154 ASSERT(NT_SUCCESS(Status
));
156 ASSERT(Dacl
!= NULL
);
157 ExFreePoolWithTag(Dacl
, 'lcaD');
163 ObpCreateDosDevicesDirectory(VOID
)
165 OBJECT_ATTRIBUTES ObjectAttributes
;
166 UNICODE_STRING RootName
, TargetName
, LinkName
;
167 HANDLE Handle
, SymHandle
;
168 SECURITY_DESCRIPTOR DosDevicesSD
;
171 /* Create a custom security descriptor for the global DosDevices directory */
172 Status
= ObpGetDosDevicesProtection(&DosDevicesSD
);
173 if (!NT_SUCCESS(Status
))
176 /* Create the global DosDevices directory \?? */
177 RtlInitUnicodeString(&RootName
, L
"\\GLOBAL??");
178 InitializeObjectAttributes(&ObjectAttributes
,
183 Status
= NtCreateDirectoryObject(&Handle
,
184 DIRECTORY_ALL_ACCESS
,
186 if (!NT_SUCCESS(Status
))
189 /* Create the system device map */
190 Status
= ObSetDeviceMap(NULL
, Handle
);
191 if (!NT_SUCCESS(Status
))
194 /*********************************************\
195 |*** HACK until we support device mappings ***|
196 |*** Add a symlink \??\ <--> \GLOBAL??\ ***|
197 \*********************************************/
198 RtlInitUnicodeString(&LinkName
, L
"\\??");
199 InitializeObjectAttributes(&ObjectAttributes
,
204 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
205 SYMBOLIC_LINK_ALL_ACCESS
,
208 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
209 /*********************************************\
210 \*********************************************/
212 // FIXME: Create a device mapping for the global \?? directory
215 * Initialize the \??\GLOBALROOT symbolic link
216 * pointing to the root directory \ .
218 RtlInitUnicodeString(&LinkName
, L
"GLOBALROOT");
219 RtlInitUnicodeString(&TargetName
, L
"");
220 InitializeObjectAttributes(&ObjectAttributes
,
225 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
226 SYMBOLIC_LINK_ALL_ACCESS
,
229 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
232 * Initialize the \??\Global symbolic link pointing to the global
233 * DosDevices directory \?? . It is used to access the global \??
234 * by user-mode components which, by default, use a per-session
235 * DosDevices directory.
237 RtlInitUnicodeString(&LinkName
, L
"Global");
238 InitializeObjectAttributes(&ObjectAttributes
,
243 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
244 SYMBOLIC_LINK_ALL_ACCESS
,
247 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
249 /* Close the directory handle */
251 if (!NT_SUCCESS(Status
))
255 * Initialize the \DosDevices symbolic link pointing to the global
256 * DosDevices directory \?? , for backward compatibility with
257 * Windows NT-2000 systems.
259 RtlCreateUnicodeString(&LinkName
, L
"\\DosDevices");
260 RtlInitUnicodeString(&RootName
, (PCWSTR
)&ObpDosDevicesShortNameRoot
);
261 InitializeObjectAttributes(&ObjectAttributes
,
266 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
267 SYMBOLIC_LINK_ALL_ACCESS
,
270 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
273 ObpFreeDosDevicesProtection(&DosDevicesSD
);
280 * @name ObpDeleteNameCheck
282 * The ObpDeleteNameCheck routine checks if a named object should be
283 * removed from the object directory namespace.
286 * Pointer to the object to check for possible removal.
290 * @remarks An object is removed if the following 4 criteria are met:
291 * 1) The object has 0 handles open
292 * 2) The object is in the directory namespace and has a name
293 * 3) The object is not permanent
298 ObpDeleteNameCheck(IN PVOID Object
)
300 POBJECT_HEADER ObjectHeader
;
301 OBP_LOOKUP_CONTEXT Context
;
302 POBJECT_HEADER_NAME_INFO ObjectNameInfo
;
303 POBJECT_TYPE ObjectType
;
304 PVOID Directory
= NULL
;
306 /* Get object structures */
307 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
308 ObjectNameInfo
= ObpReferenceNameInfo(ObjectHeader
);
309 ObjectType
= ObjectHeader
->Type
;
312 * Check if the handle count is 0, if the object is named,
313 * and if the object isn't a permanent object.
315 if (!(ObjectHeader
->HandleCount
) &&
317 (ObjectNameInfo
->Name
.Length
) &&
318 (ObjectNameInfo
->Directory
) &&
319 !(ObjectHeader
->Flags
& OB_FLAG_PERMANENT
))
321 /* Setup a lookup context */
322 ObpInitializeLookupContext(&Context
);
324 /* Lock the directory */
325 ObpAcquireDirectoryLockExclusive(ObjectNameInfo
->Directory
, &Context
);
328 Object
= ObpLookupEntryDirectory(ObjectNameInfo
->Directory
,
329 &ObjectNameInfo
->Name
,
335 /* Lock the object */
336 ObpAcquireObjectLock(ObjectHeader
);
338 /* Make sure we can still delete the object */
339 if (!(ObjectHeader
->HandleCount
) &&
340 !(ObjectHeader
->Flags
& OB_FLAG_PERMANENT
))
342 /* First delete it from the directory */
343 ObpDeleteEntryDirectory(&Context
);
345 /* Check if this is a symbolic link */
346 if (ObjectType
== ObpSymbolicLinkObjectType
)
348 /* Remove internal name */
349 ObpDeleteSymbolicLinkName(Object
);
352 /* Check if the kernel exclusive is set */
353 ObjectNameInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
354 if ((ObjectNameInfo
) &&
355 (ObjectNameInfo
->QueryReferences
& OB_FLAG_KERNEL_EXCLUSIVE
))
357 /* Remove protection flag */
358 InterlockedExchangeAdd((PLONG
)&ObjectNameInfo
->QueryReferences
,
359 -OB_FLAG_KERNEL_EXCLUSIVE
);
362 /* Get the directory */
363 Directory
= ObjectNameInfo
->Directory
;
366 /* Release the lock */
367 ObpReleaseObjectLock(ObjectHeader
);
370 /* Cleanup after lookup */
371 ObpReleaseLookupContext(&Context
);
373 /* Remove another query reference since we added one on top */
374 ObpDereferenceNameInfo(ObjectNameInfo
);
376 /* Check if we were inserted in a directory */
379 /* We were, so first remove the extra reference we had added */
380 ObpDereferenceNameInfo(ObjectNameInfo
);
382 /* Now dereference the object as well */
383 ObDereferenceObject(Object
);
388 /* Remove the reference we added */
389 ObpDereferenceNameInfo(ObjectNameInfo
);
395 ObpIsUnsecureName(IN PUNICODE_STRING ObjectName
,
396 IN BOOLEAN CaseInSensitive
)
399 PWSTR UnsecureBuffer
;
400 UNICODE_STRING UnsecureName
;
402 /* No unsecure names known, quit */
403 if (ObpUnsecureGlobalNamesBuffer
[0] == UNICODE_NULL
)
408 /* By default, we have a secure name */
410 /* We will browse the whole string */
411 UnsecureBuffer
= &ObpUnsecureGlobalNamesBuffer
[0];
414 /* Initialize the unicode string */
415 RtlInitUnicodeString(&UnsecureName
, UnsecureBuffer
);
416 /* We're at the end of the multisz string! */
417 if (UnsecureName
.Length
== 0)
423 * Does the unsecure name prefix the object name?
424 * If so, that's an unsecure name, and return so
426 if (RtlPrefixUnicodeString(&UnsecureName
, ObjectName
, CaseInSensitive
))
433 * Move to the next string. As a reminder, ObpUnsecureGlobalNamesBuffer is
434 * a multisz, so we move the string next to the current UNICODE_NULL char
436 UnsecureBuffer
= (PWSTR
)((ULONG_PTR
)UnsecureBuffer
+ UnsecureName
.Length
+ sizeof(UNICODE_NULL
));
439 /* Return our findings */
445 ObpLookupObjectName(IN HANDLE RootHandle OPTIONAL
,
446 IN OUT PUNICODE_STRING ObjectName
,
448 IN POBJECT_TYPE ObjectType
,
449 IN KPROCESSOR_MODE AccessMode
,
450 IN OUT PVOID ParseContext
,
451 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
452 IN PVOID InsertObject OPTIONAL
,
453 IN OUT PACCESS_STATE AccessState
,
454 OUT POBP_LOOKUP_CONTEXT LookupContext
,
455 OUT PVOID
*FoundObject
)
458 POBJECT_HEADER ObjectHeader
;
459 UNICODE_STRING ComponentName
, RemainingName
;
460 BOOLEAN Reparse
= FALSE
, SymLink
= FALSE
;
461 POBJECT_DIRECTORY Directory
= NULL
, ParentDirectory
= NULL
, RootDirectory
;
462 POBJECT_DIRECTORY ReferencedDirectory
= NULL
, ReferencedParentDirectory
= NULL
;
464 OB_PARSE_METHOD ParseRoutine
;
466 KPROCESSOR_MODE AccessCheckMode
;
468 POBJECT_HEADER_NAME_INFO ObjectNameInfo
;
469 ULONG MaxReparse
= 30;
471 OBTRACE(OB_NAMESPACE_DEBUG
,
472 "%s - Finding Object: %wZ. Expecting: %p\n",
477 /* Initialize starting state */
478 ObpInitializeLookupContext(LookupContext
);
480 Status
= STATUS_SUCCESS
;
483 /* Check if case-insensitivity is checked */
484 if (ObpCaseInsensitive
)
486 /* Check if the object type requests this */
487 if (!(ObjectType
) || (ObjectType
->TypeInfo
.CaseInsensitive
))
489 /* Add the flag to disable case sensitivity */
490 Attributes
|= OBJ_CASE_INSENSITIVE
;
494 /* Check if this is a access checks are being forced */
495 AccessCheckMode
= (Attributes
& OBJ_FORCE_ACCESS_CHECK
) ?
496 UserMode
: AccessMode
;
498 /* Check if we got a Root Directory */
501 /* We did. Reference it */
502 Status
= ObReferenceObjectByHandle(RootHandle
,
506 (PVOID
*)&RootDirectory
,
508 if (!NT_SUCCESS(Status
)) return Status
;
511 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(RootDirectory
);
513 /* The name cannot start with a separator, unless this is a file */
514 if ((ObjectName
->Buffer
) &&
515 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
) &&
516 (ObjectHeader
->Type
!= IoFileObjectType
))
518 /* The syntax is bad, so fail this request */
519 ObDereferenceObject(RootDirectory
);
520 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
523 /* Don't parse a Directory */
524 if (ObjectHeader
->Type
!= ObpDirectoryObjectType
)
526 /* Make sure the Object Type has a parse routine */
527 ParseRoutine
= ObjectHeader
->Type
->TypeInfo
.ParseProcedure
;
530 /* We can't parse a name if we don't have a parse routine */
531 ObDereferenceObject(RootDirectory
);
532 return STATUS_INVALID_HANDLE
;
535 /* Set default parse count */
541 /* Start with the full name */
542 RemainingName
= *ObjectName
;
544 /* Call the Parse Procedure */
545 ObpCalloutStart(&CalloutIrql
);
546 Status
= ParseRoutine(RootDirectory
,
556 ObpCalloutEnd(CalloutIrql
, "Parse", ObjectHeader
->Type
, Object
);
558 /* Check for success or failure, so not reparse */
559 if ((Status
!= STATUS_REPARSE
) &&
560 (Status
!= STATUS_REPARSE_OBJECT
))
562 /* Check for failure */
563 if (!NT_SUCCESS(Status
))
565 /* Parse routine might not have cleared this, do it */
570 /* Modify status to reflect failure inside Ob */
571 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
574 /* We're done, return the status and object */
575 *FoundObject
= Object
;
576 ObDereferenceObject(RootDirectory
);
579 else if ((!ObjectName
->Length
) ||
580 (!ObjectName
->Buffer
) ||
581 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
583 /* Reparsed to the root directory, so start over */
584 ObDereferenceObject(RootDirectory
);
585 RootDirectory
= ObpRootDirectoryObject
;
587 /* Don't use this anymore, since we're starting at root */
591 else if (--MaxReparse
)
593 /* Try reparsing again */
598 /* Reparsed too many times */
599 ObDereferenceObject(RootDirectory
);
601 /* Return the object and normalized status */
602 *FoundObject
= Object
;
603 if (!Object
) Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
608 else if (!(ObjectName
->Length
) || !(ObjectName
->Buffer
))
610 /* Just return the Root Directory if we didn't get a name */
611 Status
= ObReferenceObjectByPointer(RootDirectory
,
615 if (NT_SUCCESS(Status
)) Object
= RootDirectory
;
617 /* Remove the first reference we added and return the object */
618 ObDereferenceObject(RootDirectory
);
619 *FoundObject
= Object
;
625 /* We did not get a Root Directory, so use the root */
626 RootDirectory
= ObpRootDirectoryObject
;
628 /* It must start with a path separator */
629 if (!(ObjectName
->Length
) ||
630 !(ObjectName
->Buffer
) ||
631 (ObjectName
->Buffer
[0] != OBJ_NAME_PATH_SEPARATOR
))
633 /* This name is invalid, so fail */
634 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
637 /* Check if the name is only the path separator */
638 if (ObjectName
->Length
== sizeof(OBJ_NAME_PATH_SEPARATOR
))
640 /* So the caller only wants the root directory; do we have one? */
643 /* This must be the first time we're creating it... right? */
646 /* Yes, so return it to ObInsert so that it can create it */
647 Status
= ObReferenceObjectByPointer(InsertObject
,
651 if (NT_SUCCESS(Status
)) *FoundObject
= InsertObject
;
656 /* This should never really happen */
658 return STATUS_INVALID_PARAMETER
;
663 /* We do have the root directory, so just return it */
664 Status
= ObReferenceObjectByPointer(RootDirectory
,
668 if (NT_SUCCESS(Status
)) *FoundObject
= RootDirectory
;
675 /* FIXME: Check if we have a device map */
677 /* Check if this is a possible DOS name */
678 if (!((ULONG_PTR
)(ObjectName
->Buffer
) & 7))
681 * This could be one. Does it match the prefix?
682 * Note that as an optimization, the match is done as 64-bit
683 * compare since the prefix is "\??\" which is exactly 8 bytes.
685 * In the second branch, we test for "\??" which is also valid.
686 * This time, we use a 32-bit compare followed by a Unicode
687 * character compare (16-bit), since the sum is 6 bytes.
689 if ((ObjectName
->Length
>= ObpDosDevicesShortName
.Length
) &&
690 (*(PULONGLONG
)(ObjectName
->Buffer
) ==
691 ObpDosDevicesShortNamePrefix
.Alignment
.QuadPart
))
695 else if ((ObjectName
->Length
== ObpDosDevicesShortName
.Length
-
697 (*(PULONG
)(ObjectName
->Buffer
) ==
698 ObpDosDevicesShortNameRoot
.Alignment
.LowPart
) &&
699 (*((PWCHAR
)(ObjectName
->Buffer
) + 2) ==
700 (WCHAR
)(ObpDosDevicesShortNameRoot
.Alignment
.HighPart
)))
708 /* Check if we were reparsing a symbolic link */
717 while (Reparse
&& MaxReparse
)
720 RemainingName
= *ObjectName
;
722 /* Disable reparsing again */
725 /* Start parse loop */
731 /* Check if the name starts with a path separator */
732 if ((RemainingName
.Length
) &&
733 (RemainingName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
735 /* Skip the path separator */
736 RemainingName
.Buffer
++;
737 RemainingName
.Length
-= sizeof(OBJ_NAME_PATH_SEPARATOR
);
740 /* Find the next Part Name */
741 ComponentName
= RemainingName
;
742 while (RemainingName
.Length
)
744 /* Break if we found the \ ending */
745 if (RemainingName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
) break;
748 RemainingName
.Buffer
++;
749 RemainingName
.Length
-= sizeof(OBJ_NAME_PATH_SEPARATOR
);
752 /* Get its size and make sure it's valid */
753 ComponentName
.Length
-= RemainingName
.Length
;
754 if (!ComponentName
.Length
)
756 /* Invalid size, fail */
757 Status
= STATUS_OBJECT_NAME_INVALID
;
761 /* Check if we're in the root */
762 if (!Directory
) Directory
= RootDirectory
;
764 /* Check if this is a user-mode call that needs to traverse */
765 if ((AccessCheckMode
!= KernelMode
) &&
766 !(AccessState
->Flags
& TOKEN_HAS_TRAVERSE_PRIVILEGE
))
768 /* We shouldn't have referenced a directory yet */
769 ASSERT(ReferencedDirectory
== NULL
);
771 /* Reference the directory */
772 ObReferenceObject(Directory
);
773 ReferencedDirectory
= Directory
;
775 /* Check if we have a parent directory */
778 /* Check for traverse access */
779 if (!ObpCheckTraverseAccess(ParentDirectory
,
786 /* We don't have it, fail */
792 /* Check if we don't have a remaining name yet */
793 if (!RemainingName
.Length
)
795 /* Check if we don't have a referenced directory yet */
796 if (!ReferencedDirectory
)
799 ObReferenceObject(Directory
);
800 ReferencedDirectory
= Directory
;
803 /* Check if we are inserting an object */
806 /* Lock the directory */
807 ObpAcquireDirectoryLockExclusive(Directory
, LookupContext
);
812 Object
= ObpLookupEntryDirectory(Directory
,
815 InsertObject
? FALSE
: TRUE
,
819 /* We didn't find it... do we still have a path? */
820 if (RemainingName
.Length
)
822 /* Then tell the caller the path wasn't found */
823 Status
= STATUS_OBJECT_PATH_NOT_FOUND
;
826 else if (!InsertObject
)
828 /* Otherwise, we have a path, but the name isn't valid */
829 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
833 /* Check create access for the object */
834 if (!ObCheckCreateObjectAccess(Directory
,
835 ObjectType
== ObpDirectoryObjectType
?
836 DIRECTORY_CREATE_SUBDIRECTORY
:
837 DIRECTORY_CREATE_OBJECT
,
844 /* We don't have create access, fail */
848 /* Get the object header */
849 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(InsertObject
);
852 * Deny object creation if:
853 * That's a section object or a symbolic link
854 * Which isn't in the same section that root directory
855 * That doesn't have the SeCreateGlobalPrivilege
856 * And that is not a known unsecure name
858 if (RootDirectory
->SessionId
!= -1)
860 if (ObjectHeader
->Type
== MmSectionObjectType
||
861 ObjectHeader
->Type
== ObpSymbolicLinkObjectType
)
863 if (RootDirectory
->SessionId
!= PsGetCurrentProcessSessionId() &&
864 !SeSinglePrivilegeCheck(SeCreateGlobalPrivilege
, AccessCheckMode
) &&
865 !ObpIsUnsecureName(&ComponentName
, BooleanFlagOn(Attributes
, OBJ_CASE_INSENSITIVE
)))
867 Status
= STATUS_ACCESS_DENIED
;
873 /* Create Object Name */
874 NewName
= ExAllocatePoolWithTag(PagedPool
,
875 ComponentName
.Length
,
878 !(ObpInsertEntryDirectory(Directory
,
882 /* Either couldn't allocate the name, or insert failed */
883 if (NewName
) ExFreePoolWithTag(NewName
, OB_NAME_TAG
);
885 /* Fail due to memory reasons */
886 Status
= STATUS_INSUFFICIENT_RESOURCES
;
890 /* Reference newly to be inserted object */
891 ObReferenceObject(InsertObject
);
893 /* Get the name information */
894 ObjectNameInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
896 /* Reference the directory */
897 ObReferenceObject(Directory
);
900 RtlCopyMemory(NewName
,
901 ComponentName
.Buffer
,
902 ComponentName
.Length
);
904 /* Check if we had an old name */
905 if (ObjectNameInfo
->Name
.Buffer
)
908 ExFreePoolWithTag(ObjectNameInfo
->Name
.Buffer
, OB_NAME_TAG
);
912 ObjectNameInfo
->Name
.Buffer
= NewName
;
913 ObjectNameInfo
->Name
.Length
= ComponentName
.Length
;
914 ObjectNameInfo
->Name
.MaximumLength
= ComponentName
.Length
;
916 /* Return Status and the Expected Object */
917 Status
= STATUS_SUCCESS
;
918 Object
= InsertObject
;
920 /* Get out of here */
925 /* We found it, so now get its header */
926 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
929 * Check for a parse Procedure, but don't bother to parse for an insert
930 * unless it's a Symbolic Link, in which case we MUST parse
932 ParseRoutine
= ObjectHeader
->Type
->TypeInfo
.ParseProcedure
;
933 if ((ParseRoutine
) &&
934 (!(InsertObject
) || (ParseRoutine
== ObpParseSymbolicLink
)))
936 /* Use the Root Directory next time */
939 /* Increment the pointer count */
940 InterlockedExchangeAddSizeT(&ObjectHeader
->PointerCount
, 1);
942 /* Cleanup from the first lookup */
943 ObpReleaseLookupContext(LookupContext
);
945 /* Check if we have a referenced directory */
946 if (ReferencedDirectory
)
948 /* We do, dereference it */
949 ObDereferenceObject(ReferencedDirectory
);
950 ReferencedDirectory
= NULL
;
953 /* Check if we have a referenced parent directory */
954 if (ReferencedParentDirectory
)
956 /* We do, dereference it */
957 ObDereferenceObject(ReferencedParentDirectory
);
958 ReferencedParentDirectory
= NULL
;
961 /* Call the Parse Procedure */
962 ObpCalloutStart(&CalloutIrql
);
963 Status
= ParseRoutine(Object
,
973 ObpCalloutEnd(CalloutIrql
, "Parse", ObjectHeader
->Type
, Object
);
975 /* Remove our extra reference */
976 ObDereferenceObject(&ObjectHeader
->Body
);
978 /* Check if we have to reparse */
979 if ((Status
== STATUS_REPARSE
) ||
980 (Status
== STATUS_REPARSE_OBJECT
))
991 /* Start over from root if we got sent back there */
992 if ((Status
== STATUS_REPARSE_OBJECT
) ||
993 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
995 /* Check if we got a root directory */
998 /* Stop using it, because we have a new directory now */
999 ObDereferenceObject(RootDirectory
);
1004 ParentDirectory
= NULL
;
1005 RootDirectory
= ObpRootDirectoryObject
;
1007 /* Check for reparse status */
1008 if (Status
== STATUS_REPARSE_OBJECT
)
1010 /* Don't reparse again */
1013 /* Did we actually get an object to which to reparse? */
1016 /* We didn't, so set a failure status */
1017 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1021 /* We did, so we're free to parse the new object */
1027 /* This is a symbolic link */
1032 else if (RootDirectory
== ObpRootDirectoryObject
)
1034 /* We got STATUS_REPARSE but are at the Root Directory */
1036 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1040 else if (!NT_SUCCESS(Status
))
1047 /* We didn't reparse but we didn't find the Object Either */
1048 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1051 /* Break out of the loop */
1056 /* No parse routine...do we still have a remaining name? */
1057 if (!RemainingName
.Length
)
1059 /* Are we creating an object? */
1062 /* Check if this is a user-mode call that needs to traverse */
1063 if ((AccessCheckMode
!= KernelMode
) &&
1064 !(AccessState
->Flags
& TOKEN_HAS_TRAVERSE_PRIVILEGE
))
1066 /* Check if we can get it */
1067 if (!ObpCheckTraverseAccess(Directory
,
1074 /* We don't have access, fail */
1080 /* Reference the Object */
1081 Status
= ObReferenceObjectByPointer(Object
,
1085 if (!NT_SUCCESS(Status
)) Object
= NULL
;
1088 /* And get out of the reparse loop */
1093 /* We still have a name; check if this is a directory object */
1094 if (ObjectHeader
->Type
== ObpDirectoryObjectType
)
1096 /* Check if we have a referenced parent directory */
1097 if (ReferencedParentDirectory
)
1099 /* Dereference it */
1100 ObDereferenceObject(ReferencedParentDirectory
);
1103 /* Restart the lookup from this directory */
1104 ReferencedParentDirectory
= ReferencedDirectory
;
1105 ParentDirectory
= Directory
;
1107 ReferencedDirectory
= NULL
;
1111 /* We still have a name, but no parse routine for it */
1112 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
1121 /* Check if we failed */
1122 if (!NT_SUCCESS(Status
))
1124 /* Cleanup after lookup */
1125 ObpReleaseLookupContext(LookupContext
);
1128 /* Check if we have a device map and dereference it if so */
1129 //if (DeviceMap) ObfDereferenceDeviceMap(DeviceMap);
1131 /* Check if we have a referenced directory and dereference it if so */
1132 if (ReferencedDirectory
) ObDereferenceObject(ReferencedDirectory
);
1134 /* Check if we have a referenced parent directory */
1135 if (ReferencedParentDirectory
)
1137 /* We do, dereference it */
1138 ObDereferenceObject(ReferencedParentDirectory
);
1141 /* Set the found object and check if we got one */
1142 *FoundObject
= Object
;
1145 /* Nothing was found. Did we reparse or get success? */
1146 if ((Status
== STATUS_REPARSE
) || (NT_SUCCESS(Status
)))
1148 /* Set correct failure */
1149 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1153 /* Check if we had a root directory */
1154 if (RootHandle
) ObDereferenceObject(RootDirectory
);
1156 /* Return status to caller */
1157 OBTRACE(OB_NAMESPACE_DEBUG
,
1158 "%s - Found Object: %p. Expected: %p\n",
1165 /* PUBLIC FUNCTIONS *********************************************************/
1169 ObQueryNameString(IN PVOID Object
,
1170 OUT POBJECT_NAME_INFORMATION ObjectNameInfo
,
1172 OUT PULONG ReturnLength
)
1174 POBJECT_HEADER_NAME_INFO LocalInfo
;
1175 POBJECT_HEADER ObjectHeader
;
1176 POBJECT_DIRECTORY ParentDirectory
;
1179 BOOLEAN ObjectIsNamed
;
1180 NTSTATUS Status
= STATUS_SUCCESS
;
1182 /* Get the Kernel Meta-Structures */
1183 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
1184 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
1186 /* Check if a Query Name Procedure is available */
1187 if (ObjectHeader
->Type
->TypeInfo
.QueryNameProcedure
)
1189 /* Call the procedure inside SEH */
1190 ObjectIsNamed
= ((LocalInfo
) && (LocalInfo
->Name
.Length
> 0));
1194 Status
= ObjectHeader
->Type
->TypeInfo
.QueryNameProcedure(Object
,
1201 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1203 /* Return the exception code */
1204 Status
= _SEH2_GetExceptionCode();
1211 /* Check if the object doesn't even have a name */
1212 if (!(LocalInfo
) || !(LocalInfo
->Name
.Buffer
))
1214 Status
= STATUS_SUCCESS
;
1218 /* We're returning the name structure */
1219 *ReturnLength
= sizeof(OBJECT_NAME_INFORMATION
);
1221 /* Check if we were given enough space */
1222 if (*ReturnLength
> Length
)
1224 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1228 /* Return an empty buffer */
1229 RtlInitEmptyUnicodeString(&ObjectNameInfo
->Name
, NULL
, 0);
1232 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1234 /* Return the exception code */
1235 Status
= _SEH2_GetExceptionCode();
1243 * Find the size needed for the name. We won't do
1244 * this during the Name Creation loop because we want
1245 * to let the caller know that the buffer isn't big
1246 * enough right at the beginning, not work our way through
1247 * and find out at the end
1251 if (Object
== ObpRootDirectoryObject
)
1253 /* Size of the '\' string */
1254 NameSize
= sizeof(OBJ_NAME_PATH_SEPARATOR
);
1258 /* Get the Object Directory and add name of Object */
1259 ParentDirectory
= LocalInfo
->Directory
;
1260 NameSize
= sizeof(OBJ_NAME_PATH_SEPARATOR
) + LocalInfo
->Name
.Length
;
1262 /* Loop inside the directory to get the top-most one (meaning root) */
1263 while ((ParentDirectory
!= ObpRootDirectoryObject
) && (ParentDirectory
))
1265 /* Get the Name Information */
1266 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(
1267 OBJECT_TO_OBJECT_HEADER(ParentDirectory
));
1269 /* Add the size of the Directory Name */
1270 if (LocalInfo
&& LocalInfo
->Directory
)
1272 /* Size of the '\' string + Directory Name */
1273 NameSize
+= sizeof(OBJ_NAME_PATH_SEPARATOR
) +
1274 LocalInfo
->Name
.Length
;
1276 /* Move to next parent Directory */
1277 ParentDirectory
= LocalInfo
->Directory
;
1281 /* Directory with no name. We append "...\" */
1282 NameSize
+= sizeof(L
"...") + sizeof(OBJ_NAME_PATH_SEPARATOR
);
1288 /* Finally, add the name of the structure and the null char */
1289 *ReturnLength
= NameSize
+
1290 sizeof(OBJECT_NAME_INFORMATION
) +
1291 sizeof(UNICODE_NULL
);
1293 /* Check if we were given enough space */
1294 if (*ReturnLength
> Length
) _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH
);
1297 * Now we will actually create the name. We work backwards because
1298 * it's easier to start off from the Name we have and walk up the
1299 * parent directories. We use the same logic as Name Length calculation.
1301 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
1302 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectNameInfo
+ *ReturnLength
);
1303 *--ObjectName
= UNICODE_NULL
;
1305 /* Check if the object is actually the Root directory */
1306 if (Object
== ObpRootDirectoryObject
)
1308 /* This is already the Root Directory, return "\\" */
1309 *--ObjectName
= OBJ_NAME_PATH_SEPARATOR
;
1310 ObjectNameInfo
->Name
.Length
= (USHORT
)NameSize
;
1311 ObjectNameInfo
->Name
.MaximumLength
= (USHORT
)(NameSize
+
1312 sizeof(UNICODE_NULL
));
1313 ObjectNameInfo
->Name
.Buffer
= ObjectName
;
1314 Status
= STATUS_SUCCESS
;
1318 /* Start by adding the Object's Name */
1319 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1320 LocalInfo
->Name
.Length
);
1321 RtlCopyMemory(ObjectName
,
1322 LocalInfo
->Name
.Buffer
,
1323 LocalInfo
->Name
.Length
);
1325 /* Now parse the Parent directories until we reach the top */
1326 ParentDirectory
= LocalInfo
->Directory
;
1327 while ((ParentDirectory
!= ObpRootDirectoryObject
) && (ParentDirectory
))
1329 /* Get the name information */
1330 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(
1331 OBJECT_TO_OBJECT_HEADER(ParentDirectory
));
1334 *(--ObjectName
) = OBJ_NAME_PATH_SEPARATOR
;
1336 /* Add the Parent Directory's Name */
1337 if (LocalInfo
&& LocalInfo
->Name
.Buffer
)
1340 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1341 LocalInfo
->Name
.Length
);
1342 RtlCopyMemory(ObjectName
,
1343 LocalInfo
->Name
.Buffer
,
1344 LocalInfo
->Name
.Length
);
1346 /* Move to next parent */
1347 ParentDirectory
= LocalInfo
->Directory
;
1351 /* Directory without a name, we add "..." */
1352 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1354 sizeof(UNICODE_NULL
));
1355 RtlCopyMemory(ObjectName
, L
"...", sizeof(L
"..."));
1360 /* Add Root Directory Name */
1361 *(--ObjectName
) = OBJ_NAME_PATH_SEPARATOR
;
1362 ObjectNameInfo
->Name
.Length
= (USHORT
)NameSize
;
1363 ObjectNameInfo
->Name
.MaximumLength
=
1364 (USHORT
)(NameSize
+ sizeof(UNICODE_NULL
));
1365 ObjectNameInfo
->Name
.Buffer
= ObjectName
;
1368 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1370 /* Return the exception code */
1371 Status
= _SEH2_GetExceptionCode();
1375 /* Return success */