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