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