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