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