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