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