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 RtlCreateUnicodeString(&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 */ 325 ObpInitializeLookupContext(&Context); 326 327 /* Lock the directory */ 328 ObpAcquireDirectoryLockExclusive(ObjectNameInfo->Directory, &Context); 329 330 /* Do the lookup */ 331 Object = ObpLookupEntryDirectory(ObjectNameInfo->Directory, 332 &ObjectNameInfo->Name, 333 0, 334 FALSE, 335 &Context); 336 if (Object) 337 { 338 /* Lock the object */ 339 ObpAcquireObjectLock(ObjectHeader); 340 341 /* Make sure we can still delete the object */ 342 if (!(ObjectHeader->HandleCount) && 343 !(ObjectHeader->Flags & OB_FLAG_PERMANENT)) 344 { 345 /* First delete it from the directory */ 346 ObpDeleteEntryDirectory(&Context); 347 348 /* Check if this is a symbolic link */ 349 if (ObjectType == ObpSymbolicLinkObjectType) 350 { 351 /* Remove internal name */ 352 ObpDeleteSymbolicLinkName(Object); 353 } 354 355 /* Check if the kernel exclusive is set */ 356 ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader); 357 if ((ObjectNameInfo) && 358 (ObjectNameInfo->QueryReferences & OB_FLAG_KERNEL_EXCLUSIVE)) 359 { 360 /* Remove protection flag */ 361 InterlockedExchangeAdd((PLONG)&ObjectNameInfo->QueryReferences, 362 -OB_FLAG_KERNEL_EXCLUSIVE); 363 } 364 365 /* Get the directory */ 366 Directory = ObjectNameInfo->Directory; 367 } 368 369 /* Release the lock */ 370 ObpReleaseObjectLock(ObjectHeader); 371 } 372 373 /* Cleanup after lookup */ 374 ObpReleaseLookupContext(&Context); 375 376 /* Remove another query reference since we added one on top */ 377 ObpDereferenceNameInfo(ObjectNameInfo); 378 379 /* Check if we were inserted in a directory */ 380 if (Directory) 381 { 382 /* We were, so first remove the extra reference we had added */ 383 ObpDereferenceNameInfo(ObjectNameInfo); 384 385 /* Now dereference the object as well */ 386 ObDereferenceObject(Object); 387 } 388 } 389 else 390 { 391 /* Remove the reference we added */ 392 ObpDereferenceNameInfo(ObjectNameInfo); 393 } 394 } 395 396 BOOLEAN 397 NTAPI 398 ObpIsUnsecureName(IN PUNICODE_STRING ObjectName, 399 IN BOOLEAN CaseInSensitive) 400 { 401 BOOLEAN Unsecure; 402 PWSTR UnsecureBuffer; 403 UNICODE_STRING UnsecureName; 404 405 /* No unsecure names known, quit */ 406 if (ObpUnsecureGlobalNamesBuffer[0] == UNICODE_NULL) 407 { 408 return FALSE; 409 } 410 411 /* By default, we have a secure name */ 412 Unsecure = FALSE; 413 /* We will browse the whole string */ 414 UnsecureBuffer = &ObpUnsecureGlobalNamesBuffer[0]; 415 while (TRUE) 416 { 417 /* Initialize the unicode string */ 418 RtlInitUnicodeString(&UnsecureName, UnsecureBuffer); 419 /* We're at the end of the multisz string! */ 420 if (UnsecureName.Length == 0) 421 { 422 break; 423 } 424 425 /* 426 * Does the unsecure name prefix the object name? 427 * If so, that's an unsecure name, and return so 428 */ 429 if (RtlPrefixUnicodeString(&UnsecureName, ObjectName, CaseInSensitive)) 430 { 431 Unsecure = TRUE; 432 break; 433 } 434 435 /* 436 * Move to the next string. As a reminder, ObpUnsecureGlobalNamesBuffer is 437 * a multisz, so we move the string next to the current UNICODE_NULL char 438 */ 439 UnsecureBuffer = (PWSTR)((ULONG_PTR)UnsecureBuffer + UnsecureName.Length + sizeof(UNICODE_NULL)); 440 } 441 442 /* Return our findings */ 443 return Unsecure; 444 } 445 446 NTSTATUS 447 NTAPI 448 ObpLookupObjectName(IN HANDLE RootHandle OPTIONAL, 449 IN OUT PUNICODE_STRING ObjectName, 450 IN ULONG Attributes, 451 IN POBJECT_TYPE ObjectType, 452 IN KPROCESSOR_MODE AccessMode, 453 IN OUT PVOID ParseContext, 454 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL, 455 IN PVOID InsertObject OPTIONAL, 456 IN OUT PACCESS_STATE AccessState, 457 OUT POBP_LOOKUP_CONTEXT LookupContext, 458 OUT PVOID *FoundObject) 459 { 460 PVOID Object; 461 POBJECT_HEADER ObjectHeader; 462 UNICODE_STRING ComponentName, RemainingName; 463 BOOLEAN Reparse = FALSE, SymLink = FALSE; 464 POBJECT_DIRECTORY Directory = NULL, ParentDirectory = NULL, RootDirectory; 465 POBJECT_DIRECTORY ReferencedDirectory = NULL, ReferencedParentDirectory = NULL; 466 KIRQL CalloutIrql; 467 OB_PARSE_METHOD ParseRoutine; 468 NTSTATUS Status; 469 KPROCESSOR_MODE AccessCheckMode; 470 PWCHAR NewName; 471 POBJECT_HEADER_NAME_INFO ObjectNameInfo; 472 ULONG MaxReparse = 30; 473 PDEVICE_MAP DeviceMap = NULL; 474 UNICODE_STRING LocalName; 475 PAGED_CODE(); 476 OBTRACE(OB_NAMESPACE_DEBUG, 477 "%s - Finding Object: %wZ. Expecting: %p\n", 478 __FUNCTION__, 479 ObjectName, 480 InsertObject); 481 482 /* Initialize starting state */ 483 ObpInitializeLookupContext(LookupContext); 484 *FoundObject = NULL; 485 Status = STATUS_SUCCESS; 486 Object = NULL; 487 488 /* Check if case-insensitivity is checked */ 489 if (ObpCaseInsensitive) 490 { 491 /* Check if the object type requests this */ 492 if (!(ObjectType) || (ObjectType->TypeInfo.CaseInsensitive)) 493 { 494 /* Add the flag to disable case sensitivity */ 495 Attributes |= OBJ_CASE_INSENSITIVE; 496 } 497 } 498 499 /* Check if this is a access checks are being forced */ 500 AccessCheckMode = (Attributes & OBJ_FORCE_ACCESS_CHECK) ? 501 UserMode : AccessMode; 502 503 /* Check if we got a Root Directory */ 504 if (RootHandle) 505 { 506 /* We did. Reference it */ 507 Status = ObReferenceObjectByHandle(RootHandle, 508 0, 509 NULL, 510 AccessMode, 511 (PVOID*)&RootDirectory, 512 NULL); 513 if (!NT_SUCCESS(Status)) return Status; 514 515 /* Get the header */ 516 ObjectHeader = OBJECT_TO_OBJECT_HEADER(RootDirectory); 517 518 /* The name cannot start with a separator, unless this is a file */ 519 if ((ObjectName->Buffer) && 520 (ObjectName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR) && 521 (ObjectHeader->Type != IoFileObjectType)) 522 { 523 /* The syntax is bad, so fail this request */ 524 ObDereferenceObject(RootDirectory); 525 return STATUS_OBJECT_PATH_SYNTAX_BAD; 526 } 527 528 /* Don't parse a Directory */ 529 if (ObjectHeader->Type != ObpDirectoryObjectType) 530 { 531 /* Make sure the Object Type has a parse routine */ 532 ParseRoutine = ObjectHeader->Type->TypeInfo.ParseProcedure; 533 if (!ParseRoutine) 534 { 535 /* We can't parse a name if we don't have a parse routine */ 536 ObDereferenceObject(RootDirectory); 537 return STATUS_INVALID_HANDLE; 538 } 539 540 /* Set default parse count */ 541 MaxReparse = 30; 542 543 /* Now parse */ 544 while (TRUE) 545 { 546 /* Start with the full name */ 547 RemainingName = *ObjectName; 548 549 /* Call the Parse Procedure */ 550 ObpCalloutStart(&CalloutIrql); 551 Status = ParseRoutine(RootDirectory, 552 ObjectType, 553 AccessState, 554 AccessCheckMode, 555 Attributes, 556 ObjectName, 557 &RemainingName, 558 ParseContext, 559 SecurityQos, 560 &Object); 561 ObpCalloutEnd(CalloutIrql, "Parse", ObjectHeader->Type, Object); 562 563 /* Check for success or failure, so not reparse */ 564 if ((Status != STATUS_REPARSE) && 565 (Status != STATUS_REPARSE_OBJECT)) 566 { 567 /* Check for failure */ 568 if (!NT_SUCCESS(Status)) 569 { 570 /* Parse routine might not have cleared this, do it */ 571 Object = NULL; 572 } 573 else if (!Object) 574 { 575 /* Modify status to reflect failure inside Ob */ 576 Status = STATUS_OBJECT_NAME_NOT_FOUND; 577 } 578 579 /* We're done, return the status and object */ 580 *FoundObject = Object; 581 ObDereferenceObject(RootDirectory); 582 return Status; 583 } 584 else if ((!ObjectName->Length) || 585 (!ObjectName->Buffer) || 586 (ObjectName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)) 587 { 588 /* Reparsed to the root directory, so start over */ 589 ObDereferenceObject(RootDirectory); 590 RootDirectory = ObpRootDirectoryObject; 591 592 /* Don't use this anymore, since we're starting at root */ 593 RootHandle = NULL; 594 goto ParseFromRoot; 595 } 596 else if (--MaxReparse) 597 { 598 /* Try reparsing again */ 599 continue; 600 } 601 else 602 { 603 /* Reparsed too many times */ 604 ObDereferenceObject(RootDirectory); 605 606 /* Return the object and normalized status */ 607 *FoundObject = Object; 608 if (!Object) Status = STATUS_OBJECT_NAME_NOT_FOUND; 609 return Status; 610 } 611 } 612 } 613 else if (!(ObjectName->Length) || !(ObjectName->Buffer)) 614 { 615 /* Just return the Root Directory if we didn't get a name */ 616 Status = ObReferenceObjectByPointer(RootDirectory, 617 0, 618 ObjectType, 619 AccessMode); 620 if (NT_SUCCESS(Status)) Object = RootDirectory; 621 622 /* Remove the first reference we added and return the object */ 623 ObDereferenceObject(RootDirectory); 624 *FoundObject = Object; 625 return Status; 626 } 627 628 LocalName = *ObjectName; 629 } 630 else 631 { 632 /* We did not get a Root Directory, so use the root */ 633 RootDirectory = ObpRootDirectoryObject; 634 635 /* It must start with a path separator */ 636 if (!(ObjectName->Length) || 637 !(ObjectName->Buffer) || 638 (ObjectName->Buffer[0] != OBJ_NAME_PATH_SEPARATOR)) 639 { 640 /* This name is invalid, so fail */ 641 return STATUS_OBJECT_PATH_SYNTAX_BAD; 642 } 643 644 /* Check if the name is only the path separator */ 645 if (ObjectName->Length == sizeof(OBJ_NAME_PATH_SEPARATOR)) 646 { 647 /* So the caller only wants the root directory; do we have one? */ 648 if (!RootDirectory) 649 { 650 /* This must be the first time we're creating it... right? */ 651 if (InsertObject) 652 { 653 /* Yes, so return it to ObInsert so that it can create it */ 654 Status = ObReferenceObjectByPointer(InsertObject, 655 0, 656 ObjectType, 657 AccessMode); 658 if (NT_SUCCESS(Status)) *FoundObject = InsertObject; 659 return Status; 660 } 661 else 662 { 663 /* This should never really happen */ 664 ASSERT(FALSE); 665 return STATUS_INVALID_PARAMETER; 666 } 667 } 668 else 669 { 670 /* We do have the root directory, so just return it */ 671 Status = ObReferenceObjectByPointer(RootDirectory, 672 0, 673 ObjectType, 674 AccessMode); 675 if (NT_SUCCESS(Status)) *FoundObject = RootDirectory; 676 return Status; 677 } 678 } 679 else 680 { 681 ParseFromRoot: 682 LocalName = *ObjectName; 683 684 /* Deference the device map if we already have one */ 685 if (DeviceMap != NULL) 686 { 687 ObfDereferenceDeviceMap(DeviceMap); 688 DeviceMap = NULL; 689 } 690 691 /* Check if this is a possible DOS name */ 692 if (!((ULONG_PTR)(ObjectName->Buffer) & 7)) 693 { 694 /* 695 * This could be one. Does it match the prefix? 696 * Note that as an optimization, the match is done as 64-bit 697 * compare since the prefix is "\??\" which is exactly 8 bytes. 698 * 699 * In the second branch, we test for "\??" which is also valid. 700 * This time, we use a 32-bit compare followed by a Unicode 701 * character compare (16-bit), since the sum is 6 bytes. 702 */ 703 if ((ObjectName->Length >= ObpDosDevicesShortName.Length) && 704 (*(PULONGLONG)(ObjectName->Buffer) == 705 ObpDosDevicesShortNamePrefix.Alignment.QuadPart)) 706 { 707 DeviceMap = ObpReferenceDeviceMap(); 708 /* We have a local mapping, drop the ?? prefix */ 709 if (DeviceMap != NULL && DeviceMap->DosDevicesDirectory != NULL) 710 { 711 LocalName.Length -= ObpDosDevicesShortName.Length; 712 LocalName.MaximumLength -= ObpDosDevicesShortName.Length; 713 LocalName.Buffer += (ObpDosDevicesShortName.Length / sizeof(WCHAR)); 714 715 /* We'll browse that local directory */ 716 Directory = DeviceMap->DosDevicesDirectory; 717 } 718 } 719 else if ((ObjectName->Length == ObpDosDevicesShortName.Length - 720 sizeof(WCHAR)) && 721 (*(PULONG)(ObjectName->Buffer) == 722 ObpDosDevicesShortNameRoot.Alignment.LowPart) && 723 (*((PWCHAR)(ObjectName->Buffer) + 2) == 724 (WCHAR)(ObpDosDevicesShortNameRoot.Alignment.HighPart))) 725 { 726 DeviceMap = ObpReferenceDeviceMap(); 727 728 /* Caller is looking for the directory itself */ 729 if (DeviceMap != NULL && DeviceMap->DosDevicesDirectory != NULL) 730 { 731 Status = ObReferenceObjectByPointer(DeviceMap->DosDevicesDirectory, 732 0, 733 ObjectType, 734 AccessMode); 735 if (NT_SUCCESS(Status)) 736 { 737 *FoundObject = DeviceMap->DosDevicesDirectory; 738 } 739 740 ObfDereferenceDeviceMap(DeviceMap); 741 return Status; 742 } 743 } 744 } 745 } 746 } 747 748 /* Check if we were reparsing a symbolic link */ 749 if (!SymLink) 750 { 751 /* Allow reparse */ 752 Reparse = TRUE; 753 MaxReparse = 30; 754 } 755 756 /* Reparse */ 757 while (Reparse && MaxReparse) 758 { 759 /* Get the name */ 760 RemainingName = LocalName; 761 762 /* Disable reparsing again */ 763 Reparse = FALSE; 764 765 /* Start parse loop */ 766 while (TRUE) 767 { 768 /* Clear object */ 769 Object = NULL; 770 771 /* Check if the name starts with a path separator */ 772 if ((RemainingName.Length) && 773 (RemainingName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR)) 774 { 775 /* Skip the path separator */ 776 RemainingName.Buffer++; 777 RemainingName.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR); 778 } 779 780 /* Find the next Part Name */ 781 ComponentName = RemainingName; 782 while (RemainingName.Length) 783 { 784 /* Break if we found the \ ending */ 785 if (RemainingName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR) break; 786 787 /* Move on */ 788 RemainingName.Buffer++; 789 RemainingName.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR); 790 } 791 792 /* Get its size and make sure it's valid */ 793 ComponentName.Length -= RemainingName.Length; 794 if (!ComponentName.Length) 795 { 796 /* Invalid size, fail */ 797 Status = STATUS_OBJECT_NAME_INVALID; 798 break; 799 } 800 801 /* Check if we're in the root */ 802 if (!Directory) Directory = RootDirectory; 803 804 /* Check if this is a user-mode call that needs to traverse */ 805 if ((AccessCheckMode != KernelMode) && 806 !(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE)) 807 { 808 /* We shouldn't have referenced a directory yet */ 809 ASSERT(ReferencedDirectory == NULL); 810 811 /* Reference the directory */ 812 ObReferenceObject(Directory); 813 ReferencedDirectory = Directory; 814 815 /* Check if we have a parent directory */ 816 if (ParentDirectory) 817 { 818 /* Check for traverse access */ 819 if (!ObpCheckTraverseAccess(ParentDirectory, 820 DIRECTORY_TRAVERSE, 821 AccessState, 822 FALSE, 823 AccessCheckMode, 824 &Status)) 825 { 826 /* We don't have it, fail */ 827 break; 828 } 829 } 830 } 831 832 /* Check if we don't have a remaining name yet */ 833 if (!RemainingName.Length) 834 { 835 /* Check if we don't have a referenced directory yet */ 836 if (!ReferencedDirectory) 837 { 838 /* Reference it */ 839 ObReferenceObject(Directory); 840 ReferencedDirectory = Directory; 841 } 842 843 /* Check if we are inserting an object */ 844 if (InsertObject) 845 { 846 /* Lock the directory */ 847 ObpAcquireDirectoryLockExclusive(Directory, LookupContext); 848 } 849 } 850 851 /* Do the lookup */ 852 Object = ObpLookupEntryDirectory(Directory, 853 &ComponentName, 854 Attributes, 855 InsertObject ? FALSE : TRUE, 856 LookupContext); 857 if (!Object) 858 { 859 /* We didn't find it... do we still have a path? */ 860 if (RemainingName.Length) 861 { 862 /* Then tell the caller the path wasn't found */ 863 Status = STATUS_OBJECT_PATH_NOT_FOUND; 864 break; 865 } 866 else if (!InsertObject) 867 { 868 /* Otherwise, we have a path, but the name isn't valid */ 869 Status = STATUS_OBJECT_NAME_NOT_FOUND; 870 break; 871 } 872 873 /* Check create access for the object */ 874 if (!ObCheckCreateObjectAccess(Directory, 875 ObjectType == ObpDirectoryObjectType ? 876 DIRECTORY_CREATE_SUBDIRECTORY : 877 DIRECTORY_CREATE_OBJECT, 878 AccessState, 879 &ComponentName, 880 FALSE, 881 AccessCheckMode, 882 &Status)) 883 { 884 /* We don't have create access, fail */ 885 break; 886 } 887 888 /* Get the object header */ 889 ObjectHeader = OBJECT_TO_OBJECT_HEADER(InsertObject); 890 891 /* 892 * Deny object creation if: 893 * That's a section object or a symbolic link 894 * Which isn't in the same section that root directory 895 * That doesn't have the SeCreateGlobalPrivilege 896 * And that is not a known unsecure name 897 */ 898 if (RootDirectory->SessionId != -1) 899 { 900 if (ObjectHeader->Type == MmSectionObjectType || 901 ObjectHeader->Type == ObpSymbolicLinkObjectType) 902 { 903 if (RootDirectory->SessionId != PsGetCurrentProcessSessionId() && 904 !SeSinglePrivilegeCheck(SeCreateGlobalPrivilege, AccessCheckMode) && 905 !ObpIsUnsecureName(&ComponentName, BooleanFlagOn(Attributes, OBJ_CASE_INSENSITIVE))) 906 { 907 Status = STATUS_ACCESS_DENIED; 908 break; 909 } 910 } 911 } 912 913 /* Create Object Name */ 914 NewName = ExAllocatePoolWithTag(PagedPool, 915 ComponentName.Length, 916 OB_NAME_TAG); 917 if (!(NewName) || 918 !(ObpInsertEntryDirectory(Directory, 919 LookupContext, 920 ObjectHeader))) 921 { 922 /* Either couldn't allocate the name, or insert failed */ 923 if (NewName) ExFreePoolWithTag(NewName, OB_NAME_TAG); 924 925 /* Fail due to memory reasons */ 926 Status = STATUS_INSUFFICIENT_RESOURCES; 927 break; 928 } 929 930 /* Reference newly to be inserted object */ 931 ObReferenceObject(InsertObject); 932 933 /* Get the name information */ 934 ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader); 935 936 /* Reference the directory */ 937 ObReferenceObject(Directory); 938 939 /* Copy the Name */ 940 RtlCopyMemory(NewName, 941 ComponentName.Buffer, 942 ComponentName.Length); 943 944 /* Check if we had an old name */ 945 if (ObjectNameInfo->Name.Buffer) 946 { 947 /* Free it */ 948 ExFreePoolWithTag(ObjectNameInfo->Name.Buffer, OB_NAME_TAG); 949 } 950 951 /* Write new one */ 952 ObjectNameInfo->Name.Buffer = NewName; 953 ObjectNameInfo->Name.Length = ComponentName.Length; 954 ObjectNameInfo->Name.MaximumLength = ComponentName.Length; 955 956 /* Return Status and the Expected Object */ 957 Status = STATUS_SUCCESS; 958 Object = InsertObject; 959 960 /* Get out of here */ 961 break; 962 } 963 964 ReparseObject: 965 /* We found it, so now get its header */ 966 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); 967 968 /* 969 * Check for a parse Procedure, but don't bother to parse for an insert 970 * unless it's a Symbolic Link, in which case we MUST parse 971 */ 972 ParseRoutine = ObjectHeader->Type->TypeInfo.ParseProcedure; 973 if ((ParseRoutine) && 974 (!(InsertObject) || (ParseRoutine == ObpParseSymbolicLink))) 975 { 976 /* Use the Root Directory next time */ 977 Directory = NULL; 978 979 /* Increment the pointer count */ 980 InterlockedExchangeAddSizeT(&ObjectHeader->PointerCount, 1); 981 982 /* Cleanup from the first lookup */ 983 ObpReleaseLookupContext(LookupContext); 984 985 /* Check if we have a referenced directory */ 986 if (ReferencedDirectory) 987 { 988 /* We do, dereference it */ 989 ObDereferenceObject(ReferencedDirectory); 990 ReferencedDirectory = NULL; 991 } 992 993 /* Check if we have a referenced parent directory */ 994 if (ReferencedParentDirectory) 995 { 996 /* We do, dereference it */ 997 ObDereferenceObject(ReferencedParentDirectory); 998 ReferencedParentDirectory = NULL; 999 } 1000 1001 /* Call the Parse Procedure */ 1002 ObpCalloutStart(&CalloutIrql); 1003 Status = ParseRoutine(Object, 1004 ObjectType, 1005 AccessState, 1006 AccessCheckMode, 1007 Attributes, 1008 ObjectName, 1009 &RemainingName, 1010 ParseContext, 1011 SecurityQos, 1012 &Object); 1013 ObpCalloutEnd(CalloutIrql, "Parse", ObjectHeader->Type, Object); 1014 1015 /* Remove our extra reference */ 1016 ObDereferenceObject(&ObjectHeader->Body); 1017 1018 /* Check if we have to reparse */ 1019 if ((Status == STATUS_REPARSE) || 1020 (Status == STATUS_REPARSE_OBJECT)) 1021 { 1022 /* Reparse again */ 1023 Reparse = TRUE; 1024 --MaxReparse; 1025 if (MaxReparse == 0) 1026 { 1027 Object = NULL; 1028 break; 1029 } 1030 1031 /* Start over from root if we got sent back there */ 1032 if ((Status == STATUS_REPARSE_OBJECT) || 1033 (ObjectName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)) 1034 { 1035 /* Check if we got a root directory */ 1036 if (RootHandle) 1037 { 1038 /* Stop using it, because we have a new directory now */ 1039 ObDereferenceObject(RootDirectory); 1040 RootHandle = NULL; 1041 } 1042 1043 /* Start at Root */ 1044 ParentDirectory = NULL; 1045 RootDirectory = ObpRootDirectoryObject; 1046 1047 /* Check for reparse status */ 1048 if (Status == STATUS_REPARSE_OBJECT) 1049 { 1050 /* Don't reparse again */ 1051 Reparse = FALSE; 1052 1053 /* Did we actually get an object to which to reparse? */ 1054 if (!Object) 1055 { 1056 /* We didn't, so set a failure status */ 1057 Status = STATUS_OBJECT_NAME_NOT_FOUND; 1058 } 1059 else 1060 { 1061 /* We did, so we're free to parse the new object */ 1062 goto ReparseObject; 1063 } 1064 } 1065 else 1066 { 1067 /* This is a symbolic link */ 1068 SymLink = TRUE; 1069 goto ParseFromRoot; 1070 } 1071 } 1072 else if (RootDirectory == ObpRootDirectoryObject) 1073 { 1074 /* We got STATUS_REPARSE but are at the Root Directory */ 1075 Object = NULL; 1076 Status = STATUS_OBJECT_NAME_NOT_FOUND; 1077 Reparse = FALSE; 1078 } 1079 } 1080 else if (!NT_SUCCESS(Status)) 1081 { 1082 /* Total failure */ 1083 Object = NULL; 1084 } 1085 else if (!Object) 1086 { 1087 /* We didn't reparse but we didn't find the Object Either */ 1088 Status = STATUS_OBJECT_NAME_NOT_FOUND; 1089 } 1090 1091 /* Break out of the loop */ 1092 break; 1093 } 1094 else 1095 { 1096 /* No parse routine...do we still have a remaining name? */ 1097 if (!RemainingName.Length) 1098 { 1099 /* Are we creating an object? */ 1100 if (!InsertObject) 1101 { 1102 /* Check if this is a user-mode call that needs to traverse */ 1103 if ((AccessCheckMode != KernelMode) && 1104 !(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE)) 1105 { 1106 /* Check if we can get it */ 1107 if (!ObpCheckTraverseAccess(Directory, 1108 DIRECTORY_TRAVERSE, 1109 AccessState, 1110 FALSE, 1111 AccessCheckMode, 1112 &Status)) 1113 { 1114 /* We don't have access, fail */ 1115 Object = NULL; 1116 break; 1117 } 1118 } 1119 1120 /* Reference the Object */ 1121 Status = ObReferenceObjectByPointer(Object, 1122 0, 1123 ObjectType, 1124 AccessMode); 1125 if (!NT_SUCCESS(Status)) Object = NULL; 1126 } 1127 1128 /* And get out of the reparse loop */ 1129 break; 1130 } 1131 else 1132 { 1133 /* We still have a name; check if this is a directory object */ 1134 if (ObjectHeader->Type == ObpDirectoryObjectType) 1135 { 1136 /* Check if we have a referenced parent directory */ 1137 if (ReferencedParentDirectory) 1138 { 1139 /* Dereference it */ 1140 ObDereferenceObject(ReferencedParentDirectory); 1141 } 1142 1143 /* Restart the lookup from this directory */ 1144 ReferencedParentDirectory = ReferencedDirectory; 1145 ParentDirectory = Directory; 1146 Directory = Object; 1147 ReferencedDirectory = NULL; 1148 } 1149 else 1150 { 1151 /* We still have a name, but no parse routine for it */ 1152 Status = STATUS_OBJECT_TYPE_MISMATCH; 1153 Object = NULL; 1154 break; 1155 } 1156 } 1157 } 1158 } 1159 } 1160 1161 /* Check if we failed */ 1162 if (!NT_SUCCESS(Status)) 1163 { 1164 /* Cleanup after lookup */ 1165 ObpReleaseLookupContext(LookupContext); 1166 } 1167 1168 /* Check if we have a device map and dereference it if so */ 1169 if (DeviceMap) ObfDereferenceDeviceMap(DeviceMap); 1170 1171 /* Check if we have a referenced directory and dereference it if so */ 1172 if (ReferencedDirectory) ObDereferenceObject(ReferencedDirectory); 1173 1174 /* Check if we have a referenced parent directory */ 1175 if (ReferencedParentDirectory) 1176 { 1177 /* We do, dereference it */ 1178 ObDereferenceObject(ReferencedParentDirectory); 1179 } 1180 1181 /* Set the found object and check if we got one */ 1182 *FoundObject = Object; 1183 if (!Object) 1184 { 1185 /* Nothing was found. Did we reparse or get success? */ 1186 if ((Status == STATUS_REPARSE) || (NT_SUCCESS(Status))) 1187 { 1188 /* Set correct failure */ 1189 Status = STATUS_OBJECT_NAME_NOT_FOUND; 1190 } 1191 } 1192 1193 /* Check if we had a root directory */ 1194 if (RootHandle) ObDereferenceObject(RootDirectory); 1195 1196 /* Return status to caller */ 1197 OBTRACE(OB_NAMESPACE_DEBUG, 1198 "%s - Found Object: %p. Expected: %p\n", 1199 __FUNCTION__, 1200 *FoundObject, 1201 InsertObject); 1202 return Status; 1203 } 1204 1205 /* PUBLIC FUNCTIONS *********************************************************/ 1206 1207 NTSTATUS 1208 NTAPI 1209 ObQueryNameString(IN PVOID Object, 1210 OUT POBJECT_NAME_INFORMATION ObjectNameInfo, 1211 IN ULONG Length, 1212 OUT PULONG ReturnLength) 1213 { 1214 POBJECT_HEADER_NAME_INFO LocalInfo; 1215 POBJECT_HEADER ObjectHeader; 1216 POBJECT_DIRECTORY ParentDirectory; 1217 ULONG NameSize; 1218 PWCH ObjectName; 1219 BOOLEAN ObjectIsNamed; 1220 NTSTATUS Status = STATUS_SUCCESS; 1221 1222 /* Get the Kernel Meta-Structures */ 1223 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); 1224 LocalInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader); 1225 1226 /* Check if a Query Name Procedure is available */ 1227 if (ObjectHeader->Type->TypeInfo.QueryNameProcedure) 1228 { 1229 /* Call the procedure inside SEH */ 1230 ObjectIsNamed = ((LocalInfo) && (LocalInfo->Name.Length > 0)); 1231 1232 _SEH2_TRY 1233 { 1234 Status = ObjectHeader->Type->TypeInfo.QueryNameProcedure(Object, 1235 ObjectIsNamed, 1236 ObjectNameInfo, 1237 Length, 1238 ReturnLength, 1239 KernelMode); 1240 } 1241 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1242 { 1243 /* Return the exception code */ 1244 Status = _SEH2_GetExceptionCode(); 1245 } 1246 _SEH2_END; 1247 1248 return Status; 1249 } 1250 1251 /* Check if the object doesn't even have a name */ 1252 if (!(LocalInfo) || !(LocalInfo->Name.Buffer)) 1253 { 1254 Status = STATUS_SUCCESS; 1255 1256 _SEH2_TRY 1257 { 1258 /* We're returning the name structure */ 1259 *ReturnLength = sizeof(OBJECT_NAME_INFORMATION); 1260 1261 /* Check if we were given enough space */ 1262 if (*ReturnLength > Length) 1263 { 1264 Status = STATUS_INFO_LENGTH_MISMATCH; 1265 } 1266 else 1267 { 1268 /* Return an empty buffer */ 1269 RtlInitEmptyUnicodeString(&ObjectNameInfo->Name, NULL, 0); 1270 } 1271 } 1272 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1273 { 1274 /* Return the exception code */ 1275 Status = _SEH2_GetExceptionCode(); 1276 } 1277 _SEH2_END; 1278 1279 return Status; 1280 } 1281 1282 /* 1283 * Find the size needed for the name. We won't do 1284 * this during the Name Creation loop because we want 1285 * to let the caller know that the buffer isn't big 1286 * enough right at the beginning, not work our way through 1287 * and find out at the end 1288 */ 1289 _SEH2_TRY 1290 { 1291 if (Object == ObpRootDirectoryObject) 1292 { 1293 /* Size of the '\' string */ 1294 NameSize = sizeof(OBJ_NAME_PATH_SEPARATOR); 1295 } 1296 else 1297 { 1298 /* Get the Object Directory and add name of Object */ 1299 ParentDirectory = LocalInfo->Directory; 1300 NameSize = sizeof(OBJ_NAME_PATH_SEPARATOR) + LocalInfo->Name.Length; 1301 1302 /* Loop inside the directory to get the top-most one (meaning root) */ 1303 while ((ParentDirectory != ObpRootDirectoryObject) && (ParentDirectory)) 1304 { 1305 /* Get the Name Information */ 1306 LocalInfo = OBJECT_HEADER_TO_NAME_INFO( 1307 OBJECT_TO_OBJECT_HEADER(ParentDirectory)); 1308 1309 /* Add the size of the Directory Name */ 1310 if (LocalInfo && LocalInfo->Directory) 1311 { 1312 /* Size of the '\' string + Directory Name */ 1313 NameSize += sizeof(OBJ_NAME_PATH_SEPARATOR) + 1314 LocalInfo->Name.Length; 1315 1316 /* Move to next parent Directory */ 1317 ParentDirectory = LocalInfo->Directory; 1318 } 1319 else 1320 { 1321 /* Directory with no name. We append "...\" */ 1322 NameSize += sizeof(L"...") + sizeof(OBJ_NAME_PATH_SEPARATOR); 1323 break; 1324 } 1325 } 1326 } 1327 1328 /* Finally, add the name of the structure and the null char */ 1329 *ReturnLength = NameSize + 1330 sizeof(OBJECT_NAME_INFORMATION) + 1331 sizeof(UNICODE_NULL); 1332 1333 /* Check if we were given enough space */ 1334 if (*ReturnLength > Length) _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH); 1335 1336 /* 1337 * Now we will actually create the name. We work backwards because 1338 * it's easier to start off from the Name we have and walk up the 1339 * parent directories. We use the same logic as Name Length calculation. 1340 */ 1341 LocalInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader); 1342 ObjectName = (PWCH)((ULONG_PTR)ObjectNameInfo + *ReturnLength); 1343 *--ObjectName = UNICODE_NULL; 1344 1345 /* Check if the object is actually the Root directory */ 1346 if (Object == ObpRootDirectoryObject) 1347 { 1348 /* This is already the Root Directory, return "\\" */ 1349 *--ObjectName = OBJ_NAME_PATH_SEPARATOR; 1350 ObjectNameInfo->Name.Length = (USHORT)NameSize; 1351 ObjectNameInfo->Name.MaximumLength = (USHORT)(NameSize + 1352 sizeof(UNICODE_NULL)); 1353 ObjectNameInfo->Name.Buffer = ObjectName; 1354 Status = STATUS_SUCCESS; 1355 } 1356 else 1357 { 1358 /* Start by adding the Object's Name */ 1359 ObjectName = (PWCH)((ULONG_PTR)ObjectName - 1360 LocalInfo->Name.Length); 1361 RtlCopyMemory(ObjectName, 1362 LocalInfo->Name.Buffer, 1363 LocalInfo->Name.Length); 1364 1365 /* Now parse the Parent directories until we reach the top */ 1366 ParentDirectory = LocalInfo->Directory; 1367 while ((ParentDirectory != ObpRootDirectoryObject) && (ParentDirectory)) 1368 { 1369 /* Get the name information */ 1370 LocalInfo = OBJECT_HEADER_TO_NAME_INFO( 1371 OBJECT_TO_OBJECT_HEADER(ParentDirectory)); 1372 1373 /* Add the "\" */ 1374 *(--ObjectName) = OBJ_NAME_PATH_SEPARATOR; 1375 1376 /* Add the Parent Directory's Name */ 1377 if (LocalInfo && LocalInfo->Name.Buffer) 1378 { 1379 /* Add the name */ 1380 ObjectName = (PWCH)((ULONG_PTR)ObjectName - 1381 LocalInfo->Name.Length); 1382 RtlCopyMemory(ObjectName, 1383 LocalInfo->Name.Buffer, 1384 LocalInfo->Name.Length); 1385 1386 /* Move to next parent */ 1387 ParentDirectory = LocalInfo->Directory; 1388 } 1389 else 1390 { 1391 /* Directory without a name, we add "..." */ 1392 ObjectName = (PWCH)((ULONG_PTR)ObjectName - 1393 sizeof(L"...") + 1394 sizeof(UNICODE_NULL)); 1395 RtlCopyMemory(ObjectName, L"...", sizeof(L"...")); 1396 break; 1397 } 1398 } 1399 1400 /* Add Root Directory Name */ 1401 *(--ObjectName) = OBJ_NAME_PATH_SEPARATOR; 1402 ObjectNameInfo->Name.Length = (USHORT)NameSize; 1403 ObjectNameInfo->Name.MaximumLength = 1404 (USHORT)(NameSize + sizeof(UNICODE_NULL)); 1405 ObjectNameInfo->Name.Buffer = ObjectName; 1406 } 1407 } 1408 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1409 { 1410 /* Return the exception code */ 1411 Status = _SEH2_GetExceptionCode(); 1412 } 1413 _SEH2_END; 1414 1415 /* Return success */ 1416 return Status; 1417 } 1418 1419 /* EOF */ 1420