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
ObpGetDosDevicesProtection(OUT PSECURITY_DESCRIPTOR SecurityDescriptor)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, TAG_DACL);
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, TAG_DACL);
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
ObpFreeDosDevicesProtection(OUT PSECURITY_DESCRIPTOR SecurityDescriptor)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, TAG_DACL);
172 }
173
174 CODE_SEG("INIT")
175 NTSTATUS
176 NTAPI
ObpCreateDosDevicesDirectory(VOID)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
ObpDeleteNameCheck(IN PVOID Object)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
ObpIsUnsecureName(IN PUNICODE_STRING ObjectName,IN BOOLEAN CaseInSensitive)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
ObpLookupObjectName(IN HANDLE RootHandle OPTIONAL,IN OUT PUNICODE_STRING ObjectName,IN ULONG Attributes,IN POBJECT_TYPE ObjectType,IN KPROCESSOR_MODE AccessMode,IN OUT PVOID ParseContext,IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,IN PVOID InsertObject OPTIONAL,IN OUT PACCESS_STATE AccessState,OUT POBP_LOOKUP_CONTEXT LookupContext,OUT PVOID * FoundObject)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
ObQueryNameString(IN PVOID Object,OUT POBJECT_NAME_INFORMATION ObjectNameInfo,IN ULONG Length,OUT PULONG ReturnLength)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