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 32b9423f07SPierre Schweitzer WCHAR ObpUnsecureGlobalNamesBuffer[128] = {0}; 33b9423f07SPierre Schweitzer ULONG ObpUnsecureGlobalNamesLength = sizeof(ObpUnsecureGlobalNamesBuffer); 34b9423f07SPierre Schweitzer 35c2c66affSColin Finck /* PRIVATE FUNCTIONS *********************************************************/ 36c2c66affSColin Finck 3771fefa32STimo Kreuzer INIT_FUNCTION 38c2c66affSColin Finck NTSTATUS 39c2c66affSColin Finck NTAPI 4095d303bfSPierre Schweitzer ObpGetDosDevicesProtection(OUT PSECURITY_DESCRIPTOR SecurityDescriptor) 41c2c66affSColin Finck { 42c2c66affSColin Finck PACL Dacl; 4395d303bfSPierre Schweitzer ULONG AclSize; 441b42731dSPierre Schweitzer NTSTATUS Status; 4595d303bfSPierre Schweitzer 4695d303bfSPierre Schweitzer /* Initialize the SD */ 471b42731dSPierre Schweitzer Status = RtlCreateSecurityDescriptor(SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION); 481b42731dSPierre Schweitzer ASSERT(NT_SUCCESS(Status)); 49c2c66affSColin Finck 5033f524c6SPierre Schweitzer if (ObpProtectionMode & 1) 5133f524c6SPierre Schweitzer { 52c2c66affSColin Finck AclSize = sizeof(ACL) + 53c2c66affSColin Finck sizeof(ACE) + RtlLengthSid(SeWorldSid) + 54c2c66affSColin Finck sizeof(ACE) + RtlLengthSid(SeLocalSystemSid) + 55c2c66affSColin Finck sizeof(ACE) + RtlLengthSid(SeWorldSid) + 56c2c66affSColin Finck sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid) + 57c2c66affSColin Finck sizeof(ACE) + RtlLengthSid(SeLocalSystemSid) + 58c2c66affSColin Finck sizeof(ACE) + RtlLengthSid(SeCreatorOwnerSid); 59c2c66affSColin Finck 6095d303bfSPierre Schweitzer /* Allocate the ACL */ 6195d303bfSPierre Schweitzer Dacl = ExAllocatePoolWithTag(PagedPool, AclSize, 'lcaD'); 6295d303bfSPierre Schweitzer if (Dacl == NULL) 63c2c66affSColin Finck { 64c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES; 65c2c66affSColin Finck } 66c2c66affSColin Finck 67c2c66affSColin Finck /* Initialize the DACL */ 681b42731dSPierre Schweitzer Status = RtlCreateAcl(Dacl, AclSize, ACL_REVISION); 691b42731dSPierre Schweitzer ASSERT(NT_SUCCESS(Status)); 70c2c66affSColin Finck 71c2c66affSColin Finck /* Add the ACEs */ 721b42731dSPierre Schweitzer Status = RtlAddAccessAllowedAce(Dacl, 73c2c66affSColin Finck ACL_REVISION, 74c2c66affSColin Finck GENERIC_READ | GENERIC_EXECUTE, 75c2c66affSColin Finck SeWorldSid); 761b42731dSPierre Schweitzer ASSERT(NT_SUCCESS(Status)); 77c2c66affSColin Finck 781b42731dSPierre Schweitzer Status = RtlAddAccessAllowedAce(Dacl, 79c2c66affSColin Finck ACL_REVISION, 80c2c66affSColin Finck GENERIC_ALL, 81c2c66affSColin Finck SeLocalSystemSid); 821b42731dSPierre Schweitzer ASSERT(NT_SUCCESS(Status)); 83c2c66affSColin Finck 841b42731dSPierre Schweitzer Status = RtlAddAccessAllowedAceEx(Dacl, 85c2c66affSColin Finck ACL_REVISION, 86c2c66affSColin Finck INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, 87c2c66affSColin Finck GENERIC_EXECUTE, 88c2c66affSColin Finck SeWorldSid); 891b42731dSPierre Schweitzer ASSERT(NT_SUCCESS(Status)); 90c2c66affSColin Finck 911b42731dSPierre Schweitzer Status = RtlAddAccessAllowedAceEx(Dacl, 92c2c66affSColin Finck ACL_REVISION, 93c2c66affSColin Finck INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, 94c2c66affSColin Finck GENERIC_ALL, 95c2c66affSColin Finck SeAliasAdminsSid); 961b42731dSPierre Schweitzer ASSERT(NT_SUCCESS(Status)); 97c2c66affSColin Finck 981b42731dSPierre Schweitzer Status = RtlAddAccessAllowedAceEx(Dacl, 99c2c66affSColin Finck ACL_REVISION, 100c2c66affSColin Finck INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, 101c2c66affSColin Finck GENERIC_ALL, 102c2c66affSColin Finck SeLocalSystemSid); 1031b42731dSPierre Schweitzer ASSERT(NT_SUCCESS(Status)); 104c2c66affSColin Finck 1051b42731dSPierre Schweitzer Status = RtlAddAccessAllowedAceEx(Dacl, 106c2c66affSColin Finck ACL_REVISION, 107c2c66affSColin Finck INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, 108c2c66affSColin Finck GENERIC_ALL, 109c2c66affSColin Finck SeCreatorOwnerSid); 1101b42731dSPierre Schweitzer ASSERT(NT_SUCCESS(Status)); 11133f524c6SPierre Schweitzer } 11233f524c6SPierre Schweitzer else 11333f524c6SPierre Schweitzer { 11433f524c6SPierre Schweitzer AclSize = sizeof(ACL) + 11533f524c6SPierre Schweitzer sizeof(ACE) + RtlLengthSid(SeLocalSystemSid) + 11633f524c6SPierre Schweitzer sizeof(ACE) + RtlLengthSid(SeWorldSid) + 11733f524c6SPierre Schweitzer sizeof(ACE) + RtlLengthSid(SeLocalSystemSid); 11833f524c6SPierre Schweitzer 11995d303bfSPierre Schweitzer /* Allocate the ACL */ 12095d303bfSPierre Schweitzer Dacl = ExAllocatePoolWithTag(PagedPool, AclSize, 'lcaD'); 12195d303bfSPierre Schweitzer if (Dacl == NULL) 12233f524c6SPierre Schweitzer { 12333f524c6SPierre Schweitzer return STATUS_INSUFFICIENT_RESOURCES; 12433f524c6SPierre Schweitzer } 12533f524c6SPierre Schweitzer 12633f524c6SPierre Schweitzer /* Initialize the DACL */ 1271b42731dSPierre Schweitzer Status = RtlCreateAcl(Dacl, AclSize, ACL_REVISION); 1281b42731dSPierre Schweitzer ASSERT(NT_SUCCESS(Status)); 12933f524c6SPierre Schweitzer 13033f524c6SPierre Schweitzer /* Add the ACEs */ 1311b42731dSPierre Schweitzer Status = RtlAddAccessAllowedAce(Dacl, 13233f524c6SPierre Schweitzer ACL_REVISION, 13333f524c6SPierre Schweitzer GENERIC_READ | GENERIC_EXECUTE | GENERIC_WRITE, 13433f524c6SPierre Schweitzer SeWorldSid); 1351b42731dSPierre Schweitzer ASSERT(NT_SUCCESS(Status)); 13633f524c6SPierre Schweitzer 1371b42731dSPierre Schweitzer Status = RtlAddAccessAllowedAce(Dacl, 13833f524c6SPierre Schweitzer ACL_REVISION, 13933f524c6SPierre Schweitzer GENERIC_ALL, 14033f524c6SPierre Schweitzer SeLocalSystemSid); 1411b42731dSPierre Schweitzer ASSERT(NT_SUCCESS(Status)); 14233f524c6SPierre Schweitzer 1431b42731dSPierre Schweitzer Status = RtlAddAccessAllowedAceEx(Dacl, 14433f524c6SPierre Schweitzer ACL_REVISION, 14533f524c6SPierre Schweitzer INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, 14633f524c6SPierre Schweitzer GENERIC_ALL, 14733f524c6SPierre Schweitzer SeWorldSid); 1481b42731dSPierre Schweitzer ASSERT(NT_SUCCESS(Status)); 14933f524c6SPierre Schweitzer } 150c2c66affSColin Finck 151c2c66affSColin Finck /* Attach the DACL to the SD */ 1521b42731dSPierre Schweitzer Status = RtlSetDaclSecurityDescriptor(SecurityDescriptor, TRUE, Dacl, FALSE); 1531b42731dSPierre Schweitzer ASSERT(NT_SUCCESS(Status)); 154c2c66affSColin Finck 15595d303bfSPierre Schweitzer return STATUS_SUCCESS; 156c2c66affSColin Finck } 157c2c66affSColin Finck 15871fefa32STimo Kreuzer INIT_FUNCTION 1598f655f94SPierre Schweitzer VOID 1608f655f94SPierre Schweitzer NTAPI 1618f655f94SPierre Schweitzer ObpFreeDosDevicesProtection(OUT PSECURITY_DESCRIPTOR SecurityDescriptor) 1628f655f94SPierre Schweitzer { 1638f655f94SPierre Schweitzer PACL Dacl; 1648f655f94SPierre Schweitzer NTSTATUS Status; 1658f655f94SPierre Schweitzer BOOLEAN DaclPresent, DaclDefaulted; 1668f655f94SPierre Schweitzer 1678f655f94SPierre Schweitzer Status = RtlGetDaclSecurityDescriptor(SecurityDescriptor, &DaclPresent, &Dacl, &DaclDefaulted); 1688f655f94SPierre Schweitzer ASSERT(NT_SUCCESS(Status)); 1698f655f94SPierre Schweitzer ASSERT(DaclPresent); 1708f655f94SPierre Schweitzer ASSERT(Dacl != NULL); 1718f655f94SPierre Schweitzer ExFreePoolWithTag(Dacl, 'lcaD'); 1728f655f94SPierre Schweitzer } 1738f655f94SPierre Schweitzer 1748f655f94SPierre Schweitzer INIT_FUNCTION 175c2c66affSColin Finck NTSTATUS 176c2c66affSColin Finck NTAPI 177c2c66affSColin Finck ObpCreateDosDevicesDirectory(VOID) 178c2c66affSColin Finck { 179c2c66affSColin Finck OBJECT_ATTRIBUTES ObjectAttributes; 180c2c66affSColin Finck UNICODE_STRING RootName, TargetName, LinkName; 181c2c66affSColin Finck HANDLE Handle, SymHandle; 18295d303bfSPierre Schweitzer SECURITY_DESCRIPTOR DosDevicesSD; 183c2c66affSColin Finck NTSTATUS Status; 184c2c66affSColin Finck 1857898b2eaSPierre Schweitzer /* 1867898b2eaSPierre Schweitzer * Enable LUID mappings only if not explicitely disabled 1877898b2eaSPierre Schweitzer * and if protection mode is set 1887898b2eaSPierre Schweitzer */ 1897898b2eaSPierre Schweitzer if (ObpProtectionMode == 0 || ObpLUIDDeviceMapsDisabled != 0) 1907898b2eaSPierre Schweitzer ObpLUIDDeviceMapsEnabled = 0; 19133604e01SPierre Schweitzer else 19233604e01SPierre Schweitzer ObpLUIDDeviceMapsEnabled = 1; 1937898b2eaSPierre Schweitzer 194c2c66affSColin Finck /* Create a custom security descriptor for the global DosDevices directory */ 19595d303bfSPierre Schweitzer Status = ObpGetDosDevicesProtection(&DosDevicesSD); 196c2c66affSColin Finck if (!NT_SUCCESS(Status)) 197c2c66affSColin Finck return Status; 198c2c66affSColin Finck 199c2c66affSColin Finck /* Create the global DosDevices directory \?? */ 200c2c66affSColin Finck RtlInitUnicodeString(&RootName, L"\\GLOBAL??"); 201c2c66affSColin Finck InitializeObjectAttributes(&ObjectAttributes, 202c2c66affSColin Finck &RootName, 203c2c66affSColin Finck OBJ_PERMANENT, 204c2c66affSColin Finck NULL, 20595d303bfSPierre Schweitzer &DosDevicesSD); 206c2c66affSColin Finck Status = NtCreateDirectoryObject(&Handle, 207c2c66affSColin Finck DIRECTORY_ALL_ACCESS, 208c2c66affSColin Finck &ObjectAttributes); 209fe6c7f05SPierre Schweitzer if (!NT_SUCCESS(Status)) 210fe6c7f05SPierre Schweitzer goto done; 211c2c66affSColin Finck 212c2c66affSColin Finck /* Create the system device map */ 213933dddebSPierre Schweitzer Status = ObSetDeviceMap(NULL, Handle); 214c2c66affSColin Finck if (!NT_SUCCESS(Status)) 215fe6c7f05SPierre Schweitzer goto done; 216c2c66affSColin Finck 217c2c66affSColin Finck /* 218c2c66affSColin Finck * Initialize the \??\GLOBALROOT symbolic link 219c2c66affSColin Finck * pointing to the root directory \ . 220c2c66affSColin Finck */ 221c2c66affSColin Finck RtlInitUnicodeString(&LinkName, L"GLOBALROOT"); 222c2c66affSColin Finck RtlInitUnicodeString(&TargetName, L""); 223c2c66affSColin Finck InitializeObjectAttributes(&ObjectAttributes, 224c2c66affSColin Finck &LinkName, 225c2c66affSColin Finck OBJ_PERMANENT, 226c2c66affSColin Finck Handle, 227fe6c7f05SPierre Schweitzer &DosDevicesSD); 228c2c66affSColin Finck Status = NtCreateSymbolicLinkObject(&SymHandle, 229c2c66affSColin Finck SYMBOLIC_LINK_ALL_ACCESS, 230c2c66affSColin Finck &ObjectAttributes, 231c2c66affSColin Finck &TargetName); 232c2c66affSColin Finck if (NT_SUCCESS(Status)) NtClose(SymHandle); 233c2c66affSColin Finck 234c2c66affSColin Finck /* 235c2c66affSColin Finck * Initialize the \??\Global symbolic link pointing to the global 236c2c66affSColin Finck * DosDevices directory \?? . It is used to access the global \?? 237c2c66affSColin Finck * by user-mode components which, by default, use a per-session 238c2c66affSColin Finck * DosDevices directory. 239c2c66affSColin Finck */ 240c2c66affSColin Finck RtlInitUnicodeString(&LinkName, L"Global"); 241c2c66affSColin Finck InitializeObjectAttributes(&ObjectAttributes, 242c2c66affSColin Finck &LinkName, 243c2c66affSColin Finck OBJ_PERMANENT, 244c2c66affSColin Finck Handle, 245fe6c7f05SPierre Schweitzer &DosDevicesSD); 246c2c66affSColin Finck Status = NtCreateSymbolicLinkObject(&SymHandle, 247c2c66affSColin Finck SYMBOLIC_LINK_ALL_ACCESS, 248c2c66affSColin Finck &ObjectAttributes, 249c2c66affSColin Finck &RootName); 250c2c66affSColin Finck if (NT_SUCCESS(Status)) NtClose(SymHandle); 251c2c66affSColin Finck 252c2c66affSColin Finck /* Close the directory handle */ 253c2c66affSColin Finck NtClose(Handle); 254fe6c7f05SPierre Schweitzer if (!NT_SUCCESS(Status)) 255fe6c7f05SPierre Schweitzer goto done; 256c2c66affSColin Finck 257c2c66affSColin Finck /* 258c2c66affSColin Finck * Initialize the \DosDevices symbolic link pointing to the global 259c2c66affSColin Finck * DosDevices directory \?? , for backward compatibility with 260c2c66affSColin Finck * Windows NT-2000 systems. 261c2c66affSColin Finck */ 262c2c66affSColin Finck RtlCreateUnicodeString(&LinkName, L"\\DosDevices"); 263c2c66affSColin Finck RtlInitUnicodeString(&RootName, (PCWSTR)&ObpDosDevicesShortNameRoot); 264c2c66affSColin Finck InitializeObjectAttributes(&ObjectAttributes, 265c2c66affSColin Finck &LinkName, 266c2c66affSColin Finck OBJ_PERMANENT, 267c2c66affSColin Finck NULL, 268fe6c7f05SPierre Schweitzer &DosDevicesSD); 269c2c66affSColin Finck Status = NtCreateSymbolicLinkObject(&SymHandle, 270c2c66affSColin Finck SYMBOLIC_LINK_ALL_ACCESS, 271c2c66affSColin Finck &ObjectAttributes, 272c2c66affSColin Finck &RootName); 273c2c66affSColin Finck if (NT_SUCCESS(Status)) NtClose(SymHandle); 274c2c66affSColin Finck 275fe6c7f05SPierre Schweitzer done: 2768f655f94SPierre Schweitzer ObpFreeDosDevicesProtection(&DosDevicesSD); 277fe6c7f05SPierre Schweitzer 278c2c66affSColin Finck /* Return status */ 279c2c66affSColin Finck return Status; 280c2c66affSColin Finck } 281c2c66affSColin Finck 282c2c66affSColin Finck /*++ 283c2c66affSColin Finck * @name ObpDeleteNameCheck 284c2c66affSColin Finck * 285c2c66affSColin Finck * The ObpDeleteNameCheck routine checks if a named object should be 286c2c66affSColin Finck * removed from the object directory namespace. 287c2c66affSColin Finck * 288c2c66affSColin Finck * @param Object 289c2c66affSColin Finck * Pointer to the object to check for possible removal. 290c2c66affSColin Finck * 291c2c66affSColin Finck * @return None. 292c2c66affSColin Finck * 293c2c66affSColin Finck * @remarks An object is removed if the following 4 criteria are met: 294c2c66affSColin Finck * 1) The object has 0 handles open 295c2c66affSColin Finck * 2) The object is in the directory namespace and has a name 296c2c66affSColin Finck * 3) The object is not permanent 297c2c66affSColin Finck * 298c2c66affSColin Finck *--*/ 299c2c66affSColin Finck VOID 300c2c66affSColin Finck NTAPI 301c2c66affSColin Finck ObpDeleteNameCheck(IN PVOID Object) 302c2c66affSColin Finck { 303c2c66affSColin Finck POBJECT_HEADER ObjectHeader; 304c2c66affSColin Finck OBP_LOOKUP_CONTEXT Context; 305c2c66affSColin Finck POBJECT_HEADER_NAME_INFO ObjectNameInfo; 306c2c66affSColin Finck POBJECT_TYPE ObjectType; 307c2c66affSColin Finck PVOID Directory = NULL; 308c2c66affSColin Finck 309c2c66affSColin Finck /* Get object structures */ 310c2c66affSColin Finck ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); 311c2c66affSColin Finck ObjectNameInfo = ObpReferenceNameInfo(ObjectHeader); 312c2c66affSColin Finck ObjectType = ObjectHeader->Type; 313c2c66affSColin Finck 314c2c66affSColin Finck /* 315c2c66affSColin Finck * Check if the handle count is 0, if the object is named, 316c2c66affSColin Finck * and if the object isn't a permanent object. 317c2c66affSColin Finck */ 318c2c66affSColin Finck if (!(ObjectHeader->HandleCount) && 319c2c66affSColin Finck (ObjectNameInfo) && 320c2c66affSColin Finck (ObjectNameInfo->Name.Length) && 321c2c66affSColin Finck (ObjectNameInfo->Directory) && 322c2c66affSColin Finck !(ObjectHeader->Flags & OB_FLAG_PERMANENT)) 323c2c66affSColin Finck { 324c2c66affSColin Finck /* Setup a lookup context */ 325c2c66affSColin Finck ObpInitializeLookupContext(&Context); 326c2c66affSColin Finck 327c2c66affSColin Finck /* Lock the directory */ 328c2c66affSColin Finck ObpAcquireDirectoryLockExclusive(ObjectNameInfo->Directory, &Context); 329c2c66affSColin Finck 330c2c66affSColin Finck /* Do the lookup */ 331c2c66affSColin Finck Object = ObpLookupEntryDirectory(ObjectNameInfo->Directory, 332c2c66affSColin Finck &ObjectNameInfo->Name, 333c2c66affSColin Finck 0, 334c2c66affSColin Finck FALSE, 335c2c66affSColin Finck &Context); 336c2c66affSColin Finck if (Object) 337c2c66affSColin Finck { 338c2c66affSColin Finck /* Lock the object */ 339c2c66affSColin Finck ObpAcquireObjectLock(ObjectHeader); 340c2c66affSColin Finck 341c2c66affSColin Finck /* Make sure we can still delete the object */ 342c2c66affSColin Finck if (!(ObjectHeader->HandleCount) && 343c2c66affSColin Finck !(ObjectHeader->Flags & OB_FLAG_PERMANENT)) 344c2c66affSColin Finck { 345c2c66affSColin Finck /* First delete it from the directory */ 346c2c66affSColin Finck ObpDeleteEntryDirectory(&Context); 347c2c66affSColin Finck 348c2c66affSColin Finck /* Check if this is a symbolic link */ 3492c909db2STimo Kreuzer if (ObjectType == ObpSymbolicLinkObjectType) 350c2c66affSColin Finck { 351c2c66affSColin Finck /* Remove internal name */ 352c2c66affSColin Finck ObpDeleteSymbolicLinkName(Object); 353c2c66affSColin Finck } 354c2c66affSColin Finck 355c2c66affSColin Finck /* Check if the kernel exclusive is set */ 356c2c66affSColin Finck ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader); 357c2c66affSColin Finck if ((ObjectNameInfo) && 358c2c66affSColin Finck (ObjectNameInfo->QueryReferences & OB_FLAG_KERNEL_EXCLUSIVE)) 359c2c66affSColin Finck { 360c2c66affSColin Finck /* Remove protection flag */ 361c2c66affSColin Finck InterlockedExchangeAdd((PLONG)&ObjectNameInfo->QueryReferences, 362c2c66affSColin Finck -OB_FLAG_KERNEL_EXCLUSIVE); 363c2c66affSColin Finck } 364c2c66affSColin Finck 365c2c66affSColin Finck /* Get the directory */ 366c2c66affSColin Finck Directory = ObjectNameInfo->Directory; 367c2c66affSColin Finck } 368c2c66affSColin Finck 369c2c66affSColin Finck /* Release the lock */ 370c2c66affSColin Finck ObpReleaseObjectLock(ObjectHeader); 371c2c66affSColin Finck } 372c2c66affSColin Finck 373c2c66affSColin Finck /* Cleanup after lookup */ 374c2c66affSColin Finck ObpReleaseLookupContext(&Context); 375c2c66affSColin Finck 376c2c66affSColin Finck /* Remove another query reference since we added one on top */ 377c2c66affSColin Finck ObpDereferenceNameInfo(ObjectNameInfo); 378c2c66affSColin Finck 379c2c66affSColin Finck /* Check if we were inserted in a directory */ 380c2c66affSColin Finck if (Directory) 381c2c66affSColin Finck { 382c2c66affSColin Finck /* We were, so first remove the extra reference we had added */ 383c2c66affSColin Finck ObpDereferenceNameInfo(ObjectNameInfo); 384c2c66affSColin Finck 385c2c66affSColin Finck /* Now dereference the object as well */ 386c2c66affSColin Finck ObDereferenceObject(Object); 387c2c66affSColin Finck } 388c2c66affSColin Finck } 389c2c66affSColin Finck else 390c2c66affSColin Finck { 391c2c66affSColin Finck /* Remove the reference we added */ 392c2c66affSColin Finck ObpDereferenceNameInfo(ObjectNameInfo); 393c2c66affSColin Finck } 394c2c66affSColin Finck } 395c2c66affSColin Finck 3960f363535SPierre Schweitzer BOOLEAN 3970f363535SPierre Schweitzer NTAPI 3980f363535SPierre Schweitzer ObpIsUnsecureName(IN PUNICODE_STRING ObjectName, 3990f363535SPierre Schweitzer IN BOOLEAN CaseInSensitive) 4000f363535SPierre Schweitzer { 4010f363535SPierre Schweitzer BOOLEAN Unsecure; 4020f363535SPierre Schweitzer PWSTR UnsecureBuffer; 4030f363535SPierre Schweitzer UNICODE_STRING UnsecureName; 4040f363535SPierre Schweitzer 4050f363535SPierre Schweitzer /* No unsecure names known, quit */ 4060f363535SPierre Schweitzer if (ObpUnsecureGlobalNamesBuffer[0] == UNICODE_NULL) 4070f363535SPierre Schweitzer { 4080f363535SPierre Schweitzer return FALSE; 4090f363535SPierre Schweitzer } 4100f363535SPierre Schweitzer 4110f363535SPierre Schweitzer /* By default, we have a secure name */ 4120f363535SPierre Schweitzer Unsecure = FALSE; 4130f363535SPierre Schweitzer /* We will browse the whole string */ 4140f363535SPierre Schweitzer UnsecureBuffer = &ObpUnsecureGlobalNamesBuffer[0]; 4150f363535SPierre Schweitzer while (TRUE) 4160f363535SPierre Schweitzer { 4170f363535SPierre Schweitzer /* Initialize the unicode string */ 4180f363535SPierre Schweitzer RtlInitUnicodeString(&UnsecureName, UnsecureBuffer); 4190f363535SPierre Schweitzer /* We're at the end of the multisz string! */ 4200f363535SPierre Schweitzer if (UnsecureName.Length == 0) 4210f363535SPierre Schweitzer { 4220f363535SPierre Schweitzer break; 4230f363535SPierre Schweitzer } 4240f363535SPierre Schweitzer 4250f363535SPierre Schweitzer /* 4260f363535SPierre Schweitzer * Does the unsecure name prefix the object name? 4270f363535SPierre Schweitzer * If so, that's an unsecure name, and return so 4280f363535SPierre Schweitzer */ 4290f363535SPierre Schweitzer if (RtlPrefixUnicodeString(&UnsecureName, ObjectName, CaseInSensitive)) 4300f363535SPierre Schweitzer { 4310f363535SPierre Schweitzer Unsecure = TRUE; 4320f363535SPierre Schweitzer break; 4330f363535SPierre Schweitzer } 4340f363535SPierre Schweitzer 4350f363535SPierre Schweitzer /* 4360f363535SPierre Schweitzer * Move to the next string. As a reminder, ObpUnsecureGlobalNamesBuffer is 4370f363535SPierre Schweitzer * a multisz, so we move the string next to the current UNICODE_NULL char 4380f363535SPierre Schweitzer */ 4390f363535SPierre Schweitzer UnsecureBuffer = (PWSTR)((ULONG_PTR)UnsecureBuffer + UnsecureName.Length + sizeof(UNICODE_NULL)); 4400f363535SPierre Schweitzer } 4410f363535SPierre Schweitzer 4420f363535SPierre Schweitzer /* Return our findings */ 4430f363535SPierre Schweitzer return Unsecure; 4440f363535SPierre Schweitzer } 4450f363535SPierre Schweitzer 446c2c66affSColin Finck NTSTATUS 447c2c66affSColin Finck NTAPI 448c2c66affSColin Finck ObpLookupObjectName(IN HANDLE RootHandle OPTIONAL, 449c2c66affSColin Finck IN OUT PUNICODE_STRING ObjectName, 450c2c66affSColin Finck IN ULONG Attributes, 451c2c66affSColin Finck IN POBJECT_TYPE ObjectType, 452c2c66affSColin Finck IN KPROCESSOR_MODE AccessMode, 453c2c66affSColin Finck IN OUT PVOID ParseContext, 454c2c66affSColin Finck IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL, 455c2c66affSColin Finck IN PVOID InsertObject OPTIONAL, 456c2c66affSColin Finck IN OUT PACCESS_STATE AccessState, 457c2c66affSColin Finck OUT POBP_LOOKUP_CONTEXT LookupContext, 458c2c66affSColin Finck OUT PVOID *FoundObject) 459c2c66affSColin Finck { 460c2c66affSColin Finck PVOID Object; 461c2c66affSColin Finck POBJECT_HEADER ObjectHeader; 462c2c66affSColin Finck UNICODE_STRING ComponentName, RemainingName; 463c2c66affSColin Finck BOOLEAN Reparse = FALSE, SymLink = FALSE; 464c2c66affSColin Finck POBJECT_DIRECTORY Directory = NULL, ParentDirectory = NULL, RootDirectory; 465c2c66affSColin Finck POBJECT_DIRECTORY ReferencedDirectory = NULL, ReferencedParentDirectory = NULL; 466c2c66affSColin Finck KIRQL CalloutIrql; 467c2c66affSColin Finck OB_PARSE_METHOD ParseRoutine; 468c2c66affSColin Finck NTSTATUS Status; 469c2c66affSColin Finck KPROCESSOR_MODE AccessCheckMode; 470c2c66affSColin Finck PWCHAR NewName; 471c2c66affSColin Finck POBJECT_HEADER_NAME_INFO ObjectNameInfo; 472c2c66affSColin Finck ULONG MaxReparse = 30; 473*f13b6e02SPierre Schweitzer PDEVICE_MAP DeviceMap = NULL; 474*f13b6e02SPierre Schweitzer UNICODE_STRING LocalName; 475c2c66affSColin Finck PAGED_CODE(); 476c2c66affSColin Finck OBTRACE(OB_NAMESPACE_DEBUG, 477c2c66affSColin Finck "%s - Finding Object: %wZ. Expecting: %p\n", 478c2c66affSColin Finck __FUNCTION__, 479c2c66affSColin Finck ObjectName, 480c2c66affSColin Finck InsertObject); 481c2c66affSColin Finck 482c2c66affSColin Finck /* Initialize starting state */ 483c2c66affSColin Finck ObpInitializeLookupContext(LookupContext); 484c2c66affSColin Finck *FoundObject = NULL; 485c2c66affSColin Finck Status = STATUS_SUCCESS; 486c2c66affSColin Finck Object = NULL; 487c2c66affSColin Finck 488c2c66affSColin Finck /* Check if case-insensitivity is checked */ 489c2c66affSColin Finck if (ObpCaseInsensitive) 490c2c66affSColin Finck { 491c2c66affSColin Finck /* Check if the object type requests this */ 492c2c66affSColin Finck if (!(ObjectType) || (ObjectType->TypeInfo.CaseInsensitive)) 493c2c66affSColin Finck { 494c2c66affSColin Finck /* Add the flag to disable case sensitivity */ 495c2c66affSColin Finck Attributes |= OBJ_CASE_INSENSITIVE; 496c2c66affSColin Finck } 497c2c66affSColin Finck } 498c2c66affSColin Finck 499c2c66affSColin Finck /* Check if this is a access checks are being forced */ 500c2c66affSColin Finck AccessCheckMode = (Attributes & OBJ_FORCE_ACCESS_CHECK) ? 501c2c66affSColin Finck UserMode : AccessMode; 502c2c66affSColin Finck 503c2c66affSColin Finck /* Check if we got a Root Directory */ 504c2c66affSColin Finck if (RootHandle) 505c2c66affSColin Finck { 506c2c66affSColin Finck /* We did. Reference it */ 507c2c66affSColin Finck Status = ObReferenceObjectByHandle(RootHandle, 508c2c66affSColin Finck 0, 509c2c66affSColin Finck NULL, 510c2c66affSColin Finck AccessMode, 511c2c66affSColin Finck (PVOID*)&RootDirectory, 512c2c66affSColin Finck NULL); 513c2c66affSColin Finck if (!NT_SUCCESS(Status)) return Status; 514c2c66affSColin Finck 515c2c66affSColin Finck /* Get the header */ 516c2c66affSColin Finck ObjectHeader = OBJECT_TO_OBJECT_HEADER(RootDirectory); 517c2c66affSColin Finck 518c2c66affSColin Finck /* The name cannot start with a separator, unless this is a file */ 519c2c66affSColin Finck if ((ObjectName->Buffer) && 520c2c66affSColin Finck (ObjectName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR) && 521c2c66affSColin Finck (ObjectHeader->Type != IoFileObjectType)) 522c2c66affSColin Finck { 523c2c66affSColin Finck /* The syntax is bad, so fail this request */ 524c2c66affSColin Finck ObDereferenceObject(RootDirectory); 525c2c66affSColin Finck return STATUS_OBJECT_PATH_SYNTAX_BAD; 526c2c66affSColin Finck } 527c2c66affSColin Finck 528c2c66affSColin Finck /* Don't parse a Directory */ 5292c909db2STimo Kreuzer if (ObjectHeader->Type != ObpDirectoryObjectType) 530c2c66affSColin Finck { 531c2c66affSColin Finck /* Make sure the Object Type has a parse routine */ 532c2c66affSColin Finck ParseRoutine = ObjectHeader->Type->TypeInfo.ParseProcedure; 533c2c66affSColin Finck if (!ParseRoutine) 534c2c66affSColin Finck { 535c2c66affSColin Finck /* We can't parse a name if we don't have a parse routine */ 536c2c66affSColin Finck ObDereferenceObject(RootDirectory); 537c2c66affSColin Finck return STATUS_INVALID_HANDLE; 538c2c66affSColin Finck } 539c2c66affSColin Finck 540c2c66affSColin Finck /* Set default parse count */ 541c2c66affSColin Finck MaxReparse = 30; 542c2c66affSColin Finck 543c2c66affSColin Finck /* Now parse */ 544c2c66affSColin Finck while (TRUE) 545c2c66affSColin Finck { 546c2c66affSColin Finck /* Start with the full name */ 547c2c66affSColin Finck RemainingName = *ObjectName; 548c2c66affSColin Finck 549c2c66affSColin Finck /* Call the Parse Procedure */ 550c2c66affSColin Finck ObpCalloutStart(&CalloutIrql); 551c2c66affSColin Finck Status = ParseRoutine(RootDirectory, 552c2c66affSColin Finck ObjectType, 553c2c66affSColin Finck AccessState, 554c2c66affSColin Finck AccessCheckMode, 555c2c66affSColin Finck Attributes, 556c2c66affSColin Finck ObjectName, 557c2c66affSColin Finck &RemainingName, 558c2c66affSColin Finck ParseContext, 559c2c66affSColin Finck SecurityQos, 560c2c66affSColin Finck &Object); 561c2c66affSColin Finck ObpCalloutEnd(CalloutIrql, "Parse", ObjectHeader->Type, Object); 562c2c66affSColin Finck 563c2c66affSColin Finck /* Check for success or failure, so not reparse */ 564c2c66affSColin Finck if ((Status != STATUS_REPARSE) && 565c2c66affSColin Finck (Status != STATUS_REPARSE_OBJECT)) 566c2c66affSColin Finck { 567c2c66affSColin Finck /* Check for failure */ 568c2c66affSColin Finck if (!NT_SUCCESS(Status)) 569c2c66affSColin Finck { 570c2c66affSColin Finck /* Parse routine might not have cleared this, do it */ 571c2c66affSColin Finck Object = NULL; 572c2c66affSColin Finck } 573c2c66affSColin Finck else if (!Object) 574c2c66affSColin Finck { 575c2c66affSColin Finck /* Modify status to reflect failure inside Ob */ 576c2c66affSColin Finck Status = STATUS_OBJECT_NAME_NOT_FOUND; 577c2c66affSColin Finck } 578c2c66affSColin Finck 579c2c66affSColin Finck /* We're done, return the status and object */ 580c2c66affSColin Finck *FoundObject = Object; 581c2c66affSColin Finck ObDereferenceObject(RootDirectory); 582c2c66affSColin Finck return Status; 583c2c66affSColin Finck } 584c2c66affSColin Finck else if ((!ObjectName->Length) || 585c2c66affSColin Finck (!ObjectName->Buffer) || 586c2c66affSColin Finck (ObjectName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)) 587c2c66affSColin Finck { 588c2c66affSColin Finck /* Reparsed to the root directory, so start over */ 589c2c66affSColin Finck ObDereferenceObject(RootDirectory); 590c2c66affSColin Finck RootDirectory = ObpRootDirectoryObject; 591c2c66affSColin Finck 592c2c66affSColin Finck /* Don't use this anymore, since we're starting at root */ 593c2c66affSColin Finck RootHandle = NULL; 594c2c66affSColin Finck goto ParseFromRoot; 595c2c66affSColin Finck } 596c2c66affSColin Finck else if (--MaxReparse) 597c2c66affSColin Finck { 598c2c66affSColin Finck /* Try reparsing again */ 599c2c66affSColin Finck continue; 600c2c66affSColin Finck } 601c2c66affSColin Finck else 602c2c66affSColin Finck { 603c2c66affSColin Finck /* Reparsed too many times */ 604c2c66affSColin Finck ObDereferenceObject(RootDirectory); 605c2c66affSColin Finck 606c2c66affSColin Finck /* Return the object and normalized status */ 607c2c66affSColin Finck *FoundObject = Object; 608c2c66affSColin Finck if (!Object) Status = STATUS_OBJECT_NAME_NOT_FOUND; 609c2c66affSColin Finck return Status; 610c2c66affSColin Finck } 611c2c66affSColin Finck } 612c2c66affSColin Finck } 613c2c66affSColin Finck else if (!(ObjectName->Length) || !(ObjectName->Buffer)) 614c2c66affSColin Finck { 615c2c66affSColin Finck /* Just return the Root Directory if we didn't get a name */ 616c2c66affSColin Finck Status = ObReferenceObjectByPointer(RootDirectory, 617c2c66affSColin Finck 0, 618c2c66affSColin Finck ObjectType, 619c2c66affSColin Finck AccessMode); 620c2c66affSColin Finck if (NT_SUCCESS(Status)) Object = RootDirectory; 621c2c66affSColin Finck 622c2c66affSColin Finck /* Remove the first reference we added and return the object */ 623c2c66affSColin Finck ObDereferenceObject(RootDirectory); 624c2c66affSColin Finck *FoundObject = Object; 625c2c66affSColin Finck return Status; 626c2c66affSColin Finck } 627*f13b6e02SPierre Schweitzer 628*f13b6e02SPierre Schweitzer LocalName = *ObjectName; 629c2c66affSColin Finck } 630c2c66affSColin Finck else 631c2c66affSColin Finck { 632c2c66affSColin Finck /* We did not get a Root Directory, so use the root */ 633c2c66affSColin Finck RootDirectory = ObpRootDirectoryObject; 634c2c66affSColin Finck 635c2c66affSColin Finck /* It must start with a path separator */ 636c2c66affSColin Finck if (!(ObjectName->Length) || 637c2c66affSColin Finck !(ObjectName->Buffer) || 638c2c66affSColin Finck (ObjectName->Buffer[0] != OBJ_NAME_PATH_SEPARATOR)) 639c2c66affSColin Finck { 640c2c66affSColin Finck /* This name is invalid, so fail */ 641c2c66affSColin Finck return STATUS_OBJECT_PATH_SYNTAX_BAD; 642c2c66affSColin Finck } 643c2c66affSColin Finck 644c2c66affSColin Finck /* Check if the name is only the path separator */ 645c2c66affSColin Finck if (ObjectName->Length == sizeof(OBJ_NAME_PATH_SEPARATOR)) 646c2c66affSColin Finck { 647c2c66affSColin Finck /* So the caller only wants the root directory; do we have one? */ 648c2c66affSColin Finck if (!RootDirectory) 649c2c66affSColin Finck { 650c2c66affSColin Finck /* This must be the first time we're creating it... right? */ 651c2c66affSColin Finck if (InsertObject) 652c2c66affSColin Finck { 653c2c66affSColin Finck /* Yes, so return it to ObInsert so that it can create it */ 654c2c66affSColin Finck Status = ObReferenceObjectByPointer(InsertObject, 655c2c66affSColin Finck 0, 656c2c66affSColin Finck ObjectType, 657c2c66affSColin Finck AccessMode); 658c2c66affSColin Finck if (NT_SUCCESS(Status)) *FoundObject = InsertObject; 659c2c66affSColin Finck return Status; 660c2c66affSColin Finck } 661c2c66affSColin Finck else 662c2c66affSColin Finck { 663c2c66affSColin Finck /* This should never really happen */ 664c2c66affSColin Finck ASSERT(FALSE); 665c2c66affSColin Finck return STATUS_INVALID_PARAMETER; 666c2c66affSColin Finck } 667c2c66affSColin Finck } 668c2c66affSColin Finck else 669c2c66affSColin Finck { 670c2c66affSColin Finck /* We do have the root directory, so just return it */ 671c2c66affSColin Finck Status = ObReferenceObjectByPointer(RootDirectory, 672c2c66affSColin Finck 0, 673c2c66affSColin Finck ObjectType, 674c2c66affSColin Finck AccessMode); 675c2c66affSColin Finck if (NT_SUCCESS(Status)) *FoundObject = RootDirectory; 676c2c66affSColin Finck return Status; 677c2c66affSColin Finck } 678c2c66affSColin Finck } 679c2c66affSColin Finck else 680c2c66affSColin Finck { 681c2c66affSColin Finck ParseFromRoot: 682*f13b6e02SPierre Schweitzer LocalName = *ObjectName; 683*f13b6e02SPierre Schweitzer 684*f13b6e02SPierre Schweitzer /* Deference the device map if we already have one */ 685*f13b6e02SPierre Schweitzer if (DeviceMap != NULL) 686*f13b6e02SPierre Schweitzer { 687*f13b6e02SPierre Schweitzer ObfDereferenceDeviceMap(DeviceMap); 688*f13b6e02SPierre Schweitzer DeviceMap = NULL; 689*f13b6e02SPierre Schweitzer } 690c2c66affSColin Finck 691c2c66affSColin Finck /* Check if this is a possible DOS name */ 692c2c66affSColin Finck if (!((ULONG_PTR)(ObjectName->Buffer) & 7)) 693c2c66affSColin Finck { 694c2c66affSColin Finck /* 695c2c66affSColin Finck * This could be one. Does it match the prefix? 696c2c66affSColin Finck * Note that as an optimization, the match is done as 64-bit 697c2c66affSColin Finck * compare since the prefix is "\??\" which is exactly 8 bytes. 698c2c66affSColin Finck * 699c2c66affSColin Finck * In the second branch, we test for "\??" which is also valid. 700c2c66affSColin Finck * This time, we use a 32-bit compare followed by a Unicode 701c2c66affSColin Finck * character compare (16-bit), since the sum is 6 bytes. 702c2c66affSColin Finck */ 703c2c66affSColin Finck if ((ObjectName->Length >= ObpDosDevicesShortName.Length) && 704c2c66affSColin Finck (*(PULONGLONG)(ObjectName->Buffer) == 705c2c66affSColin Finck ObpDosDevicesShortNamePrefix.Alignment.QuadPart)) 706c2c66affSColin Finck { 707*f13b6e02SPierre Schweitzer DeviceMap = ObpReferenceDeviceMap(); 708*f13b6e02SPierre Schweitzer /* We have a local mapping, drop the ?? prefix */ 709*f13b6e02SPierre Schweitzer if (DeviceMap != NULL && DeviceMap->DosDevicesDirectory != NULL) 710*f13b6e02SPierre Schweitzer { 711*f13b6e02SPierre Schweitzer LocalName.Length -= ObpDosDevicesShortName.Length; 712*f13b6e02SPierre Schweitzer LocalName.MaximumLength -= ObpDosDevicesShortName.Length; 713*f13b6e02SPierre Schweitzer LocalName.Buffer += (ObpDosDevicesShortName.Length / sizeof(WCHAR)); 714*f13b6e02SPierre Schweitzer 715*f13b6e02SPierre Schweitzer /* We'll browse that local directory */ 716*f13b6e02SPierre Schweitzer Directory = DeviceMap->DosDevicesDirectory; 717*f13b6e02SPierre Schweitzer } 718c2c66affSColin Finck } 719c2c66affSColin Finck else if ((ObjectName->Length == ObpDosDevicesShortName.Length - 720c2c66affSColin Finck sizeof(WCHAR)) && 721c2c66affSColin Finck (*(PULONG)(ObjectName->Buffer) == 722c2c66affSColin Finck ObpDosDevicesShortNameRoot.Alignment.LowPart) && 723c2c66affSColin Finck (*((PWCHAR)(ObjectName->Buffer) + 2) == 724c2c66affSColin Finck (WCHAR)(ObpDosDevicesShortNameRoot.Alignment.HighPart))) 725c2c66affSColin Finck { 726*f13b6e02SPierre Schweitzer DeviceMap = ObpReferenceDeviceMap(); 727*f13b6e02SPierre Schweitzer 728*f13b6e02SPierre Schweitzer /* Caller is looking for the directory itself */ 729*f13b6e02SPierre Schweitzer if (DeviceMap != NULL && DeviceMap->DosDevicesDirectory != NULL) 730*f13b6e02SPierre Schweitzer { 731*f13b6e02SPierre Schweitzer Status = ObReferenceObjectByPointer(DeviceMap->DosDevicesDirectory, 732*f13b6e02SPierre Schweitzer 0, 733*f13b6e02SPierre Schweitzer ObjectType, 734*f13b6e02SPierre Schweitzer AccessMode); 735*f13b6e02SPierre Schweitzer if (NT_SUCCESS(Status)) 736*f13b6e02SPierre Schweitzer { 737*f13b6e02SPierre Schweitzer *FoundObject = DeviceMap->DosDevicesDirectory; 738*f13b6e02SPierre Schweitzer } 739*f13b6e02SPierre Schweitzer 740*f13b6e02SPierre Schweitzer ObfDereferenceDeviceMap(DeviceMap); 741*f13b6e02SPierre Schweitzer return Status; 742*f13b6e02SPierre Schweitzer } 743c2c66affSColin Finck } 744c2c66affSColin Finck } 745c2c66affSColin Finck } 746c2c66affSColin Finck } 747c2c66affSColin Finck 748c2c66affSColin Finck /* Check if we were reparsing a symbolic link */ 749c2c66affSColin Finck if (!SymLink) 750c2c66affSColin Finck { 751c2c66affSColin Finck /* Allow reparse */ 752c2c66affSColin Finck Reparse = TRUE; 753c2c66affSColin Finck MaxReparse = 30; 754c2c66affSColin Finck } 755c2c66affSColin Finck 756c2c66affSColin Finck /* Reparse */ 757c2c66affSColin Finck while (Reparse && MaxReparse) 758c2c66affSColin Finck { 759c2c66affSColin Finck /* Get the name */ 760*f13b6e02SPierre Schweitzer RemainingName = LocalName; 761c2c66affSColin Finck 762c2c66affSColin Finck /* Disable reparsing again */ 763c2c66affSColin Finck Reparse = FALSE; 764c2c66affSColin Finck 765c2c66affSColin Finck /* Start parse loop */ 766c2c66affSColin Finck while (TRUE) 767c2c66affSColin Finck { 768c2c66affSColin Finck /* Clear object */ 769c2c66affSColin Finck Object = NULL; 770c2c66affSColin Finck 771c2c66affSColin Finck /* Check if the name starts with a path separator */ 772c2c66affSColin Finck if ((RemainingName.Length) && 773c2c66affSColin Finck (RemainingName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR)) 774c2c66affSColin Finck { 775c2c66affSColin Finck /* Skip the path separator */ 776c2c66affSColin Finck RemainingName.Buffer++; 777c2c66affSColin Finck RemainingName.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR); 778c2c66affSColin Finck } 779c2c66affSColin Finck 780c2c66affSColin Finck /* Find the next Part Name */ 781c2c66affSColin Finck ComponentName = RemainingName; 782c2c66affSColin Finck while (RemainingName.Length) 783c2c66affSColin Finck { 784c2c66affSColin Finck /* Break if we found the \ ending */ 785c2c66affSColin Finck if (RemainingName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR) break; 786c2c66affSColin Finck 787c2c66affSColin Finck /* Move on */ 788c2c66affSColin Finck RemainingName.Buffer++; 789c2c66affSColin Finck RemainingName.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR); 790c2c66affSColin Finck } 791c2c66affSColin Finck 792c2c66affSColin Finck /* Get its size and make sure it's valid */ 793c2c66affSColin Finck ComponentName.Length -= RemainingName.Length; 794c2c66affSColin Finck if (!ComponentName.Length) 795c2c66affSColin Finck { 796c2c66affSColin Finck /* Invalid size, fail */ 797c2c66affSColin Finck Status = STATUS_OBJECT_NAME_INVALID; 798c2c66affSColin Finck break; 799c2c66affSColin Finck } 800c2c66affSColin Finck 801c2c66affSColin Finck /* Check if we're in the root */ 802c2c66affSColin Finck if (!Directory) Directory = RootDirectory; 803c2c66affSColin Finck 804c2c66affSColin Finck /* Check if this is a user-mode call that needs to traverse */ 805c2c66affSColin Finck if ((AccessCheckMode != KernelMode) && 806c2c66affSColin Finck !(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE)) 807c2c66affSColin Finck { 808c2c66affSColin Finck /* We shouldn't have referenced a directory yet */ 809c2c66affSColin Finck ASSERT(ReferencedDirectory == NULL); 810c2c66affSColin Finck 811c2c66affSColin Finck /* Reference the directory */ 812c2c66affSColin Finck ObReferenceObject(Directory); 813c2c66affSColin Finck ReferencedDirectory = Directory; 814c2c66affSColin Finck 815c2c66affSColin Finck /* Check if we have a parent directory */ 816c2c66affSColin Finck if (ParentDirectory) 817c2c66affSColin Finck { 818c2c66affSColin Finck /* Check for traverse access */ 819c2c66affSColin Finck if (!ObpCheckTraverseAccess(ParentDirectory, 820c2c66affSColin Finck DIRECTORY_TRAVERSE, 821c2c66affSColin Finck AccessState, 822c2c66affSColin Finck FALSE, 823c2c66affSColin Finck AccessCheckMode, 824c2c66affSColin Finck &Status)) 825c2c66affSColin Finck { 826c2c66affSColin Finck /* We don't have it, fail */ 827c2c66affSColin Finck break; 828c2c66affSColin Finck } 829c2c66affSColin Finck } 830c2c66affSColin Finck } 831c2c66affSColin Finck 832c2c66affSColin Finck /* Check if we don't have a remaining name yet */ 833c2c66affSColin Finck if (!RemainingName.Length) 834c2c66affSColin Finck { 835c2c66affSColin Finck /* Check if we don't have a referenced directory yet */ 836c2c66affSColin Finck if (!ReferencedDirectory) 837c2c66affSColin Finck { 838c2c66affSColin Finck /* Reference it */ 839c2c66affSColin Finck ObReferenceObject(Directory); 840c2c66affSColin Finck ReferencedDirectory = Directory; 841c2c66affSColin Finck } 842c2c66affSColin Finck 843c2c66affSColin Finck /* Check if we are inserting an object */ 844c2c66affSColin Finck if (InsertObject) 845c2c66affSColin Finck { 846c2c66affSColin Finck /* Lock the directory */ 847c2c66affSColin Finck ObpAcquireDirectoryLockExclusive(Directory, LookupContext); 848c2c66affSColin Finck } 849c2c66affSColin Finck } 850c2c66affSColin Finck 851c2c66affSColin Finck /* Do the lookup */ 852c2c66affSColin Finck Object = ObpLookupEntryDirectory(Directory, 853c2c66affSColin Finck &ComponentName, 854c2c66affSColin Finck Attributes, 855c2c66affSColin Finck InsertObject ? FALSE : TRUE, 856c2c66affSColin Finck LookupContext); 857c2c66affSColin Finck if (!Object) 858c2c66affSColin Finck { 859c2c66affSColin Finck /* We didn't find it... do we still have a path? */ 860c2c66affSColin Finck if (RemainingName.Length) 861c2c66affSColin Finck { 862c2c66affSColin Finck /* Then tell the caller the path wasn't found */ 863c2c66affSColin Finck Status = STATUS_OBJECT_PATH_NOT_FOUND; 864c2c66affSColin Finck break; 865c2c66affSColin Finck } 866c2c66affSColin Finck else if (!InsertObject) 867c2c66affSColin Finck { 868c2c66affSColin Finck /* Otherwise, we have a path, but the name isn't valid */ 869c2c66affSColin Finck Status = STATUS_OBJECT_NAME_NOT_FOUND; 870c2c66affSColin Finck break; 871c2c66affSColin Finck } 872c2c66affSColin Finck 873c2c66affSColin Finck /* Check create access for the object */ 874c2c66affSColin Finck if (!ObCheckCreateObjectAccess(Directory, 8752c909db2STimo Kreuzer ObjectType == ObpDirectoryObjectType ? 876c2c66affSColin Finck DIRECTORY_CREATE_SUBDIRECTORY : 877c2c66affSColin Finck DIRECTORY_CREATE_OBJECT, 878c2c66affSColin Finck AccessState, 879c2c66affSColin Finck &ComponentName, 880c2c66affSColin Finck FALSE, 881c2c66affSColin Finck AccessCheckMode, 882c2c66affSColin Finck &Status)) 883c2c66affSColin Finck { 884c2c66affSColin Finck /* We don't have create access, fail */ 885c2c66affSColin Finck break; 886c2c66affSColin Finck } 887c2c66affSColin Finck 888c2c66affSColin Finck /* Get the object header */ 889c2c66affSColin Finck ObjectHeader = OBJECT_TO_OBJECT_HEADER(InsertObject); 890c2c66affSColin Finck 8919c603718SPierre Schweitzer /* 8929c603718SPierre Schweitzer * Deny object creation if: 8939c603718SPierre Schweitzer * That's a section object or a symbolic link 8949c603718SPierre Schweitzer * Which isn't in the same section that root directory 8959c603718SPierre Schweitzer * That doesn't have the SeCreateGlobalPrivilege 8969c603718SPierre Schweitzer * And that is not a known unsecure name 8979c603718SPierre Schweitzer */ 8989c603718SPierre Schweitzer if (RootDirectory->SessionId != -1) 8999c603718SPierre Schweitzer { 9009c603718SPierre Schweitzer if (ObjectHeader->Type == MmSectionObjectType || 9019c603718SPierre Schweitzer ObjectHeader->Type == ObpSymbolicLinkObjectType) 9029c603718SPierre Schweitzer { 9039c603718SPierre Schweitzer if (RootDirectory->SessionId != PsGetCurrentProcessSessionId() && 9049c603718SPierre Schweitzer !SeSinglePrivilegeCheck(SeCreateGlobalPrivilege, AccessCheckMode) && 9059c603718SPierre Schweitzer !ObpIsUnsecureName(&ComponentName, BooleanFlagOn(Attributes, OBJ_CASE_INSENSITIVE))) 9069c603718SPierre Schweitzer { 9079c603718SPierre Schweitzer Status = STATUS_ACCESS_DENIED; 9089c603718SPierre Schweitzer break; 9099c603718SPierre Schweitzer } 9109c603718SPierre Schweitzer } 9119c603718SPierre Schweitzer } 912c2c66affSColin Finck 913c2c66affSColin Finck /* Create Object Name */ 914c2c66affSColin Finck NewName = ExAllocatePoolWithTag(PagedPool, 915c2c66affSColin Finck ComponentName.Length, 916c2c66affSColin Finck OB_NAME_TAG); 917c2c66affSColin Finck if (!(NewName) || 918c2c66affSColin Finck !(ObpInsertEntryDirectory(Directory, 919c2c66affSColin Finck LookupContext, 920c2c66affSColin Finck ObjectHeader))) 921c2c66affSColin Finck { 922c2c66affSColin Finck /* Either couldn't allocate the name, or insert failed */ 923c2c66affSColin Finck if (NewName) ExFreePoolWithTag(NewName, OB_NAME_TAG); 924c2c66affSColin Finck 925c2c66affSColin Finck /* Fail due to memory reasons */ 926c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES; 927c2c66affSColin Finck break; 928c2c66affSColin Finck } 929c2c66affSColin Finck 930c2c66affSColin Finck /* Reference newly to be inserted object */ 931c2c66affSColin Finck ObReferenceObject(InsertObject); 932c2c66affSColin Finck 933c2c66affSColin Finck /* Get the name information */ 934c2c66affSColin Finck ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader); 935c2c66affSColin Finck 936c2c66affSColin Finck /* Reference the directory */ 937c2c66affSColin Finck ObReferenceObject(Directory); 938c2c66affSColin Finck 939c2c66affSColin Finck /* Copy the Name */ 940c2c66affSColin Finck RtlCopyMemory(NewName, 941c2c66affSColin Finck ComponentName.Buffer, 942c2c66affSColin Finck ComponentName.Length); 943c2c66affSColin Finck 944c2c66affSColin Finck /* Check if we had an old name */ 945c2c66affSColin Finck if (ObjectNameInfo->Name.Buffer) 946c2c66affSColin Finck { 947c2c66affSColin Finck /* Free it */ 948c2c66affSColin Finck ExFreePoolWithTag(ObjectNameInfo->Name.Buffer, OB_NAME_TAG); 949c2c66affSColin Finck } 950c2c66affSColin Finck 951c2c66affSColin Finck /* Write new one */ 952c2c66affSColin Finck ObjectNameInfo->Name.Buffer = NewName; 953c2c66affSColin Finck ObjectNameInfo->Name.Length = ComponentName.Length; 954c2c66affSColin Finck ObjectNameInfo->Name.MaximumLength = ComponentName.Length; 955c2c66affSColin Finck 956c2c66affSColin Finck /* Return Status and the Expected Object */ 957c2c66affSColin Finck Status = STATUS_SUCCESS; 958c2c66affSColin Finck Object = InsertObject; 959c2c66affSColin Finck 960c2c66affSColin Finck /* Get out of here */ 961c2c66affSColin Finck break; 962c2c66affSColin Finck } 963c2c66affSColin Finck 964c2c66affSColin Finck ReparseObject: 965c2c66affSColin Finck /* We found it, so now get its header */ 966c2c66affSColin Finck ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); 967c2c66affSColin Finck 968c2c66affSColin Finck /* 969c2c66affSColin Finck * Check for a parse Procedure, but don't bother to parse for an insert 970c2c66affSColin Finck * unless it's a Symbolic Link, in which case we MUST parse 971c2c66affSColin Finck */ 972c2c66affSColin Finck ParseRoutine = ObjectHeader->Type->TypeInfo.ParseProcedure; 973c2c66affSColin Finck if ((ParseRoutine) && 974c2c66affSColin Finck (!(InsertObject) || (ParseRoutine == ObpParseSymbolicLink))) 975c2c66affSColin Finck { 976c2c66affSColin Finck /* Use the Root Directory next time */ 977c2c66affSColin Finck Directory = NULL; 978c2c66affSColin Finck 979c2c66affSColin Finck /* Increment the pointer count */ 980ff7cc6f3STimo Kreuzer InterlockedExchangeAddSizeT(&ObjectHeader->PointerCount, 1); 981c2c66affSColin Finck 982c2c66affSColin Finck /* Cleanup from the first lookup */ 983c2c66affSColin Finck ObpReleaseLookupContext(LookupContext); 984c2c66affSColin Finck 985c2c66affSColin Finck /* Check if we have a referenced directory */ 986c2c66affSColin Finck if (ReferencedDirectory) 987c2c66affSColin Finck { 988c2c66affSColin Finck /* We do, dereference it */ 989c2c66affSColin Finck ObDereferenceObject(ReferencedDirectory); 990c2c66affSColin Finck ReferencedDirectory = NULL; 991c2c66affSColin Finck } 992c2c66affSColin Finck 993c2c66affSColin Finck /* Check if we have a referenced parent directory */ 994c2c66affSColin Finck if (ReferencedParentDirectory) 995c2c66affSColin Finck { 996c2c66affSColin Finck /* We do, dereference it */ 997c2c66affSColin Finck ObDereferenceObject(ReferencedParentDirectory); 998c2c66affSColin Finck ReferencedParentDirectory = NULL; 999c2c66affSColin Finck } 1000c2c66affSColin Finck 1001c2c66affSColin Finck /* Call the Parse Procedure */ 1002c2c66affSColin Finck ObpCalloutStart(&CalloutIrql); 1003c2c66affSColin Finck Status = ParseRoutine(Object, 1004c2c66affSColin Finck ObjectType, 1005c2c66affSColin Finck AccessState, 1006c2c66affSColin Finck AccessCheckMode, 1007c2c66affSColin Finck Attributes, 1008c2c66affSColin Finck ObjectName, 1009c2c66affSColin Finck &RemainingName, 1010c2c66affSColin Finck ParseContext, 1011c2c66affSColin Finck SecurityQos, 1012c2c66affSColin Finck &Object); 1013c2c66affSColin Finck ObpCalloutEnd(CalloutIrql, "Parse", ObjectHeader->Type, Object); 1014c2c66affSColin Finck 1015c2c66affSColin Finck /* Remove our extra reference */ 1016c2c66affSColin Finck ObDereferenceObject(&ObjectHeader->Body); 1017c2c66affSColin Finck 1018c2c66affSColin Finck /* Check if we have to reparse */ 1019c2c66affSColin Finck if ((Status == STATUS_REPARSE) || 1020c2c66affSColin Finck (Status == STATUS_REPARSE_OBJECT)) 1021c2c66affSColin Finck { 1022c2c66affSColin Finck /* Reparse again */ 1023c2c66affSColin Finck Reparse = TRUE; 1024c2c66affSColin Finck --MaxReparse; 1025c2c66affSColin Finck if (MaxReparse == 0) 1026c2c66affSColin Finck { 1027c2c66affSColin Finck Object = NULL; 1028c2c66affSColin Finck break; 1029c2c66affSColin Finck } 1030c2c66affSColin Finck 1031c2c66affSColin Finck /* Start over from root if we got sent back there */ 1032c2c66affSColin Finck if ((Status == STATUS_REPARSE_OBJECT) || 1033c2c66affSColin Finck (ObjectName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)) 1034c2c66affSColin Finck { 1035c2c66affSColin Finck /* Check if we got a root directory */ 1036c2c66affSColin Finck if (RootHandle) 1037c2c66affSColin Finck { 1038c2c66affSColin Finck /* Stop using it, because we have a new directory now */ 1039c2c66affSColin Finck ObDereferenceObject(RootDirectory); 1040c2c66affSColin Finck RootHandle = NULL; 1041c2c66affSColin Finck } 1042c2c66affSColin Finck 1043c2c66affSColin Finck /* Start at Root */ 1044c2c66affSColin Finck ParentDirectory = NULL; 1045c2c66affSColin Finck RootDirectory = ObpRootDirectoryObject; 1046c2c66affSColin Finck 1047c2c66affSColin Finck /* Check for reparse status */ 1048c2c66affSColin Finck if (Status == STATUS_REPARSE_OBJECT) 1049c2c66affSColin Finck { 1050c2c66affSColin Finck /* Don't reparse again */ 1051c2c66affSColin Finck Reparse = FALSE; 1052c2c66affSColin Finck 1053c2c66affSColin Finck /* Did we actually get an object to which to reparse? */ 1054c2c66affSColin Finck if (!Object) 1055c2c66affSColin Finck { 1056c2c66affSColin Finck /* We didn't, so set a failure status */ 1057c2c66affSColin Finck Status = STATUS_OBJECT_NAME_NOT_FOUND; 1058c2c66affSColin Finck } 1059c2c66affSColin Finck else 1060c2c66affSColin Finck { 1061c2c66affSColin Finck /* We did, so we're free to parse the new object */ 1062c2c66affSColin Finck goto ReparseObject; 1063c2c66affSColin Finck } 1064c2c66affSColin Finck } 1065c2c66affSColin Finck else 1066c2c66affSColin Finck { 1067c2c66affSColin Finck /* This is a symbolic link */ 1068c2c66affSColin Finck SymLink = TRUE; 1069c2c66affSColin Finck goto ParseFromRoot; 1070c2c66affSColin Finck } 1071c2c66affSColin Finck } 1072c2c66affSColin Finck else if (RootDirectory == ObpRootDirectoryObject) 1073c2c66affSColin Finck { 1074c2c66affSColin Finck /* We got STATUS_REPARSE but are at the Root Directory */ 1075c2c66affSColin Finck Object = NULL; 1076c2c66affSColin Finck Status = STATUS_OBJECT_NAME_NOT_FOUND; 1077c2c66affSColin Finck Reparse = FALSE; 1078c2c66affSColin Finck } 1079c2c66affSColin Finck } 1080c2c66affSColin Finck else if (!NT_SUCCESS(Status)) 1081c2c66affSColin Finck { 1082c2c66affSColin Finck /* Total failure */ 1083c2c66affSColin Finck Object = NULL; 1084c2c66affSColin Finck } 1085c2c66affSColin Finck else if (!Object) 1086c2c66affSColin Finck { 1087c2c66affSColin Finck /* We didn't reparse but we didn't find the Object Either */ 1088c2c66affSColin Finck Status = STATUS_OBJECT_NAME_NOT_FOUND; 1089c2c66affSColin Finck } 1090c2c66affSColin Finck 1091c2c66affSColin Finck /* Break out of the loop */ 1092c2c66affSColin Finck break; 1093c2c66affSColin Finck } 1094c2c66affSColin Finck else 1095c2c66affSColin Finck { 1096c2c66affSColin Finck /* No parse routine...do we still have a remaining name? */ 1097c2c66affSColin Finck if (!RemainingName.Length) 1098c2c66affSColin Finck { 1099c2c66affSColin Finck /* Are we creating an object? */ 1100c2c66affSColin Finck if (!InsertObject) 1101c2c66affSColin Finck { 1102c2c66affSColin Finck /* Check if this is a user-mode call that needs to traverse */ 1103c2c66affSColin Finck if ((AccessCheckMode != KernelMode) && 1104c2c66affSColin Finck !(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE)) 1105c2c66affSColin Finck { 1106c2c66affSColin Finck /* Check if we can get it */ 1107c2c66affSColin Finck if (!ObpCheckTraverseAccess(Directory, 1108c2c66affSColin Finck DIRECTORY_TRAVERSE, 1109c2c66affSColin Finck AccessState, 1110c2c66affSColin Finck FALSE, 1111c2c66affSColin Finck AccessCheckMode, 1112c2c66affSColin Finck &Status)) 1113c2c66affSColin Finck { 1114c2c66affSColin Finck /* We don't have access, fail */ 1115c2c66affSColin Finck Object = NULL; 1116c2c66affSColin Finck break; 1117c2c66affSColin Finck } 1118c2c66affSColin Finck } 1119c2c66affSColin Finck 1120c2c66affSColin Finck /* Reference the Object */ 1121c2c66affSColin Finck Status = ObReferenceObjectByPointer(Object, 1122c2c66affSColin Finck 0, 1123c2c66affSColin Finck ObjectType, 1124c2c66affSColin Finck AccessMode); 1125c2c66affSColin Finck if (!NT_SUCCESS(Status)) Object = NULL; 1126c2c66affSColin Finck } 1127c2c66affSColin Finck 1128c2c66affSColin Finck /* And get out of the reparse loop */ 1129c2c66affSColin Finck break; 1130c2c66affSColin Finck } 1131c2c66affSColin Finck else 1132c2c66affSColin Finck { 1133c2c66affSColin Finck /* We still have a name; check if this is a directory object */ 11342c909db2STimo Kreuzer if (ObjectHeader->Type == ObpDirectoryObjectType) 1135c2c66affSColin Finck { 1136c2c66affSColin Finck /* Check if we have a referenced parent directory */ 1137c2c66affSColin Finck if (ReferencedParentDirectory) 1138c2c66affSColin Finck { 1139c2c66affSColin Finck /* Dereference it */ 1140c2c66affSColin Finck ObDereferenceObject(ReferencedParentDirectory); 1141c2c66affSColin Finck } 1142c2c66affSColin Finck 1143c2c66affSColin Finck /* Restart the lookup from this directory */ 1144c2c66affSColin Finck ReferencedParentDirectory = ReferencedDirectory; 1145c2c66affSColin Finck ParentDirectory = Directory; 1146c2c66affSColin Finck Directory = Object; 1147c2c66affSColin Finck ReferencedDirectory = NULL; 1148c2c66affSColin Finck } 1149c2c66affSColin Finck else 1150c2c66affSColin Finck { 1151c2c66affSColin Finck /* We still have a name, but no parse routine for it */ 1152c2c66affSColin Finck Status = STATUS_OBJECT_TYPE_MISMATCH; 1153c2c66affSColin Finck Object = NULL; 1154c2c66affSColin Finck break; 1155c2c66affSColin Finck } 1156c2c66affSColin Finck } 1157c2c66affSColin Finck } 1158c2c66affSColin Finck } 1159c2c66affSColin Finck } 1160c2c66affSColin Finck 1161c2c66affSColin Finck /* Check if we failed */ 1162c2c66affSColin Finck if (!NT_SUCCESS(Status)) 1163c2c66affSColin Finck { 1164c2c66affSColin Finck /* Cleanup after lookup */ 1165c2c66affSColin Finck ObpReleaseLookupContext(LookupContext); 1166c2c66affSColin Finck } 1167c2c66affSColin Finck 1168c2c66affSColin Finck /* Check if we have a device map and dereference it if so */ 1169*f13b6e02SPierre Schweitzer if (DeviceMap) ObfDereferenceDeviceMap(DeviceMap); 1170c2c66affSColin Finck 1171c2c66affSColin Finck /* Check if we have a referenced directory and dereference it if so */ 1172c2c66affSColin Finck if (ReferencedDirectory) ObDereferenceObject(ReferencedDirectory); 1173c2c66affSColin Finck 1174c2c66affSColin Finck /* Check if we have a referenced parent directory */ 1175c2c66affSColin Finck if (ReferencedParentDirectory) 1176c2c66affSColin Finck { 1177c2c66affSColin Finck /* We do, dereference it */ 1178c2c66affSColin Finck ObDereferenceObject(ReferencedParentDirectory); 1179c2c66affSColin Finck } 1180c2c66affSColin Finck 1181c2c66affSColin Finck /* Set the found object and check if we got one */ 1182c2c66affSColin Finck *FoundObject = Object; 1183c2c66affSColin Finck if (!Object) 1184c2c66affSColin Finck { 1185c2c66affSColin Finck /* Nothing was found. Did we reparse or get success? */ 1186c2c66affSColin Finck if ((Status == STATUS_REPARSE) || (NT_SUCCESS(Status))) 1187c2c66affSColin Finck { 1188c2c66affSColin Finck /* Set correct failure */ 1189c2c66affSColin Finck Status = STATUS_OBJECT_NAME_NOT_FOUND; 1190c2c66affSColin Finck } 1191c2c66affSColin Finck } 1192c2c66affSColin Finck 1193c2c66affSColin Finck /* Check if we had a root directory */ 1194c2c66affSColin Finck if (RootHandle) ObDereferenceObject(RootDirectory); 1195c2c66affSColin Finck 1196c2c66affSColin Finck /* Return status to caller */ 1197c2c66affSColin Finck OBTRACE(OB_NAMESPACE_DEBUG, 1198c2c66affSColin Finck "%s - Found Object: %p. Expected: %p\n", 1199c2c66affSColin Finck __FUNCTION__, 1200c2c66affSColin Finck *FoundObject, 1201c2c66affSColin Finck InsertObject); 1202c2c66affSColin Finck return Status; 1203c2c66affSColin Finck } 1204c2c66affSColin Finck 1205c2c66affSColin Finck /* PUBLIC FUNCTIONS *********************************************************/ 1206c2c66affSColin Finck 1207c2c66affSColin Finck NTSTATUS 1208c2c66affSColin Finck NTAPI 1209c2c66affSColin Finck ObQueryNameString(IN PVOID Object, 1210c2c66affSColin Finck OUT POBJECT_NAME_INFORMATION ObjectNameInfo, 1211c2c66affSColin Finck IN ULONG Length, 1212c2c66affSColin Finck OUT PULONG ReturnLength) 1213c2c66affSColin Finck { 1214c2c66affSColin Finck POBJECT_HEADER_NAME_INFO LocalInfo; 1215c2c66affSColin Finck POBJECT_HEADER ObjectHeader; 1216c2c66affSColin Finck POBJECT_DIRECTORY ParentDirectory; 1217c2c66affSColin Finck ULONG NameSize; 1218c2c66affSColin Finck PWCH ObjectName; 1219c2c66affSColin Finck BOOLEAN ObjectIsNamed; 1220c2c66affSColin Finck NTSTATUS Status = STATUS_SUCCESS; 1221c2c66affSColin Finck 1222c2c66affSColin Finck /* Get the Kernel Meta-Structures */ 1223c2c66affSColin Finck ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); 1224c2c66affSColin Finck LocalInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader); 1225c2c66affSColin Finck 1226c2c66affSColin Finck /* Check if a Query Name Procedure is available */ 1227c2c66affSColin Finck if (ObjectHeader->Type->TypeInfo.QueryNameProcedure) 1228c2c66affSColin Finck { 1229c2c66affSColin Finck /* Call the procedure inside SEH */ 1230c2c66affSColin Finck ObjectIsNamed = ((LocalInfo) && (LocalInfo->Name.Length > 0)); 1231c2c66affSColin Finck 1232c2c66affSColin Finck _SEH2_TRY 1233c2c66affSColin Finck { 1234c2c66affSColin Finck Status = ObjectHeader->Type->TypeInfo.QueryNameProcedure(Object, 1235c2c66affSColin Finck ObjectIsNamed, 1236c2c66affSColin Finck ObjectNameInfo, 1237c2c66affSColin Finck Length, 1238c2c66affSColin Finck ReturnLength, 1239c2c66affSColin Finck KernelMode); 1240c2c66affSColin Finck } 1241c2c66affSColin Finck _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1242c2c66affSColin Finck { 1243c2c66affSColin Finck /* Return the exception code */ 1244c2c66affSColin Finck Status = _SEH2_GetExceptionCode(); 1245c2c66affSColin Finck } 1246c2c66affSColin Finck _SEH2_END; 1247c2c66affSColin Finck 1248c2c66affSColin Finck return Status; 1249c2c66affSColin Finck } 1250c2c66affSColin Finck 1251c2c66affSColin Finck /* Check if the object doesn't even have a name */ 1252c2c66affSColin Finck if (!(LocalInfo) || !(LocalInfo->Name.Buffer)) 1253c2c66affSColin Finck { 1254c2c66affSColin Finck Status = STATUS_SUCCESS; 1255c2c66affSColin Finck 1256c2c66affSColin Finck _SEH2_TRY 1257c2c66affSColin Finck { 1258c2c66affSColin Finck /* We're returning the name structure */ 1259c2c66affSColin Finck *ReturnLength = sizeof(OBJECT_NAME_INFORMATION); 1260c2c66affSColin Finck 1261c2c66affSColin Finck /* Check if we were given enough space */ 1262c2c66affSColin Finck if (*ReturnLength > Length) 1263c2c66affSColin Finck { 1264c2c66affSColin Finck Status = STATUS_INFO_LENGTH_MISMATCH; 1265c2c66affSColin Finck } 1266c2c66affSColin Finck else 1267c2c66affSColin Finck { 1268c2c66affSColin Finck /* Return an empty buffer */ 1269c2c66affSColin Finck RtlInitEmptyUnicodeString(&ObjectNameInfo->Name, NULL, 0); 1270c2c66affSColin Finck } 1271c2c66affSColin Finck } 1272c2c66affSColin Finck _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1273c2c66affSColin Finck { 1274c2c66affSColin Finck /* Return the exception code */ 1275c2c66affSColin Finck Status = _SEH2_GetExceptionCode(); 1276c2c66affSColin Finck } 1277c2c66affSColin Finck _SEH2_END; 1278c2c66affSColin Finck 1279c2c66affSColin Finck return Status; 1280c2c66affSColin Finck } 1281c2c66affSColin Finck 1282c2c66affSColin Finck /* 1283c2c66affSColin Finck * Find the size needed for the name. We won't do 1284c2c66affSColin Finck * this during the Name Creation loop because we want 1285c2c66affSColin Finck * to let the caller know that the buffer isn't big 1286c2c66affSColin Finck * enough right at the beginning, not work our way through 1287c2c66affSColin Finck * and find out at the end 1288c2c66affSColin Finck */ 1289c2c66affSColin Finck _SEH2_TRY 1290c2c66affSColin Finck { 1291c2c66affSColin Finck if (Object == ObpRootDirectoryObject) 1292c2c66affSColin Finck { 1293c2c66affSColin Finck /* Size of the '\' string */ 1294c2c66affSColin Finck NameSize = sizeof(OBJ_NAME_PATH_SEPARATOR); 1295c2c66affSColin Finck } 1296c2c66affSColin Finck else 1297c2c66affSColin Finck { 1298c2c66affSColin Finck /* Get the Object Directory and add name of Object */ 1299c2c66affSColin Finck ParentDirectory = LocalInfo->Directory; 1300c2c66affSColin Finck NameSize = sizeof(OBJ_NAME_PATH_SEPARATOR) + LocalInfo->Name.Length; 1301c2c66affSColin Finck 1302c2c66affSColin Finck /* Loop inside the directory to get the top-most one (meaning root) */ 1303c2c66affSColin Finck while ((ParentDirectory != ObpRootDirectoryObject) && (ParentDirectory)) 1304c2c66affSColin Finck { 1305c2c66affSColin Finck /* Get the Name Information */ 1306c2c66affSColin Finck LocalInfo = OBJECT_HEADER_TO_NAME_INFO( 1307c2c66affSColin Finck OBJECT_TO_OBJECT_HEADER(ParentDirectory)); 1308c2c66affSColin Finck 1309c2c66affSColin Finck /* Add the size of the Directory Name */ 1310c2c66affSColin Finck if (LocalInfo && LocalInfo->Directory) 1311c2c66affSColin Finck { 1312c2c66affSColin Finck /* Size of the '\' string + Directory Name */ 1313c2c66affSColin Finck NameSize += sizeof(OBJ_NAME_PATH_SEPARATOR) + 1314c2c66affSColin Finck LocalInfo->Name.Length; 1315c2c66affSColin Finck 1316c2c66affSColin Finck /* Move to next parent Directory */ 1317c2c66affSColin Finck ParentDirectory = LocalInfo->Directory; 1318c2c66affSColin Finck } 1319c2c66affSColin Finck else 1320c2c66affSColin Finck { 1321c2c66affSColin Finck /* Directory with no name. We append "...\" */ 1322c2c66affSColin Finck NameSize += sizeof(L"...") + sizeof(OBJ_NAME_PATH_SEPARATOR); 1323c2c66affSColin Finck break; 1324c2c66affSColin Finck } 1325c2c66affSColin Finck } 1326c2c66affSColin Finck } 1327c2c66affSColin Finck 1328c2c66affSColin Finck /* Finally, add the name of the structure and the null char */ 1329c2c66affSColin Finck *ReturnLength = NameSize + 1330c2c66affSColin Finck sizeof(OBJECT_NAME_INFORMATION) + 1331c2c66affSColin Finck sizeof(UNICODE_NULL); 1332c2c66affSColin Finck 1333c2c66affSColin Finck /* Check if we were given enough space */ 1334c2c66affSColin Finck if (*ReturnLength > Length) _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH); 1335c2c66affSColin Finck 1336c2c66affSColin Finck /* 1337c2c66affSColin Finck * Now we will actually create the name. We work backwards because 1338c2c66affSColin Finck * it's easier to start off from the Name we have and walk up the 1339c2c66affSColin Finck * parent directories. We use the same logic as Name Length calculation. 1340c2c66affSColin Finck */ 1341c2c66affSColin Finck LocalInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader); 1342c2c66affSColin Finck ObjectName = (PWCH)((ULONG_PTR)ObjectNameInfo + *ReturnLength); 1343c2c66affSColin Finck *--ObjectName = UNICODE_NULL; 1344c2c66affSColin Finck 1345c2c66affSColin Finck /* Check if the object is actually the Root directory */ 1346c2c66affSColin Finck if (Object == ObpRootDirectoryObject) 1347c2c66affSColin Finck { 1348c2c66affSColin Finck /* This is already the Root Directory, return "\\" */ 1349c2c66affSColin Finck *--ObjectName = OBJ_NAME_PATH_SEPARATOR; 1350c2c66affSColin Finck ObjectNameInfo->Name.Length = (USHORT)NameSize; 1351c2c66affSColin Finck ObjectNameInfo->Name.MaximumLength = (USHORT)(NameSize + 1352c2c66affSColin Finck sizeof(UNICODE_NULL)); 1353c2c66affSColin Finck ObjectNameInfo->Name.Buffer = ObjectName; 1354c2c66affSColin Finck Status = STATUS_SUCCESS; 1355c2c66affSColin Finck } 1356c2c66affSColin Finck else 1357c2c66affSColin Finck { 1358c2c66affSColin Finck /* Start by adding the Object's Name */ 1359c2c66affSColin Finck ObjectName = (PWCH)((ULONG_PTR)ObjectName - 1360c2c66affSColin Finck LocalInfo->Name.Length); 1361c2c66affSColin Finck RtlCopyMemory(ObjectName, 1362c2c66affSColin Finck LocalInfo->Name.Buffer, 1363c2c66affSColin Finck LocalInfo->Name.Length); 1364c2c66affSColin Finck 1365c2c66affSColin Finck /* Now parse the Parent directories until we reach the top */ 1366c2c66affSColin Finck ParentDirectory = LocalInfo->Directory; 1367c2c66affSColin Finck while ((ParentDirectory != ObpRootDirectoryObject) && (ParentDirectory)) 1368c2c66affSColin Finck { 1369c2c66affSColin Finck /* Get the name information */ 1370c2c66affSColin Finck LocalInfo = OBJECT_HEADER_TO_NAME_INFO( 1371c2c66affSColin Finck OBJECT_TO_OBJECT_HEADER(ParentDirectory)); 1372c2c66affSColin Finck 1373c2c66affSColin Finck /* Add the "\" */ 1374c2c66affSColin Finck *(--ObjectName) = OBJ_NAME_PATH_SEPARATOR; 1375c2c66affSColin Finck 1376c2c66affSColin Finck /* Add the Parent Directory's Name */ 1377c2c66affSColin Finck if (LocalInfo && LocalInfo->Name.Buffer) 1378c2c66affSColin Finck { 1379c2c66affSColin Finck /* Add the name */ 1380c2c66affSColin Finck ObjectName = (PWCH)((ULONG_PTR)ObjectName - 1381c2c66affSColin Finck LocalInfo->Name.Length); 1382c2c66affSColin Finck RtlCopyMemory(ObjectName, 1383c2c66affSColin Finck LocalInfo->Name.Buffer, 1384c2c66affSColin Finck LocalInfo->Name.Length); 1385c2c66affSColin Finck 1386c2c66affSColin Finck /* Move to next parent */ 1387c2c66affSColin Finck ParentDirectory = LocalInfo->Directory; 1388c2c66affSColin Finck } 1389c2c66affSColin Finck else 1390c2c66affSColin Finck { 1391c2c66affSColin Finck /* Directory without a name, we add "..." */ 1392c2c66affSColin Finck ObjectName = (PWCH)((ULONG_PTR)ObjectName - 1393c2c66affSColin Finck sizeof(L"...") + 1394c2c66affSColin Finck sizeof(UNICODE_NULL)); 1395c2c66affSColin Finck RtlCopyMemory(ObjectName, L"...", sizeof(L"...")); 1396c2c66affSColin Finck break; 1397c2c66affSColin Finck } 1398c2c66affSColin Finck } 1399c2c66affSColin Finck 1400c2c66affSColin Finck /* Add Root Directory Name */ 1401c2c66affSColin Finck *(--ObjectName) = OBJ_NAME_PATH_SEPARATOR; 1402c2c66affSColin Finck ObjectNameInfo->Name.Length = (USHORT)NameSize; 1403c2c66affSColin Finck ObjectNameInfo->Name.MaximumLength = 1404c2c66affSColin Finck (USHORT)(NameSize + sizeof(UNICODE_NULL)); 1405c2c66affSColin Finck ObjectNameInfo->Name.Buffer = ObjectName; 1406c2c66affSColin Finck } 1407c2c66affSColin Finck } 1408c2c66affSColin Finck _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1409c2c66affSColin Finck { 1410c2c66affSColin Finck /* Return the exception code */ 1411c2c66affSColin Finck Status = _SEH2_GetExceptionCode(); 1412c2c66affSColin Finck } 1413c2c66affSColin Finck _SEH2_END; 1414c2c66affSColin Finck 1415c2c66affSColin Finck /* Return success */ 1416c2c66affSColin Finck return Status; 1417c2c66affSColin Finck } 1418c2c66affSColin Finck 1419c2c66affSColin Finck /* EOF */ 1420