1c2c66affSColin Finck /* 2c2c66affSColin Finck * PROJECT: ReactOS Kernel 3c2c66affSColin Finck * LICENSE: GPL - See COPYING in the top level directory 4c2c66affSColin Finck * FILE: ntoskrnl/ob/obname.c 5c2c66affSColin Finck * PURPOSE: Manages all functions related to the Object Manager name- 6c2c66affSColin Finck * space, such as finding objects or querying their names. 7c2c66affSColin Finck * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 8c2c66affSColin Finck * Eric Kohl 9c2c66affSColin Finck * Thomas Weidenmueller (w3seek@reactos.org) 10c2c66affSColin Finck */ 11c2c66affSColin Finck 12c2c66affSColin Finck /* INCLUDES ******************************************************************/ 13c2c66affSColin Finck 14c2c66affSColin Finck #include <ntoskrnl.h> 15c2c66affSColin Finck #define NDEBUG 16c2c66affSColin Finck #include <debug.h> 17c2c66affSColin Finck 18c2c66affSColin Finck BOOLEAN ObpCaseInsensitive = TRUE; 19c2c66affSColin Finck POBJECT_DIRECTORY ObpRootDirectoryObject; 20c2c66affSColin Finck POBJECT_DIRECTORY ObpTypeDirectoryObject; 21c2c66affSColin Finck 22c2c66affSColin Finck /* DOS Device Prefix \??\ and \?? */ 23c2c66affSColin Finck ALIGNEDNAME ObpDosDevicesShortNamePrefix = {{L'\\',L'?',L'?',L'\\'}}; 24c2c66affSColin Finck ALIGNEDNAME ObpDosDevicesShortNameRoot = {{L'\\',L'?',L'?',L'\0'}}; 25c2c66affSColin Finck UNICODE_STRING ObpDosDevicesShortName = 26c2c66affSColin Finck { 27c2c66affSColin Finck sizeof(ObpDosDevicesShortNamePrefix), 28c2c66affSColin Finck sizeof(ObpDosDevicesShortNamePrefix), 29c2c66affSColin Finck (PWSTR)&ObpDosDevicesShortNamePrefix 30c2c66affSColin Finck }; 31c2c66affSColin Finck 32c2c66affSColin Finck /* PRIVATE FUNCTIONS *********************************************************/ 33c2c66affSColin Finck 34c2c66affSColin Finck NTSTATUS 35c2c66affSColin Finck NTAPI 36c2c66affSColin Finck INIT_FUNCTION 37c2c66affSColin Finck ObpCreateGlobalDosDevicesSD(OUT PSECURITY_DESCRIPTOR *SecurityDescriptor) 38c2c66affSColin Finck { 39c2c66affSColin Finck PSECURITY_DESCRIPTOR Sd = NULL; 40c2c66affSColin Finck PACL Dacl; 41c2c66affSColin Finck ULONG AclSize, SdSize; 42c2c66affSColin Finck NTSTATUS Status; 43c2c66affSColin Finck 44c2c66affSColin Finck AclSize = sizeof(ACL) + 45c2c66affSColin Finck sizeof(ACE) + RtlLengthSid(SeWorldSid) + 46c2c66affSColin Finck sizeof(ACE) + RtlLengthSid(SeLocalSystemSid) + 47c2c66affSColin Finck sizeof(ACE) + RtlLengthSid(SeWorldSid) + 48c2c66affSColin Finck sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid) + 49c2c66affSColin Finck sizeof(ACE) + RtlLengthSid(SeLocalSystemSid) + 50c2c66affSColin Finck sizeof(ACE) + RtlLengthSid(SeCreatorOwnerSid); 51c2c66affSColin Finck 52c2c66affSColin Finck SdSize = sizeof(SECURITY_DESCRIPTOR) + AclSize; 53c2c66affSColin Finck 54c2c66affSColin Finck /* Allocate the SD and ACL */ 55c2c66affSColin Finck Sd = ExAllocatePoolWithTag(PagedPool, SdSize, TAG_SD); 56c2c66affSColin Finck if (Sd == NULL) 57c2c66affSColin Finck { 58c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES; 59c2c66affSColin Finck } 60c2c66affSColin Finck 61c2c66affSColin Finck /* Initialize the SD */ 62c2c66affSColin Finck Status = RtlCreateSecurityDescriptor(Sd, 63c2c66affSColin Finck SECURITY_DESCRIPTOR_REVISION); 64c2c66affSColin Finck if (!NT_SUCCESS(Status)) 65c2c66affSColin Finck return Status; 66c2c66affSColin Finck 67c2c66affSColin Finck Dacl = (PACL)((INT_PTR)Sd + sizeof(SECURITY_DESCRIPTOR)); 68c2c66affSColin Finck 69c2c66affSColin Finck /* Initialize the DACL */ 70c2c66affSColin Finck RtlCreateAcl(Dacl, AclSize, ACL_REVISION); 71c2c66affSColin Finck 72c2c66affSColin Finck /* Add the ACEs */ 73c2c66affSColin Finck RtlAddAccessAllowedAce(Dacl, 74c2c66affSColin Finck ACL_REVISION, 75c2c66affSColin Finck GENERIC_READ | GENERIC_EXECUTE, 76c2c66affSColin Finck SeWorldSid); 77c2c66affSColin Finck 78c2c66affSColin Finck RtlAddAccessAllowedAce(Dacl, 79c2c66affSColin Finck ACL_REVISION, 80c2c66affSColin Finck GENERIC_ALL, 81c2c66affSColin Finck SeLocalSystemSid); 82c2c66affSColin Finck 83c2c66affSColin Finck RtlAddAccessAllowedAceEx(Dacl, 84c2c66affSColin Finck ACL_REVISION, 85c2c66affSColin Finck INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, 86c2c66affSColin Finck GENERIC_EXECUTE, 87c2c66affSColin Finck SeWorldSid); 88c2c66affSColin Finck 89c2c66affSColin Finck RtlAddAccessAllowedAceEx(Dacl, 90c2c66affSColin Finck ACL_REVISION, 91c2c66affSColin Finck INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, 92c2c66affSColin Finck GENERIC_ALL, 93c2c66affSColin Finck SeAliasAdminsSid); 94c2c66affSColin Finck 95c2c66affSColin Finck RtlAddAccessAllowedAceEx(Dacl, 96c2c66affSColin Finck ACL_REVISION, 97c2c66affSColin Finck INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, 98c2c66affSColin Finck GENERIC_ALL, 99c2c66affSColin Finck SeLocalSystemSid); 100c2c66affSColin Finck 101c2c66affSColin Finck RtlAddAccessAllowedAceEx(Dacl, 102c2c66affSColin Finck ACL_REVISION, 103c2c66affSColin Finck INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, 104c2c66affSColin Finck GENERIC_ALL, 105c2c66affSColin Finck SeCreatorOwnerSid); 106c2c66affSColin Finck 107c2c66affSColin Finck /* Attach the DACL to the SD */ 108c2c66affSColin Finck Status = RtlSetDaclSecurityDescriptor(Sd, 109c2c66affSColin Finck TRUE, 110c2c66affSColin Finck Dacl, 111c2c66affSColin Finck FALSE); 112c2c66affSColin Finck if (!NT_SUCCESS(Status)) 113c2c66affSColin Finck goto done; 114c2c66affSColin Finck 115c2c66affSColin Finck *SecurityDescriptor = Sd; 116c2c66affSColin Finck 117c2c66affSColin Finck done: 118c2c66affSColin Finck if (!NT_SUCCESS(Status)) 119c2c66affSColin Finck { 120c2c66affSColin Finck if (Sd != NULL) 121c2c66affSColin Finck ExFreePoolWithTag(Sd, TAG_SD); 122c2c66affSColin Finck } 123c2c66affSColin Finck 124c2c66affSColin Finck return Status; 125c2c66affSColin Finck } 126c2c66affSColin Finck 127c2c66affSColin Finck NTSTATUS 128c2c66affSColin Finck NTAPI 129c2c66affSColin Finck INIT_FUNCTION 130c2c66affSColin Finck ObpCreateDosDevicesDirectory(VOID) 131c2c66affSColin Finck { 132c2c66affSColin Finck OBJECT_ATTRIBUTES ObjectAttributes; 133c2c66affSColin Finck UNICODE_STRING RootName, TargetName, LinkName; 134c2c66affSColin Finck HANDLE Handle, SymHandle; 135c2c66affSColin Finck PSECURITY_DESCRIPTOR DosDevicesSD = NULL; 136c2c66affSColin Finck NTSTATUS Status; 137c2c66affSColin Finck 138c2c66affSColin Finck /* Create a custom security descriptor for the global DosDevices directory */ 139c2c66affSColin Finck Status = ObpCreateGlobalDosDevicesSD(&DosDevicesSD); 140c2c66affSColin Finck if (!NT_SUCCESS(Status)) 141c2c66affSColin Finck return Status; 142c2c66affSColin Finck 143c2c66affSColin Finck /* Create the global DosDevices directory \?? */ 144c2c66affSColin Finck RtlInitUnicodeString(&RootName, L"\\GLOBAL??"); 145c2c66affSColin Finck InitializeObjectAttributes(&ObjectAttributes, 146c2c66affSColin Finck &RootName, 147c2c66affSColin Finck OBJ_PERMANENT, 148c2c66affSColin Finck NULL, 149c2c66affSColin Finck DosDevicesSD); 150c2c66affSColin Finck Status = NtCreateDirectoryObject(&Handle, 151c2c66affSColin Finck DIRECTORY_ALL_ACCESS, 152c2c66affSColin Finck &ObjectAttributes); 153c2c66affSColin Finck ExFreePoolWithTag(DosDevicesSD, TAG_SD); 154c2c66affSColin Finck if (!NT_SUCCESS(Status)) return Status; 155c2c66affSColin Finck 156c2c66affSColin Finck /* Create the system device map */ 157c2c66affSColin Finck Status = ObpCreateDeviceMap(Handle); 158c2c66affSColin Finck if (!NT_SUCCESS(Status)) 159c2c66affSColin Finck return Status; 160c2c66affSColin Finck 161c2c66affSColin Finck /*********************************************\ 162c2c66affSColin Finck |*** HACK until we support device mappings ***| 163c2c66affSColin Finck |*** Add a symlink \??\ <--> \GLOBAL??\ ***| 164c2c66affSColin Finck \*********************************************/ 165c2c66affSColin Finck RtlInitUnicodeString(&LinkName, L"\\??"); 166c2c66affSColin Finck InitializeObjectAttributes(&ObjectAttributes, 167c2c66affSColin Finck &LinkName, 168c2c66affSColin Finck OBJ_PERMANENT, 169c2c66affSColin Finck NULL, 170c2c66affSColin Finck NULL); 171c2c66affSColin Finck Status = NtCreateSymbolicLinkObject(&SymHandle, 172c2c66affSColin Finck SYMBOLIC_LINK_ALL_ACCESS, 173c2c66affSColin Finck &ObjectAttributes, 174c2c66affSColin Finck &RootName); 175c2c66affSColin Finck if (NT_SUCCESS(Status)) NtClose(SymHandle); 176c2c66affSColin Finck /*********************************************\ 177c2c66affSColin Finck \*********************************************/ 178c2c66affSColin Finck 179c2c66affSColin Finck // FIXME: Create a device mapping for the global \?? directory 180c2c66affSColin Finck 181c2c66affSColin Finck /* 182c2c66affSColin Finck * Initialize the \??\GLOBALROOT symbolic link 183c2c66affSColin Finck * pointing to the root directory \ . 184c2c66affSColin Finck */ 185c2c66affSColin Finck RtlInitUnicodeString(&LinkName, L"GLOBALROOT"); 186c2c66affSColin Finck RtlInitUnicodeString(&TargetName, L""); 187c2c66affSColin Finck InitializeObjectAttributes(&ObjectAttributes, 188c2c66affSColin Finck &LinkName, 189c2c66affSColin Finck OBJ_PERMANENT, 190c2c66affSColin Finck Handle, 191c2c66affSColin Finck NULL); 192c2c66affSColin Finck Status = NtCreateSymbolicLinkObject(&SymHandle, 193c2c66affSColin Finck SYMBOLIC_LINK_ALL_ACCESS, 194c2c66affSColin Finck &ObjectAttributes, 195c2c66affSColin Finck &TargetName); 196c2c66affSColin Finck if (NT_SUCCESS(Status)) NtClose(SymHandle); 197c2c66affSColin Finck 198c2c66affSColin Finck /* 199c2c66affSColin Finck * Initialize the \??\Global symbolic link pointing to the global 200c2c66affSColin Finck * DosDevices directory \?? . It is used to access the global \?? 201c2c66affSColin Finck * by user-mode components which, by default, use a per-session 202c2c66affSColin Finck * DosDevices directory. 203c2c66affSColin Finck */ 204c2c66affSColin Finck RtlInitUnicodeString(&LinkName, L"Global"); 205c2c66affSColin Finck InitializeObjectAttributes(&ObjectAttributes, 206c2c66affSColin Finck &LinkName, 207c2c66affSColin Finck OBJ_PERMANENT, 208c2c66affSColin Finck Handle, 209c2c66affSColin Finck NULL); 210c2c66affSColin Finck Status = NtCreateSymbolicLinkObject(&SymHandle, 211c2c66affSColin Finck SYMBOLIC_LINK_ALL_ACCESS, 212c2c66affSColin Finck &ObjectAttributes, 213c2c66affSColin Finck &RootName); 214c2c66affSColin Finck if (NT_SUCCESS(Status)) NtClose(SymHandle); 215c2c66affSColin Finck 216c2c66affSColin Finck /* Close the directory handle */ 217c2c66affSColin Finck NtClose(Handle); 218c2c66affSColin Finck if (!NT_SUCCESS(Status)) return Status; 219c2c66affSColin Finck 220c2c66affSColin Finck /* 221c2c66affSColin Finck * Initialize the \DosDevices symbolic link pointing to the global 222c2c66affSColin Finck * DosDevices directory \?? , for backward compatibility with 223c2c66affSColin Finck * Windows NT-2000 systems. 224c2c66affSColin Finck */ 225c2c66affSColin Finck RtlCreateUnicodeString(&LinkName, L"\\DosDevices"); 226c2c66affSColin Finck RtlInitUnicodeString(&RootName, (PCWSTR)&ObpDosDevicesShortNameRoot); 227c2c66affSColin Finck InitializeObjectAttributes(&ObjectAttributes, 228c2c66affSColin Finck &LinkName, 229c2c66affSColin Finck OBJ_PERMANENT, 230c2c66affSColin Finck NULL, 231c2c66affSColin Finck NULL); 232c2c66affSColin Finck Status = NtCreateSymbolicLinkObject(&SymHandle, 233c2c66affSColin Finck SYMBOLIC_LINK_ALL_ACCESS, 234c2c66affSColin Finck &ObjectAttributes, 235c2c66affSColin Finck &RootName); 236c2c66affSColin Finck if (NT_SUCCESS(Status)) NtClose(SymHandle); 237c2c66affSColin Finck 238c2c66affSColin Finck /* Return status */ 239c2c66affSColin Finck return Status; 240c2c66affSColin Finck } 241c2c66affSColin Finck 242c2c66affSColin Finck /*++ 243c2c66affSColin Finck * @name ObpDeleteNameCheck 244c2c66affSColin Finck * 245c2c66affSColin Finck * The ObpDeleteNameCheck routine checks if a named object should be 246c2c66affSColin Finck * removed from the object directory namespace. 247c2c66affSColin Finck * 248c2c66affSColin Finck * @param Object 249c2c66affSColin Finck * Pointer to the object to check for possible removal. 250c2c66affSColin Finck * 251c2c66affSColin Finck * @return None. 252c2c66affSColin Finck * 253c2c66affSColin Finck * @remarks An object is removed if the following 4 criteria are met: 254c2c66affSColin Finck * 1) The object has 0 handles open 255c2c66affSColin Finck * 2) The object is in the directory namespace and has a name 256c2c66affSColin Finck * 3) The object is not permanent 257c2c66affSColin Finck * 258c2c66affSColin Finck *--*/ 259c2c66affSColin Finck VOID 260c2c66affSColin Finck NTAPI 261c2c66affSColin Finck ObpDeleteNameCheck(IN PVOID Object) 262c2c66affSColin Finck { 263c2c66affSColin Finck POBJECT_HEADER ObjectHeader; 264c2c66affSColin Finck OBP_LOOKUP_CONTEXT Context; 265c2c66affSColin Finck POBJECT_HEADER_NAME_INFO ObjectNameInfo; 266c2c66affSColin Finck POBJECT_TYPE ObjectType; 267c2c66affSColin Finck PVOID Directory = NULL; 268c2c66affSColin Finck 269c2c66affSColin Finck /* Get object structures */ 270c2c66affSColin Finck ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); 271c2c66affSColin Finck ObjectNameInfo = ObpReferenceNameInfo(ObjectHeader); 272c2c66affSColin Finck ObjectType = ObjectHeader->Type; 273c2c66affSColin Finck 274c2c66affSColin Finck /* 275c2c66affSColin Finck * Check if the handle count is 0, if the object is named, 276c2c66affSColin Finck * and if the object isn't a permanent object. 277c2c66affSColin Finck */ 278c2c66affSColin Finck if (!(ObjectHeader->HandleCount) && 279c2c66affSColin Finck (ObjectNameInfo) && 280c2c66affSColin Finck (ObjectNameInfo->Name.Length) && 281c2c66affSColin Finck (ObjectNameInfo->Directory) && 282c2c66affSColin Finck !(ObjectHeader->Flags & OB_FLAG_PERMANENT)) 283c2c66affSColin Finck { 284c2c66affSColin Finck /* Setup a lookup context */ 285c2c66affSColin Finck ObpInitializeLookupContext(&Context); 286c2c66affSColin Finck 287c2c66affSColin Finck /* Lock the directory */ 288c2c66affSColin Finck ObpAcquireDirectoryLockExclusive(ObjectNameInfo->Directory, &Context); 289c2c66affSColin Finck 290c2c66affSColin Finck /* Do the lookup */ 291c2c66affSColin Finck Object = ObpLookupEntryDirectory(ObjectNameInfo->Directory, 292c2c66affSColin Finck &ObjectNameInfo->Name, 293c2c66affSColin Finck 0, 294c2c66affSColin Finck FALSE, 295c2c66affSColin Finck &Context); 296c2c66affSColin Finck if (Object) 297c2c66affSColin Finck { 298c2c66affSColin Finck /* Lock the object */ 299c2c66affSColin Finck ObpAcquireObjectLock(ObjectHeader); 300c2c66affSColin Finck 301c2c66affSColin Finck /* Make sure we can still delete the object */ 302c2c66affSColin Finck if (!(ObjectHeader->HandleCount) && 303c2c66affSColin Finck !(ObjectHeader->Flags & OB_FLAG_PERMANENT)) 304c2c66affSColin Finck { 305c2c66affSColin Finck /* First delete it from the directory */ 306c2c66affSColin Finck ObpDeleteEntryDirectory(&Context); 307c2c66affSColin Finck 308c2c66affSColin Finck /* Check if this is a symbolic link */ 309c2c66affSColin Finck if (ObjectType == ObSymbolicLinkType) 310c2c66affSColin Finck { 311c2c66affSColin Finck /* Remove internal name */ 312c2c66affSColin Finck ObpDeleteSymbolicLinkName(Object); 313c2c66affSColin Finck } 314c2c66affSColin Finck 315c2c66affSColin Finck /* Check if the kernel exclusive is set */ 316c2c66affSColin Finck ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader); 317c2c66affSColin Finck if ((ObjectNameInfo) && 318c2c66affSColin Finck (ObjectNameInfo->QueryReferences & OB_FLAG_KERNEL_EXCLUSIVE)) 319c2c66affSColin Finck { 320c2c66affSColin Finck /* Remove protection flag */ 321c2c66affSColin Finck InterlockedExchangeAdd((PLONG)&ObjectNameInfo->QueryReferences, 322c2c66affSColin Finck -OB_FLAG_KERNEL_EXCLUSIVE); 323c2c66affSColin Finck } 324c2c66affSColin Finck 325c2c66affSColin Finck /* Get the directory */ 326c2c66affSColin Finck Directory = ObjectNameInfo->Directory; 327c2c66affSColin Finck } 328c2c66affSColin Finck 329c2c66affSColin Finck /* Release the lock */ 330c2c66affSColin Finck ObpReleaseObjectLock(ObjectHeader); 331c2c66affSColin Finck } 332c2c66affSColin Finck 333c2c66affSColin Finck /* Cleanup after lookup */ 334c2c66affSColin Finck ObpReleaseLookupContext(&Context); 335c2c66affSColin Finck 336c2c66affSColin Finck /* Remove another query reference since we added one on top */ 337c2c66affSColin Finck ObpDereferenceNameInfo(ObjectNameInfo); 338c2c66affSColin Finck 339c2c66affSColin Finck /* Check if we were inserted in a directory */ 340c2c66affSColin Finck if (Directory) 341c2c66affSColin Finck { 342c2c66affSColin Finck /* We were, so first remove the extra reference we had added */ 343c2c66affSColin Finck ObpDereferenceNameInfo(ObjectNameInfo); 344c2c66affSColin Finck 345c2c66affSColin Finck /* Now dereference the object as well */ 346c2c66affSColin Finck ObDereferenceObject(Object); 347c2c66affSColin Finck } 348c2c66affSColin Finck } 349c2c66affSColin Finck else 350c2c66affSColin Finck { 351c2c66affSColin Finck /* Remove the reference we added */ 352c2c66affSColin Finck ObpDereferenceNameInfo(ObjectNameInfo); 353c2c66affSColin Finck } 354c2c66affSColin Finck } 355c2c66affSColin Finck 356c2c66affSColin Finck NTSTATUS 357c2c66affSColin Finck NTAPI 358c2c66affSColin Finck ObpLookupObjectName(IN HANDLE RootHandle OPTIONAL, 359c2c66affSColin Finck IN OUT PUNICODE_STRING ObjectName, 360c2c66affSColin Finck IN ULONG Attributes, 361c2c66affSColin Finck IN POBJECT_TYPE ObjectType, 362c2c66affSColin Finck IN KPROCESSOR_MODE AccessMode, 363c2c66affSColin Finck IN OUT PVOID ParseContext, 364c2c66affSColin Finck IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL, 365c2c66affSColin Finck IN PVOID InsertObject OPTIONAL, 366c2c66affSColin Finck IN OUT PACCESS_STATE AccessState, 367c2c66affSColin Finck OUT POBP_LOOKUP_CONTEXT LookupContext, 368c2c66affSColin Finck OUT PVOID *FoundObject) 369c2c66affSColin Finck { 370c2c66affSColin Finck PVOID Object; 371c2c66affSColin Finck POBJECT_HEADER ObjectHeader; 372c2c66affSColin Finck UNICODE_STRING ComponentName, RemainingName; 373c2c66affSColin Finck BOOLEAN Reparse = FALSE, SymLink = FALSE; 374c2c66affSColin Finck POBJECT_DIRECTORY Directory = NULL, ParentDirectory = NULL, RootDirectory; 375c2c66affSColin Finck POBJECT_DIRECTORY ReferencedDirectory = NULL, ReferencedParentDirectory = NULL; 376c2c66affSColin Finck KIRQL CalloutIrql; 377c2c66affSColin Finck OB_PARSE_METHOD ParseRoutine; 378c2c66affSColin Finck NTSTATUS Status; 379c2c66affSColin Finck KPROCESSOR_MODE AccessCheckMode; 380c2c66affSColin Finck PWCHAR NewName; 381c2c66affSColin Finck POBJECT_HEADER_NAME_INFO ObjectNameInfo; 382c2c66affSColin Finck ULONG MaxReparse = 30; 383c2c66affSColin Finck PAGED_CODE(); 384c2c66affSColin Finck OBTRACE(OB_NAMESPACE_DEBUG, 385c2c66affSColin Finck "%s - Finding Object: %wZ. Expecting: %p\n", 386c2c66affSColin Finck __FUNCTION__, 387c2c66affSColin Finck ObjectName, 388c2c66affSColin Finck InsertObject); 389c2c66affSColin Finck 390c2c66affSColin Finck /* Initialize starting state */ 391c2c66affSColin Finck ObpInitializeLookupContext(LookupContext); 392c2c66affSColin Finck *FoundObject = NULL; 393c2c66affSColin Finck Status = STATUS_SUCCESS; 394c2c66affSColin Finck Object = NULL; 395c2c66affSColin Finck 396c2c66affSColin Finck /* Check if case-insensitivity is checked */ 397c2c66affSColin Finck if (ObpCaseInsensitive) 398c2c66affSColin Finck { 399c2c66affSColin Finck /* Check if the object type requests this */ 400c2c66affSColin Finck if (!(ObjectType) || (ObjectType->TypeInfo.CaseInsensitive)) 401c2c66affSColin Finck { 402c2c66affSColin Finck /* Add the flag to disable case sensitivity */ 403c2c66affSColin Finck Attributes |= OBJ_CASE_INSENSITIVE; 404c2c66affSColin Finck } 405c2c66affSColin Finck } 406c2c66affSColin Finck 407c2c66affSColin Finck /* Check if this is a access checks are being forced */ 408c2c66affSColin Finck AccessCheckMode = (Attributes & OBJ_FORCE_ACCESS_CHECK) ? 409c2c66affSColin Finck UserMode : AccessMode; 410c2c66affSColin Finck 411c2c66affSColin Finck /* Check if we got a Root Directory */ 412c2c66affSColin Finck if (RootHandle) 413c2c66affSColin Finck { 414c2c66affSColin Finck /* We did. Reference it */ 415c2c66affSColin Finck Status = ObReferenceObjectByHandle(RootHandle, 416c2c66affSColin Finck 0, 417c2c66affSColin Finck NULL, 418c2c66affSColin Finck AccessMode, 419c2c66affSColin Finck (PVOID*)&RootDirectory, 420c2c66affSColin Finck NULL); 421c2c66affSColin Finck if (!NT_SUCCESS(Status)) return Status; 422c2c66affSColin Finck 423c2c66affSColin Finck /* Get the header */ 424c2c66affSColin Finck ObjectHeader = OBJECT_TO_OBJECT_HEADER(RootDirectory); 425c2c66affSColin Finck 426c2c66affSColin Finck /* The name cannot start with a separator, unless this is a file */ 427c2c66affSColin Finck if ((ObjectName->Buffer) && 428c2c66affSColin Finck (ObjectName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR) && 429c2c66affSColin Finck (ObjectHeader->Type != IoFileObjectType)) 430c2c66affSColin Finck { 431c2c66affSColin Finck /* The syntax is bad, so fail this request */ 432c2c66affSColin Finck ObDereferenceObject(RootDirectory); 433c2c66affSColin Finck return STATUS_OBJECT_PATH_SYNTAX_BAD; 434c2c66affSColin Finck } 435c2c66affSColin Finck 436c2c66affSColin Finck /* Don't parse a Directory */ 437c2c66affSColin Finck if (ObjectHeader->Type != ObDirectoryType) 438c2c66affSColin Finck { 439c2c66affSColin Finck /* Make sure the Object Type has a parse routine */ 440c2c66affSColin Finck ParseRoutine = ObjectHeader->Type->TypeInfo.ParseProcedure; 441c2c66affSColin Finck if (!ParseRoutine) 442c2c66affSColin Finck { 443c2c66affSColin Finck /* We can't parse a name if we don't have a parse routine */ 444c2c66affSColin Finck ObDereferenceObject(RootDirectory); 445c2c66affSColin Finck return STATUS_INVALID_HANDLE; 446c2c66affSColin Finck } 447c2c66affSColin Finck 448c2c66affSColin Finck /* Set default parse count */ 449c2c66affSColin Finck MaxReparse = 30; 450c2c66affSColin Finck 451c2c66affSColin Finck /* Now parse */ 452c2c66affSColin Finck while (TRUE) 453c2c66affSColin Finck { 454c2c66affSColin Finck /* Start with the full name */ 455c2c66affSColin Finck RemainingName = *ObjectName; 456c2c66affSColin Finck 457c2c66affSColin Finck /* Call the Parse Procedure */ 458c2c66affSColin Finck ObpCalloutStart(&CalloutIrql); 459c2c66affSColin Finck Status = ParseRoutine(RootDirectory, 460c2c66affSColin Finck ObjectType, 461c2c66affSColin Finck AccessState, 462c2c66affSColin Finck AccessCheckMode, 463c2c66affSColin Finck Attributes, 464c2c66affSColin Finck ObjectName, 465c2c66affSColin Finck &RemainingName, 466c2c66affSColin Finck ParseContext, 467c2c66affSColin Finck SecurityQos, 468c2c66affSColin Finck &Object); 469c2c66affSColin Finck ObpCalloutEnd(CalloutIrql, "Parse", ObjectHeader->Type, Object); 470c2c66affSColin Finck 471c2c66affSColin Finck /* Check for success or failure, so not reparse */ 472c2c66affSColin Finck if ((Status != STATUS_REPARSE) && 473c2c66affSColin Finck (Status != STATUS_REPARSE_OBJECT)) 474c2c66affSColin Finck { 475c2c66affSColin Finck /* Check for failure */ 476c2c66affSColin Finck if (!NT_SUCCESS(Status)) 477c2c66affSColin Finck { 478c2c66affSColin Finck /* Parse routine might not have cleared this, do it */ 479c2c66affSColin Finck Object = NULL; 480c2c66affSColin Finck } 481c2c66affSColin Finck else if (!Object) 482c2c66affSColin Finck { 483c2c66affSColin Finck /* Modify status to reflect failure inside Ob */ 484c2c66affSColin Finck Status = STATUS_OBJECT_NAME_NOT_FOUND; 485c2c66affSColin Finck } 486c2c66affSColin Finck 487c2c66affSColin Finck /* We're done, return the status and object */ 488c2c66affSColin Finck *FoundObject = Object; 489c2c66affSColin Finck ObDereferenceObject(RootDirectory); 490c2c66affSColin Finck return Status; 491c2c66affSColin Finck } 492c2c66affSColin Finck else if ((!ObjectName->Length) || 493c2c66affSColin Finck (!ObjectName->Buffer) || 494c2c66affSColin Finck (ObjectName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)) 495c2c66affSColin Finck { 496c2c66affSColin Finck /* Reparsed to the root directory, so start over */ 497c2c66affSColin Finck ObDereferenceObject(RootDirectory); 498c2c66affSColin Finck RootDirectory = ObpRootDirectoryObject; 499c2c66affSColin Finck 500c2c66affSColin Finck /* Don't use this anymore, since we're starting at root */ 501c2c66affSColin Finck RootHandle = NULL; 502c2c66affSColin Finck goto ParseFromRoot; 503c2c66affSColin Finck } 504c2c66affSColin Finck else if (--MaxReparse) 505c2c66affSColin Finck { 506c2c66affSColin Finck /* Try reparsing again */ 507c2c66affSColin Finck continue; 508c2c66affSColin Finck } 509c2c66affSColin Finck else 510c2c66affSColin Finck { 511c2c66affSColin Finck /* Reparsed too many times */ 512c2c66affSColin Finck ObDereferenceObject(RootDirectory); 513c2c66affSColin Finck 514c2c66affSColin Finck /* Return the object and normalized status */ 515c2c66affSColin Finck *FoundObject = Object; 516c2c66affSColin Finck if (!Object) Status = STATUS_OBJECT_NAME_NOT_FOUND; 517c2c66affSColin Finck return Status; 518c2c66affSColin Finck } 519c2c66affSColin Finck } 520c2c66affSColin Finck } 521c2c66affSColin Finck else if (!(ObjectName->Length) || !(ObjectName->Buffer)) 522c2c66affSColin Finck { 523c2c66affSColin Finck /* Just return the Root Directory if we didn't get a name */ 524c2c66affSColin Finck Status = ObReferenceObjectByPointer(RootDirectory, 525c2c66affSColin Finck 0, 526c2c66affSColin Finck ObjectType, 527c2c66affSColin Finck AccessMode); 528c2c66affSColin Finck if (NT_SUCCESS(Status)) Object = RootDirectory; 529c2c66affSColin Finck 530c2c66affSColin Finck /* Remove the first reference we added and return the object */ 531c2c66affSColin Finck ObDereferenceObject(RootDirectory); 532c2c66affSColin Finck *FoundObject = Object; 533c2c66affSColin Finck return Status; 534c2c66affSColin Finck } 535c2c66affSColin Finck } 536c2c66affSColin Finck else 537c2c66affSColin Finck { 538c2c66affSColin Finck /* We did not get a Root Directory, so use the root */ 539c2c66affSColin Finck RootDirectory = ObpRootDirectoryObject; 540c2c66affSColin Finck 541c2c66affSColin Finck /* It must start with a path separator */ 542c2c66affSColin Finck if (!(ObjectName->Length) || 543c2c66affSColin Finck !(ObjectName->Buffer) || 544c2c66affSColin Finck (ObjectName->Buffer[0] != OBJ_NAME_PATH_SEPARATOR)) 545c2c66affSColin Finck { 546c2c66affSColin Finck /* This name is invalid, so fail */ 547c2c66affSColin Finck return STATUS_OBJECT_PATH_SYNTAX_BAD; 548c2c66affSColin Finck } 549c2c66affSColin Finck 550c2c66affSColin Finck /* Check if the name is only the path separator */ 551c2c66affSColin Finck if (ObjectName->Length == sizeof(OBJ_NAME_PATH_SEPARATOR)) 552c2c66affSColin Finck { 553c2c66affSColin Finck /* So the caller only wants the root directory; do we have one? */ 554c2c66affSColin Finck if (!RootDirectory) 555c2c66affSColin Finck { 556c2c66affSColin Finck /* This must be the first time we're creating it... right? */ 557c2c66affSColin Finck if (InsertObject) 558c2c66affSColin Finck { 559c2c66affSColin Finck /* Yes, so return it to ObInsert so that it can create it */ 560c2c66affSColin Finck Status = ObReferenceObjectByPointer(InsertObject, 561c2c66affSColin Finck 0, 562c2c66affSColin Finck ObjectType, 563c2c66affSColin Finck AccessMode); 564c2c66affSColin Finck if (NT_SUCCESS(Status)) *FoundObject = InsertObject; 565c2c66affSColin Finck return Status; 566c2c66affSColin Finck } 567c2c66affSColin Finck else 568c2c66affSColin Finck { 569c2c66affSColin Finck /* This should never really happen */ 570c2c66affSColin Finck ASSERT(FALSE); 571c2c66affSColin Finck return STATUS_INVALID_PARAMETER; 572c2c66affSColin Finck } 573c2c66affSColin Finck } 574c2c66affSColin Finck else 575c2c66affSColin Finck { 576c2c66affSColin Finck /* We do have the root directory, so just return it */ 577c2c66affSColin Finck Status = ObReferenceObjectByPointer(RootDirectory, 578c2c66affSColin Finck 0, 579c2c66affSColin Finck ObjectType, 580c2c66affSColin Finck AccessMode); 581c2c66affSColin Finck if (NT_SUCCESS(Status)) *FoundObject = RootDirectory; 582c2c66affSColin Finck return Status; 583c2c66affSColin Finck } 584c2c66affSColin Finck } 585c2c66affSColin Finck else 586c2c66affSColin Finck { 587c2c66affSColin Finck ParseFromRoot: 588c2c66affSColin Finck /* FIXME: Check if we have a device map */ 589c2c66affSColin Finck 590c2c66affSColin Finck /* Check if this is a possible DOS name */ 591c2c66affSColin Finck if (!((ULONG_PTR)(ObjectName->Buffer) & 7)) 592c2c66affSColin Finck { 593c2c66affSColin Finck /* 594c2c66affSColin Finck * This could be one. Does it match the prefix? 595c2c66affSColin Finck * Note that as an optimization, the match is done as 64-bit 596c2c66affSColin Finck * compare since the prefix is "\??\" which is exactly 8 bytes. 597c2c66affSColin Finck * 598c2c66affSColin Finck * In the second branch, we test for "\??" which is also valid. 599c2c66affSColin Finck * This time, we use a 32-bit compare followed by a Unicode 600c2c66affSColin Finck * character compare (16-bit), since the sum is 6 bytes. 601c2c66affSColin Finck */ 602c2c66affSColin Finck if ((ObjectName->Length >= ObpDosDevicesShortName.Length) && 603c2c66affSColin Finck (*(PULONGLONG)(ObjectName->Buffer) == 604c2c66affSColin Finck ObpDosDevicesShortNamePrefix.Alignment.QuadPart)) 605c2c66affSColin Finck { 606c2c66affSColin Finck /* FIXME! */ 607c2c66affSColin Finck } 608c2c66affSColin Finck else if ((ObjectName->Length == ObpDosDevicesShortName.Length - 609c2c66affSColin Finck sizeof(WCHAR)) && 610c2c66affSColin Finck (*(PULONG)(ObjectName->Buffer) == 611c2c66affSColin Finck ObpDosDevicesShortNameRoot.Alignment.LowPart) && 612c2c66affSColin Finck (*((PWCHAR)(ObjectName->Buffer) + 2) == 613c2c66affSColin Finck (WCHAR)(ObpDosDevicesShortNameRoot.Alignment.HighPart))) 614c2c66affSColin Finck { 615c2c66affSColin Finck /* FIXME! */ 616c2c66affSColin Finck } 617c2c66affSColin Finck } 618c2c66affSColin Finck } 619c2c66affSColin Finck } 620c2c66affSColin Finck 621c2c66affSColin Finck /* Check if we were reparsing a symbolic link */ 622c2c66affSColin Finck if (!SymLink) 623c2c66affSColin Finck { 624c2c66affSColin Finck /* Allow reparse */ 625c2c66affSColin Finck Reparse = TRUE; 626c2c66affSColin Finck MaxReparse = 30; 627c2c66affSColin Finck } 628c2c66affSColin Finck 629c2c66affSColin Finck /* Reparse */ 630c2c66affSColin Finck while (Reparse && MaxReparse) 631c2c66affSColin Finck { 632c2c66affSColin Finck /* Get the name */ 633c2c66affSColin Finck RemainingName = *ObjectName; 634c2c66affSColin Finck 635c2c66affSColin Finck /* Disable reparsing again */ 636c2c66affSColin Finck Reparse = FALSE; 637c2c66affSColin Finck 638c2c66affSColin Finck /* Start parse loop */ 639c2c66affSColin Finck while (TRUE) 640c2c66affSColin Finck { 641c2c66affSColin Finck /* Clear object */ 642c2c66affSColin Finck Object = NULL; 643c2c66affSColin Finck 644c2c66affSColin Finck /* Check if the name starts with a path separator */ 645c2c66affSColin Finck if ((RemainingName.Length) && 646c2c66affSColin Finck (RemainingName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR)) 647c2c66affSColin Finck { 648c2c66affSColin Finck /* Skip the path separator */ 649c2c66affSColin Finck RemainingName.Buffer++; 650c2c66affSColin Finck RemainingName.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR); 651c2c66affSColin Finck } 652c2c66affSColin Finck 653c2c66affSColin Finck /* Find the next Part Name */ 654c2c66affSColin Finck ComponentName = RemainingName; 655c2c66affSColin Finck while (RemainingName.Length) 656c2c66affSColin Finck { 657c2c66affSColin Finck /* Break if we found the \ ending */ 658c2c66affSColin Finck if (RemainingName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR) break; 659c2c66affSColin Finck 660c2c66affSColin Finck /* Move on */ 661c2c66affSColin Finck RemainingName.Buffer++; 662c2c66affSColin Finck RemainingName.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR); 663c2c66affSColin Finck } 664c2c66affSColin Finck 665c2c66affSColin Finck /* Get its size and make sure it's valid */ 666c2c66affSColin Finck ComponentName.Length -= RemainingName.Length; 667c2c66affSColin Finck if (!ComponentName.Length) 668c2c66affSColin Finck { 669c2c66affSColin Finck /* Invalid size, fail */ 670c2c66affSColin Finck Status = STATUS_OBJECT_NAME_INVALID; 671c2c66affSColin Finck break; 672c2c66affSColin Finck } 673c2c66affSColin Finck 674c2c66affSColin Finck /* Check if we're in the root */ 675c2c66affSColin Finck if (!Directory) Directory = RootDirectory; 676c2c66affSColin Finck 677c2c66affSColin Finck /* Check if this is a user-mode call that needs to traverse */ 678c2c66affSColin Finck if ((AccessCheckMode != KernelMode) && 679c2c66affSColin Finck !(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE)) 680c2c66affSColin Finck { 681c2c66affSColin Finck /* We shouldn't have referenced a directory yet */ 682c2c66affSColin Finck ASSERT(ReferencedDirectory == NULL); 683c2c66affSColin Finck 684c2c66affSColin Finck /* Reference the directory */ 685c2c66affSColin Finck ObReferenceObject(Directory); 686c2c66affSColin Finck ReferencedDirectory = Directory; 687c2c66affSColin Finck 688c2c66affSColin Finck /* Check if we have a parent directory */ 689c2c66affSColin Finck if (ParentDirectory) 690c2c66affSColin Finck { 691c2c66affSColin Finck /* Check for traverse access */ 692c2c66affSColin Finck if (!ObpCheckTraverseAccess(ParentDirectory, 693c2c66affSColin Finck DIRECTORY_TRAVERSE, 694c2c66affSColin Finck AccessState, 695c2c66affSColin Finck FALSE, 696c2c66affSColin Finck AccessCheckMode, 697c2c66affSColin Finck &Status)) 698c2c66affSColin Finck { 699c2c66affSColin Finck /* We don't have it, fail */ 700c2c66affSColin Finck break; 701c2c66affSColin Finck } 702c2c66affSColin Finck } 703c2c66affSColin Finck } 704c2c66affSColin Finck 705c2c66affSColin Finck /* Check if we don't have a remaining name yet */ 706c2c66affSColin Finck if (!RemainingName.Length) 707c2c66affSColin Finck { 708c2c66affSColin Finck /* Check if we don't have a referenced directory yet */ 709c2c66affSColin Finck if (!ReferencedDirectory) 710c2c66affSColin Finck { 711c2c66affSColin Finck /* Reference it */ 712c2c66affSColin Finck ObReferenceObject(Directory); 713c2c66affSColin Finck ReferencedDirectory = Directory; 714c2c66affSColin Finck } 715c2c66affSColin Finck 716c2c66affSColin Finck /* Check if we are inserting an object */ 717c2c66affSColin Finck if (InsertObject) 718c2c66affSColin Finck { 719c2c66affSColin Finck /* Lock the directory */ 720c2c66affSColin Finck ObpAcquireDirectoryLockExclusive(Directory, LookupContext); 721c2c66affSColin Finck } 722c2c66affSColin Finck } 723c2c66affSColin Finck 724c2c66affSColin Finck /* Do the lookup */ 725c2c66affSColin Finck Object = ObpLookupEntryDirectory(Directory, 726c2c66affSColin Finck &ComponentName, 727c2c66affSColin Finck Attributes, 728c2c66affSColin Finck InsertObject ? FALSE : TRUE, 729c2c66affSColin Finck LookupContext); 730c2c66affSColin Finck if (!Object) 731c2c66affSColin Finck { 732c2c66affSColin Finck /* We didn't find it... do we still have a path? */ 733c2c66affSColin Finck if (RemainingName.Length) 734c2c66affSColin Finck { 735c2c66affSColin Finck /* Then tell the caller the path wasn't found */ 736c2c66affSColin Finck Status = STATUS_OBJECT_PATH_NOT_FOUND; 737c2c66affSColin Finck break; 738c2c66affSColin Finck } 739c2c66affSColin Finck else if (!InsertObject) 740c2c66affSColin Finck { 741c2c66affSColin Finck /* Otherwise, we have a path, but the name isn't valid */ 742c2c66affSColin Finck Status = STATUS_OBJECT_NAME_NOT_FOUND; 743c2c66affSColin Finck break; 744c2c66affSColin Finck } 745c2c66affSColin Finck 746c2c66affSColin Finck /* Check create access for the object */ 747c2c66affSColin Finck if (!ObCheckCreateObjectAccess(Directory, 748c2c66affSColin Finck ObjectType == ObDirectoryType ? 749c2c66affSColin Finck DIRECTORY_CREATE_SUBDIRECTORY : 750c2c66affSColin Finck DIRECTORY_CREATE_OBJECT, 751c2c66affSColin Finck AccessState, 752c2c66affSColin Finck &ComponentName, 753c2c66affSColin Finck FALSE, 754c2c66affSColin Finck AccessCheckMode, 755c2c66affSColin Finck &Status)) 756c2c66affSColin Finck { 757c2c66affSColin Finck /* We don't have create access, fail */ 758c2c66affSColin Finck break; 759c2c66affSColin Finck } 760c2c66affSColin Finck 761c2c66affSColin Finck /* Get the object header */ 762c2c66affSColin Finck ObjectHeader = OBJECT_TO_OBJECT_HEADER(InsertObject); 763c2c66affSColin Finck 764c2c66affSColin Finck /* FIXME: Check if this is a Section Object or Sym Link */ 765c2c66affSColin Finck /* FIXME: If it is, then check if this isn't session 0 */ 766c2c66affSColin Finck /* FIXME: If it isn't, check for SeCreateGlobalPrivilege */ 767c2c66affSColin Finck /* FIXME: If privilege isn't there, check for unsecure name */ 768c2c66affSColin Finck /* FIXME: If it isn't a known unsecure name, then fail */ 769c2c66affSColin Finck 770c2c66affSColin Finck /* Create Object Name */ 771c2c66affSColin Finck NewName = ExAllocatePoolWithTag(PagedPool, 772c2c66affSColin Finck ComponentName.Length, 773c2c66affSColin Finck OB_NAME_TAG); 774c2c66affSColin Finck if (!(NewName) || 775c2c66affSColin Finck !(ObpInsertEntryDirectory(Directory, 776c2c66affSColin Finck LookupContext, 777c2c66affSColin Finck ObjectHeader))) 778c2c66affSColin Finck { 779c2c66affSColin Finck /* Either couldn't allocate the name, or insert failed */ 780c2c66affSColin Finck if (NewName) ExFreePoolWithTag(NewName, OB_NAME_TAG); 781c2c66affSColin Finck 782c2c66affSColin Finck /* Fail due to memory reasons */ 783c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES; 784c2c66affSColin Finck break; 785c2c66affSColin Finck } 786c2c66affSColin Finck 787c2c66affSColin Finck /* Reference newly to be inserted object */ 788c2c66affSColin Finck ObReferenceObject(InsertObject); 789c2c66affSColin Finck 790c2c66affSColin Finck /* Get the name information */ 791c2c66affSColin Finck ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader); 792c2c66affSColin Finck 793c2c66affSColin Finck /* Reference the directory */ 794c2c66affSColin Finck ObReferenceObject(Directory); 795c2c66affSColin Finck 796c2c66affSColin Finck /* Copy the Name */ 797c2c66affSColin Finck RtlCopyMemory(NewName, 798c2c66affSColin Finck ComponentName.Buffer, 799c2c66affSColin Finck ComponentName.Length); 800c2c66affSColin Finck 801c2c66affSColin Finck /* Check if we had an old name */ 802c2c66affSColin Finck if (ObjectNameInfo->Name.Buffer) 803c2c66affSColin Finck { 804c2c66affSColin Finck /* Free it */ 805c2c66affSColin Finck ExFreePoolWithTag(ObjectNameInfo->Name.Buffer, OB_NAME_TAG); 806c2c66affSColin Finck } 807c2c66affSColin Finck 808c2c66affSColin Finck /* Write new one */ 809c2c66affSColin Finck ObjectNameInfo->Name.Buffer = NewName; 810c2c66affSColin Finck ObjectNameInfo->Name.Length = ComponentName.Length; 811c2c66affSColin Finck ObjectNameInfo->Name.MaximumLength = ComponentName.Length; 812c2c66affSColin Finck 813c2c66affSColin Finck /* Return Status and the Expected Object */ 814c2c66affSColin Finck Status = STATUS_SUCCESS; 815c2c66affSColin Finck Object = InsertObject; 816c2c66affSColin Finck 817c2c66affSColin Finck /* Get out of here */ 818c2c66affSColin Finck break; 819c2c66affSColin Finck } 820c2c66affSColin Finck 821c2c66affSColin Finck ReparseObject: 822c2c66affSColin Finck /* We found it, so now get its header */ 823c2c66affSColin Finck ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); 824c2c66affSColin Finck 825c2c66affSColin Finck /* 826c2c66affSColin Finck * Check for a parse Procedure, but don't bother to parse for an insert 827c2c66affSColin Finck * unless it's a Symbolic Link, in which case we MUST parse 828c2c66affSColin Finck */ 829c2c66affSColin Finck ParseRoutine = ObjectHeader->Type->TypeInfo.ParseProcedure; 830c2c66affSColin Finck if ((ParseRoutine) && 831c2c66affSColin Finck (!(InsertObject) || (ParseRoutine == ObpParseSymbolicLink))) 832c2c66affSColin Finck { 833c2c66affSColin Finck /* Use the Root Directory next time */ 834c2c66affSColin Finck Directory = NULL; 835c2c66affSColin Finck 836c2c66affSColin Finck /* Increment the pointer count */ 837*ff7cc6f3STimo Kreuzer InterlockedExchangeAddSizeT(&ObjectHeader->PointerCount, 1); 838c2c66affSColin Finck 839c2c66affSColin Finck /* Cleanup from the first lookup */ 840c2c66affSColin Finck ObpReleaseLookupContext(LookupContext); 841c2c66affSColin Finck 842c2c66affSColin Finck /* Check if we have a referenced directory */ 843c2c66affSColin Finck if (ReferencedDirectory) 844c2c66affSColin Finck { 845c2c66affSColin Finck /* We do, dereference it */ 846c2c66affSColin Finck ObDereferenceObject(ReferencedDirectory); 847c2c66affSColin Finck ReferencedDirectory = NULL; 848c2c66affSColin Finck } 849c2c66affSColin Finck 850c2c66affSColin Finck /* Check if we have a referenced parent directory */ 851c2c66affSColin Finck if (ReferencedParentDirectory) 852c2c66affSColin Finck { 853c2c66affSColin Finck /* We do, dereference it */ 854c2c66affSColin Finck ObDereferenceObject(ReferencedParentDirectory); 855c2c66affSColin Finck ReferencedParentDirectory = NULL; 856c2c66affSColin Finck } 857c2c66affSColin Finck 858c2c66affSColin Finck /* Call the Parse Procedure */ 859c2c66affSColin Finck ObpCalloutStart(&CalloutIrql); 860c2c66affSColin Finck Status = ParseRoutine(Object, 861c2c66affSColin Finck ObjectType, 862c2c66affSColin Finck AccessState, 863c2c66affSColin Finck AccessCheckMode, 864c2c66affSColin Finck Attributes, 865c2c66affSColin Finck ObjectName, 866c2c66affSColin Finck &RemainingName, 867c2c66affSColin Finck ParseContext, 868c2c66affSColin Finck SecurityQos, 869c2c66affSColin Finck &Object); 870c2c66affSColin Finck ObpCalloutEnd(CalloutIrql, "Parse", ObjectHeader->Type, Object); 871c2c66affSColin Finck 872c2c66affSColin Finck /* Remove our extra reference */ 873c2c66affSColin Finck ObDereferenceObject(&ObjectHeader->Body); 874c2c66affSColin Finck 875c2c66affSColin Finck /* Check if we have to reparse */ 876c2c66affSColin Finck if ((Status == STATUS_REPARSE) || 877c2c66affSColin Finck (Status == STATUS_REPARSE_OBJECT)) 878c2c66affSColin Finck { 879c2c66affSColin Finck /* Reparse again */ 880c2c66affSColin Finck Reparse = TRUE; 881c2c66affSColin Finck --MaxReparse; 882c2c66affSColin Finck if (MaxReparse == 0) 883c2c66affSColin Finck { 884c2c66affSColin Finck Object = NULL; 885c2c66affSColin Finck break; 886c2c66affSColin Finck } 887c2c66affSColin Finck 888c2c66affSColin Finck /* Start over from root if we got sent back there */ 889c2c66affSColin Finck if ((Status == STATUS_REPARSE_OBJECT) || 890c2c66affSColin Finck (ObjectName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)) 891c2c66affSColin Finck { 892c2c66affSColin Finck /* Check if we got a root directory */ 893c2c66affSColin Finck if (RootHandle) 894c2c66affSColin Finck { 895c2c66affSColin Finck /* Stop using it, because we have a new directory now */ 896c2c66affSColin Finck ObDereferenceObject(RootDirectory); 897c2c66affSColin Finck RootHandle = NULL; 898c2c66affSColin Finck } 899c2c66affSColin Finck 900c2c66affSColin Finck /* Start at Root */ 901c2c66affSColin Finck ParentDirectory = NULL; 902c2c66affSColin Finck RootDirectory = ObpRootDirectoryObject; 903c2c66affSColin Finck 904c2c66affSColin Finck /* Check for reparse status */ 905c2c66affSColin Finck if (Status == STATUS_REPARSE_OBJECT) 906c2c66affSColin Finck { 907c2c66affSColin Finck /* Don't reparse again */ 908c2c66affSColin Finck Reparse = FALSE; 909c2c66affSColin Finck 910c2c66affSColin Finck /* Did we actually get an object to which to reparse? */ 911c2c66affSColin Finck if (!Object) 912c2c66affSColin Finck { 913c2c66affSColin Finck /* We didn't, so set a failure status */ 914c2c66affSColin Finck Status = STATUS_OBJECT_NAME_NOT_FOUND; 915c2c66affSColin Finck } 916c2c66affSColin Finck else 917c2c66affSColin Finck { 918c2c66affSColin Finck /* We did, so we're free to parse the new object */ 919c2c66affSColin Finck goto ReparseObject; 920c2c66affSColin Finck } 921c2c66affSColin Finck } 922c2c66affSColin Finck else 923c2c66affSColin Finck { 924c2c66affSColin Finck /* This is a symbolic link */ 925c2c66affSColin Finck SymLink = TRUE; 926c2c66affSColin Finck goto ParseFromRoot; 927c2c66affSColin Finck } 928c2c66affSColin Finck } 929c2c66affSColin Finck else if (RootDirectory == ObpRootDirectoryObject) 930c2c66affSColin Finck { 931c2c66affSColin Finck /* We got STATUS_REPARSE but are at the Root Directory */ 932c2c66affSColin Finck Object = NULL; 933c2c66affSColin Finck Status = STATUS_OBJECT_NAME_NOT_FOUND; 934c2c66affSColin Finck Reparse = FALSE; 935c2c66affSColin Finck } 936c2c66affSColin Finck } 937c2c66affSColin Finck else if (!NT_SUCCESS(Status)) 938c2c66affSColin Finck { 939c2c66affSColin Finck /* Total failure */ 940c2c66affSColin Finck Object = NULL; 941c2c66affSColin Finck } 942c2c66affSColin Finck else if (!Object) 943c2c66affSColin Finck { 944c2c66affSColin Finck /* We didn't reparse but we didn't find the Object Either */ 945c2c66affSColin Finck Status = STATUS_OBJECT_NAME_NOT_FOUND; 946c2c66affSColin Finck } 947c2c66affSColin Finck 948c2c66affSColin Finck /* Break out of the loop */ 949c2c66affSColin Finck break; 950c2c66affSColin Finck } 951c2c66affSColin Finck else 952c2c66affSColin Finck { 953c2c66affSColin Finck /* No parse routine...do we still have a remaining name? */ 954c2c66affSColin Finck if (!RemainingName.Length) 955c2c66affSColin Finck { 956c2c66affSColin Finck /* Are we creating an object? */ 957c2c66affSColin Finck if (!InsertObject) 958c2c66affSColin Finck { 959c2c66affSColin Finck /* Check if this is a user-mode call that needs to traverse */ 960c2c66affSColin Finck if ((AccessCheckMode != KernelMode) && 961c2c66affSColin Finck !(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE)) 962c2c66affSColin Finck { 963c2c66affSColin Finck /* Check if we can get it */ 964c2c66affSColin Finck if (!ObpCheckTraverseAccess(Directory, 965c2c66affSColin Finck DIRECTORY_TRAVERSE, 966c2c66affSColin Finck AccessState, 967c2c66affSColin Finck FALSE, 968c2c66affSColin Finck AccessCheckMode, 969c2c66affSColin Finck &Status)) 970c2c66affSColin Finck { 971c2c66affSColin Finck /* We don't have access, fail */ 972c2c66affSColin Finck Object = NULL; 973c2c66affSColin Finck break; 974c2c66affSColin Finck } 975c2c66affSColin Finck } 976c2c66affSColin Finck 977c2c66affSColin Finck /* Reference the Object */ 978c2c66affSColin Finck Status = ObReferenceObjectByPointer(Object, 979c2c66affSColin Finck 0, 980c2c66affSColin Finck ObjectType, 981c2c66affSColin Finck AccessMode); 982c2c66affSColin Finck if (!NT_SUCCESS(Status)) Object = NULL; 983c2c66affSColin Finck } 984c2c66affSColin Finck 985c2c66affSColin Finck /* And get out of the reparse loop */ 986c2c66affSColin Finck break; 987c2c66affSColin Finck } 988c2c66affSColin Finck else 989c2c66affSColin Finck { 990c2c66affSColin Finck /* We still have a name; check if this is a directory object */ 991c2c66affSColin Finck if (ObjectHeader->Type == ObDirectoryType) 992c2c66affSColin Finck { 993c2c66affSColin Finck /* Check if we have a referenced parent directory */ 994c2c66affSColin Finck if (ReferencedParentDirectory) 995c2c66affSColin Finck { 996c2c66affSColin Finck /* Dereference it */ 997c2c66affSColin Finck ObDereferenceObject(ReferencedParentDirectory); 998c2c66affSColin Finck } 999c2c66affSColin Finck 1000c2c66affSColin Finck /* Restart the lookup from this directory */ 1001c2c66affSColin Finck ReferencedParentDirectory = ReferencedDirectory; 1002c2c66affSColin Finck ParentDirectory = Directory; 1003c2c66affSColin Finck Directory = Object; 1004c2c66affSColin Finck ReferencedDirectory = NULL; 1005c2c66affSColin Finck } 1006c2c66affSColin Finck else 1007c2c66affSColin Finck { 1008c2c66affSColin Finck /* We still have a name, but no parse routine for it */ 1009c2c66affSColin Finck Status = STATUS_OBJECT_TYPE_MISMATCH; 1010c2c66affSColin Finck Object = NULL; 1011c2c66affSColin Finck break; 1012c2c66affSColin Finck } 1013c2c66affSColin Finck } 1014c2c66affSColin Finck } 1015c2c66affSColin Finck } 1016c2c66affSColin Finck } 1017c2c66affSColin Finck 1018c2c66affSColin Finck /* Check if we failed */ 1019c2c66affSColin Finck if (!NT_SUCCESS(Status)) 1020c2c66affSColin Finck { 1021c2c66affSColin Finck /* Cleanup after lookup */ 1022c2c66affSColin Finck ObpReleaseLookupContext(LookupContext); 1023c2c66affSColin Finck } 1024c2c66affSColin Finck 1025c2c66affSColin Finck /* Check if we have a device map and dereference it if so */ 1026c2c66affSColin Finck //if (DeviceMap) ObfDereferenceDeviceMap(DeviceMap); 1027c2c66affSColin Finck 1028c2c66affSColin Finck /* Check if we have a referenced directory and dereference it if so */ 1029c2c66affSColin Finck if (ReferencedDirectory) ObDereferenceObject(ReferencedDirectory); 1030c2c66affSColin Finck 1031c2c66affSColin Finck /* Check if we have a referenced parent directory */ 1032c2c66affSColin Finck if (ReferencedParentDirectory) 1033c2c66affSColin Finck { 1034c2c66affSColin Finck /* We do, dereference it */ 1035c2c66affSColin Finck ObDereferenceObject(ReferencedParentDirectory); 1036c2c66affSColin Finck } 1037c2c66affSColin Finck 1038c2c66affSColin Finck /* Set the found object and check if we got one */ 1039c2c66affSColin Finck *FoundObject = Object; 1040c2c66affSColin Finck if (!Object) 1041c2c66affSColin Finck { 1042c2c66affSColin Finck /* Nothing was found. Did we reparse or get success? */ 1043c2c66affSColin Finck if ((Status == STATUS_REPARSE) || (NT_SUCCESS(Status))) 1044c2c66affSColin Finck { 1045c2c66affSColin Finck /* Set correct failure */ 1046c2c66affSColin Finck Status = STATUS_OBJECT_NAME_NOT_FOUND; 1047c2c66affSColin Finck } 1048c2c66affSColin Finck } 1049c2c66affSColin Finck 1050c2c66affSColin Finck /* Check if we had a root directory */ 1051c2c66affSColin Finck if (RootHandle) ObDereferenceObject(RootDirectory); 1052c2c66affSColin Finck 1053c2c66affSColin Finck /* Return status to caller */ 1054c2c66affSColin Finck OBTRACE(OB_NAMESPACE_DEBUG, 1055c2c66affSColin Finck "%s - Found Object: %p. Expected: %p\n", 1056c2c66affSColin Finck __FUNCTION__, 1057c2c66affSColin Finck *FoundObject, 1058c2c66affSColin Finck InsertObject); 1059c2c66affSColin Finck return Status; 1060c2c66affSColin Finck } 1061c2c66affSColin Finck 1062c2c66affSColin Finck /* PUBLIC FUNCTIONS *********************************************************/ 1063c2c66affSColin Finck 1064c2c66affSColin Finck NTSTATUS 1065c2c66affSColin Finck NTAPI 1066c2c66affSColin Finck ObQueryNameString(IN PVOID Object, 1067c2c66affSColin Finck OUT POBJECT_NAME_INFORMATION ObjectNameInfo, 1068c2c66affSColin Finck IN ULONG Length, 1069c2c66affSColin Finck OUT PULONG ReturnLength) 1070c2c66affSColin Finck { 1071c2c66affSColin Finck POBJECT_HEADER_NAME_INFO LocalInfo; 1072c2c66affSColin Finck POBJECT_HEADER ObjectHeader; 1073c2c66affSColin Finck POBJECT_DIRECTORY ParentDirectory; 1074c2c66affSColin Finck ULONG NameSize; 1075c2c66affSColin Finck PWCH ObjectName; 1076c2c66affSColin Finck BOOLEAN ObjectIsNamed; 1077c2c66affSColin Finck NTSTATUS Status = STATUS_SUCCESS; 1078c2c66affSColin Finck 1079c2c66affSColin Finck /* Get the Kernel Meta-Structures */ 1080c2c66affSColin Finck ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); 1081c2c66affSColin Finck LocalInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader); 1082c2c66affSColin Finck 1083c2c66affSColin Finck /* Check if a Query Name Procedure is available */ 1084c2c66affSColin Finck if (ObjectHeader->Type->TypeInfo.QueryNameProcedure) 1085c2c66affSColin Finck { 1086c2c66affSColin Finck /* Call the procedure inside SEH */ 1087c2c66affSColin Finck ObjectIsNamed = ((LocalInfo) && (LocalInfo->Name.Length > 0)); 1088c2c66affSColin Finck 1089c2c66affSColin Finck _SEH2_TRY 1090c2c66affSColin Finck { 1091c2c66affSColin Finck Status = ObjectHeader->Type->TypeInfo.QueryNameProcedure(Object, 1092c2c66affSColin Finck ObjectIsNamed, 1093c2c66affSColin Finck ObjectNameInfo, 1094c2c66affSColin Finck Length, 1095c2c66affSColin Finck ReturnLength, 1096c2c66affSColin Finck KernelMode); 1097c2c66affSColin Finck } 1098c2c66affSColin Finck _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1099c2c66affSColin Finck { 1100c2c66affSColin Finck /* Return the exception code */ 1101c2c66affSColin Finck Status = _SEH2_GetExceptionCode(); 1102c2c66affSColin Finck } 1103c2c66affSColin Finck _SEH2_END; 1104c2c66affSColin Finck 1105c2c66affSColin Finck return Status; 1106c2c66affSColin Finck } 1107c2c66affSColin Finck 1108c2c66affSColin Finck /* Check if the object doesn't even have a name */ 1109c2c66affSColin Finck if (!(LocalInfo) || !(LocalInfo->Name.Buffer)) 1110c2c66affSColin Finck { 1111c2c66affSColin Finck Status = STATUS_SUCCESS; 1112c2c66affSColin Finck 1113c2c66affSColin Finck _SEH2_TRY 1114c2c66affSColin Finck { 1115c2c66affSColin Finck /* We're returning the name structure */ 1116c2c66affSColin Finck *ReturnLength = sizeof(OBJECT_NAME_INFORMATION); 1117c2c66affSColin Finck 1118c2c66affSColin Finck /* Check if we were given enough space */ 1119c2c66affSColin Finck if (*ReturnLength > Length) 1120c2c66affSColin Finck { 1121c2c66affSColin Finck Status = STATUS_INFO_LENGTH_MISMATCH; 1122c2c66affSColin Finck } 1123c2c66affSColin Finck else 1124c2c66affSColin Finck { 1125c2c66affSColin Finck /* Return an empty buffer */ 1126c2c66affSColin Finck RtlInitEmptyUnicodeString(&ObjectNameInfo->Name, NULL, 0); 1127c2c66affSColin Finck } 1128c2c66affSColin Finck } 1129c2c66affSColin Finck _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1130c2c66affSColin Finck { 1131c2c66affSColin Finck /* Return the exception code */ 1132c2c66affSColin Finck Status = _SEH2_GetExceptionCode(); 1133c2c66affSColin Finck } 1134c2c66affSColin Finck _SEH2_END; 1135c2c66affSColin Finck 1136c2c66affSColin Finck return Status; 1137c2c66affSColin Finck } 1138c2c66affSColin Finck 1139c2c66affSColin Finck /* 1140c2c66affSColin Finck * Find the size needed for the name. We won't do 1141c2c66affSColin Finck * this during the Name Creation loop because we want 1142c2c66affSColin Finck * to let the caller know that the buffer isn't big 1143c2c66affSColin Finck * enough right at the beginning, not work our way through 1144c2c66affSColin Finck * and find out at the end 1145c2c66affSColin Finck */ 1146c2c66affSColin Finck _SEH2_TRY 1147c2c66affSColin Finck { 1148c2c66affSColin Finck if (Object == ObpRootDirectoryObject) 1149c2c66affSColin Finck { 1150c2c66affSColin Finck /* Size of the '\' string */ 1151c2c66affSColin Finck NameSize = sizeof(OBJ_NAME_PATH_SEPARATOR); 1152c2c66affSColin Finck } 1153c2c66affSColin Finck else 1154c2c66affSColin Finck { 1155c2c66affSColin Finck /* Get the Object Directory and add name of Object */ 1156c2c66affSColin Finck ParentDirectory = LocalInfo->Directory; 1157c2c66affSColin Finck NameSize = sizeof(OBJ_NAME_PATH_SEPARATOR) + LocalInfo->Name.Length; 1158c2c66affSColin Finck 1159c2c66affSColin Finck /* Loop inside the directory to get the top-most one (meaning root) */ 1160c2c66affSColin Finck while ((ParentDirectory != ObpRootDirectoryObject) && (ParentDirectory)) 1161c2c66affSColin Finck { 1162c2c66affSColin Finck /* Get the Name Information */ 1163c2c66affSColin Finck LocalInfo = OBJECT_HEADER_TO_NAME_INFO( 1164c2c66affSColin Finck OBJECT_TO_OBJECT_HEADER(ParentDirectory)); 1165c2c66affSColin Finck 1166c2c66affSColin Finck /* Add the size of the Directory Name */ 1167c2c66affSColin Finck if (LocalInfo && LocalInfo->Directory) 1168c2c66affSColin Finck { 1169c2c66affSColin Finck /* Size of the '\' string + Directory Name */ 1170c2c66affSColin Finck NameSize += sizeof(OBJ_NAME_PATH_SEPARATOR) + 1171c2c66affSColin Finck LocalInfo->Name.Length; 1172c2c66affSColin Finck 1173c2c66affSColin Finck /* Move to next parent Directory */ 1174c2c66affSColin Finck ParentDirectory = LocalInfo->Directory; 1175c2c66affSColin Finck } 1176c2c66affSColin Finck else 1177c2c66affSColin Finck { 1178c2c66affSColin Finck /* Directory with no name. We append "...\" */ 1179c2c66affSColin Finck NameSize += sizeof(L"...") + sizeof(OBJ_NAME_PATH_SEPARATOR); 1180c2c66affSColin Finck break; 1181c2c66affSColin Finck } 1182c2c66affSColin Finck } 1183c2c66affSColin Finck } 1184c2c66affSColin Finck 1185c2c66affSColin Finck /* Finally, add the name of the structure and the null char */ 1186c2c66affSColin Finck *ReturnLength = NameSize + 1187c2c66affSColin Finck sizeof(OBJECT_NAME_INFORMATION) + 1188c2c66affSColin Finck sizeof(UNICODE_NULL); 1189c2c66affSColin Finck 1190c2c66affSColin Finck /* Check if we were given enough space */ 1191c2c66affSColin Finck if (*ReturnLength > Length) _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH); 1192c2c66affSColin Finck 1193c2c66affSColin Finck /* 1194c2c66affSColin Finck * Now we will actually create the name. We work backwards because 1195c2c66affSColin Finck * it's easier to start off from the Name we have and walk up the 1196c2c66affSColin Finck * parent directories. We use the same logic as Name Length calculation. 1197c2c66affSColin Finck */ 1198c2c66affSColin Finck LocalInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader); 1199c2c66affSColin Finck ObjectName = (PWCH)((ULONG_PTR)ObjectNameInfo + *ReturnLength); 1200c2c66affSColin Finck *--ObjectName = UNICODE_NULL; 1201c2c66affSColin Finck 1202c2c66affSColin Finck /* Check if the object is actually the Root directory */ 1203c2c66affSColin Finck if (Object == ObpRootDirectoryObject) 1204c2c66affSColin Finck { 1205c2c66affSColin Finck /* This is already the Root Directory, return "\\" */ 1206c2c66affSColin Finck *--ObjectName = OBJ_NAME_PATH_SEPARATOR; 1207c2c66affSColin Finck ObjectNameInfo->Name.Length = (USHORT)NameSize; 1208c2c66affSColin Finck ObjectNameInfo->Name.MaximumLength = (USHORT)(NameSize + 1209c2c66affSColin Finck sizeof(UNICODE_NULL)); 1210c2c66affSColin Finck ObjectNameInfo->Name.Buffer = ObjectName; 1211c2c66affSColin Finck Status = STATUS_SUCCESS; 1212c2c66affSColin Finck } 1213c2c66affSColin Finck else 1214c2c66affSColin Finck { 1215c2c66affSColin Finck /* Start by adding the Object's Name */ 1216c2c66affSColin Finck ObjectName = (PWCH)((ULONG_PTR)ObjectName - 1217c2c66affSColin Finck LocalInfo->Name.Length); 1218c2c66affSColin Finck RtlCopyMemory(ObjectName, 1219c2c66affSColin Finck LocalInfo->Name.Buffer, 1220c2c66affSColin Finck LocalInfo->Name.Length); 1221c2c66affSColin Finck 1222c2c66affSColin Finck /* Now parse the Parent directories until we reach the top */ 1223c2c66affSColin Finck ParentDirectory = LocalInfo->Directory; 1224c2c66affSColin Finck while ((ParentDirectory != ObpRootDirectoryObject) && (ParentDirectory)) 1225c2c66affSColin Finck { 1226c2c66affSColin Finck /* Get the name information */ 1227c2c66affSColin Finck LocalInfo = OBJECT_HEADER_TO_NAME_INFO( 1228c2c66affSColin Finck OBJECT_TO_OBJECT_HEADER(ParentDirectory)); 1229c2c66affSColin Finck 1230c2c66affSColin Finck /* Add the "\" */ 1231c2c66affSColin Finck *(--ObjectName) = OBJ_NAME_PATH_SEPARATOR; 1232c2c66affSColin Finck 1233c2c66affSColin Finck /* Add the Parent Directory's Name */ 1234c2c66affSColin Finck if (LocalInfo && LocalInfo->Name.Buffer) 1235c2c66affSColin Finck { 1236c2c66affSColin Finck /* Add the name */ 1237c2c66affSColin Finck ObjectName = (PWCH)((ULONG_PTR)ObjectName - 1238c2c66affSColin Finck LocalInfo->Name.Length); 1239c2c66affSColin Finck RtlCopyMemory(ObjectName, 1240c2c66affSColin Finck LocalInfo->Name.Buffer, 1241c2c66affSColin Finck LocalInfo->Name.Length); 1242c2c66affSColin Finck 1243c2c66affSColin Finck /* Move to next parent */ 1244c2c66affSColin Finck ParentDirectory = LocalInfo->Directory; 1245c2c66affSColin Finck } 1246c2c66affSColin Finck else 1247c2c66affSColin Finck { 1248c2c66affSColin Finck /* Directory without a name, we add "..." */ 1249c2c66affSColin Finck ObjectName = (PWCH)((ULONG_PTR)ObjectName - 1250c2c66affSColin Finck sizeof(L"...") + 1251c2c66affSColin Finck sizeof(UNICODE_NULL)); 1252c2c66affSColin Finck RtlCopyMemory(ObjectName, L"...", sizeof(L"...")); 1253c2c66affSColin Finck break; 1254c2c66affSColin Finck } 1255c2c66affSColin Finck } 1256c2c66affSColin Finck 1257c2c66affSColin Finck /* Add Root Directory Name */ 1258c2c66affSColin Finck *(--ObjectName) = OBJ_NAME_PATH_SEPARATOR; 1259c2c66affSColin Finck ObjectNameInfo->Name.Length = (USHORT)NameSize; 1260c2c66affSColin Finck ObjectNameInfo->Name.MaximumLength = 1261c2c66affSColin Finck (USHORT)(NameSize + sizeof(UNICODE_NULL)); 1262c2c66affSColin Finck ObjectNameInfo->Name.Buffer = ObjectName; 1263c2c66affSColin Finck } 1264c2c66affSColin Finck } 1265c2c66affSColin Finck _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1266c2c66affSColin Finck { 1267c2c66affSColin Finck /* Return the exception code */ 1268c2c66affSColin Finck Status = _SEH2_GetExceptionCode(); 1269c2c66affSColin Finck } 1270c2c66affSColin Finck _SEH2_END; 1271c2c66affSColin Finck 1272c2c66affSColin Finck /* Return success */ 1273c2c66affSColin Finck return Status; 1274c2c66affSColin Finck } 1275c2c66affSColin Finck 1276c2c66affSColin Finck /* EOF */ 1277