Fix more DPRINTs.
[reactos.git] / reactos / ntoskrnl / ob / object.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ob/object.c
6 * PURPOSE: Implements generic object managment functions
7 *
8 * PROGRAMMERS: David Welch (welch@cwcom.net)
9 * Skywing (skywing@valhallalegends.com)
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ntoskrnl.h>
15 #define NDEBUG
16 #include <internal/debug.h>
17
18 #define UNICODE_PATH_SEP L'\\'
19 #define UNICODE_NO_PATH L"..."
20
21 typedef struct _RETENTION_CHECK_PARAMS
22 {
23 WORK_QUEUE_ITEM WorkItem;
24 POBJECT_HEADER ObjectHeader;
25 } RETENTION_CHECK_PARAMS, *PRETENTION_CHECK_PARAMS;
26
27 /* FUNCTIONS ************************************************************/
28
29 NTSTATUS
30 STDCALL
31 ObpCaptureObjectName(IN OUT PUNICODE_STRING CapturedName,
32 IN PUNICODE_STRING ObjectName,
33 IN KPROCESSOR_MODE AccessMode)
34 {
35 NTSTATUS Status = STATUS_SUCCESS;
36 UNICODE_STRING LocalName = {}; /* <= GCC 4.0 + Optimizer */
37
38 /* First Probe the String */
39 DPRINT("ObpCaptureObjectName: %wZ\n", ObjectName);
40 if (AccessMode != KernelMode)
41 {
42 DPRINT("Probing Struct\n");
43 _SEH_TRY
44 {
45 /* FIXME: Explorer or win32 broken I think */
46 #if 0
47 ProbeForRead(ObjectName,
48 sizeof(UNICODE_STRING),
49 sizeof(USHORT));
50 #endif
51 LocalName = *ObjectName;
52 }
53 _SEH_HANDLE
54 {
55 Status = _SEH_GetExceptionCode();
56 }
57 _SEH_END;
58
59 if (NT_SUCCESS(Status))
60 {
61 DPRINT("Probing OK\n");
62 _SEH_TRY
63 {
64 #if 0
65 DPRINT("Probing buffer\n");
66 ProbeForRead(LocalName.Buffer,
67 LocalName.Length,
68 sizeof(USHORT));
69 #endif
70 }
71 _SEH_HANDLE
72 {
73 Status = _SEH_GetExceptionCode();
74 }
75 _SEH_END;
76 }
77
78 /* Fail if anything up to here died */
79 if (!NT_SUCCESS(Status))
80 {
81 DPRINT1("Probing failed\n");
82 return Status;
83 }
84 }
85 else
86 {
87 LocalName = *ObjectName;
88 }
89
90 /* Make sure there really is a string */
91 DPRINT("Probing OK\n");
92 if (LocalName.Length)
93 {
94 /* Allocate a non-paged buffer for this string */
95 DPRINT("Capturing String\n");
96 CapturedName->Length = LocalName.Length;
97 CapturedName->MaximumLength = LocalName.Length + sizeof(WCHAR);
98 CapturedName->Buffer = ExAllocatePoolWithTag(NonPagedPool,
99 CapturedName->MaximumLength,
100 TAG('O','b','N','m'));
101
102 /* Copy the string and null-terminate it */
103 RtlMoveMemory(CapturedName->Buffer, LocalName.Buffer, LocalName.Length);
104 CapturedName->Buffer[LocalName.Length / sizeof(WCHAR)] = UNICODE_NULL;
105 DPRINT("String Captured: %p, %wZ\n", CapturedName, CapturedName);
106 }
107
108 return Status;
109 }
110
111 NTSTATUS
112 STDCALL
113 ObpCaptureObjectAttributes(IN POBJECT_ATTRIBUTES ObjectAttributes,
114 IN KPROCESSOR_MODE AccessMode,
115 IN POBJECT_TYPE ObjectType,
116 IN POBJECT_CREATE_INFORMATION ObjectCreateInfo,
117 OUT PUNICODE_STRING ObjectName)
118 {
119 NTSTATUS Status = STATUS_SUCCESS;
120 PSECURITY_DESCRIPTOR SecurityDescriptor;
121 PSECURITY_QUALITY_OF_SERVICE SecurityQos;
122 PUNICODE_STRING LocalObjectName = NULL;
123
124 /* Zero out the Capture Data */
125 DPRINT("ObpCaptureObjectAttributes\n");
126 RtlZeroMemory(ObjectCreateInfo, sizeof(OBJECT_CREATE_INFORMATION));
127
128 /* Check if we got Oba */
129 if (ObjectAttributes)
130 {
131 if (AccessMode != KernelMode)
132 {
133 DPRINT("Probing OBA\n");
134 _SEH_TRY
135 {
136 /* FIXME: SMSS SENDS BULLSHIT. */
137 #if 0
138 ProbeForRead(ObjectAttributes,
139 sizeof(ObjectAttributes),
140 sizeof(ULONG));
141 #endif
142 }
143 _SEH_HANDLE
144 {
145 Status = _SEH_GetExceptionCode();
146 }
147 _SEH_END;
148 }
149
150 /* Validate the Size */
151 DPRINT("Validating OBA\n");
152 if (ObjectAttributes->Length != sizeof(OBJECT_ATTRIBUTES))
153 {
154 Status = STATUS_INVALID_PARAMETER;
155 }
156
157 /* Fail if SEH or Size Validation failed */
158 if(!NT_SUCCESS(Status))
159 {
160 DPRINT1("ObpCaptureObjectAttributes failed to probe object attributes\n");
161 goto fail;
162 }
163
164 /* Set some Create Info */
165 DPRINT("Creating OBCI\n");
166 ObjectCreateInfo->RootDirectory = ObjectAttributes->RootDirectory;
167 ObjectCreateInfo->Attributes = ObjectAttributes->Attributes;
168 LocalObjectName = ObjectAttributes->ObjectName;
169 SecurityDescriptor = ObjectAttributes->SecurityDescriptor;
170 SecurityQos = ObjectAttributes->SecurityQualityOfService;
171
172 /* Validate the SD */
173 if (SecurityDescriptor)
174 {
175 DPRINT("Probing SD: %x\n", SecurityDescriptor);
176 Status = SeCaptureSecurityDescriptor(SecurityDescriptor,
177 AccessMode,
178 NonPagedPool,
179 TRUE,
180 &ObjectCreateInfo->SecurityDescriptor);
181 if(!NT_SUCCESS(Status))
182 {
183 DPRINT1("Unable to capture the security descriptor!!!\n");
184 ObjectCreateInfo->SecurityDescriptor = NULL;
185 goto fail;
186 }
187
188 DPRINT("Probe done\n");
189 ObjectCreateInfo->SecurityDescriptorCharge = 0; /* FIXME */
190 ObjectCreateInfo->ProbeMode = AccessMode;
191 }
192
193 /* Validate the QoS */
194 if (SecurityQos)
195 {
196 if (AccessMode != KernelMode)
197 {
198 DPRINT("Probing QoS\n");
199 _SEH_TRY
200 {
201 ProbeForRead(SecurityQos,
202 sizeof(SECURITY_QUALITY_OF_SERVICE),
203 sizeof(ULONG));
204 }
205 _SEH_HANDLE
206 {
207 Status = _SEH_GetExceptionCode();
208 }
209 _SEH_END;
210 }
211
212 if(!NT_SUCCESS(Status))
213 {
214 DPRINT1("Unable to capture QoS!!!\n");
215 goto fail;
216 }
217
218 ObjectCreateInfo->SecurityQualityOfService = *SecurityQos;
219 ObjectCreateInfo->SecurityQos = &ObjectCreateInfo->SecurityQualityOfService;
220 }
221 }
222
223 /* Clear Local Object Name */
224 DPRINT("Clearing name\n");
225 RtlZeroMemory(ObjectName, sizeof(UNICODE_STRING));
226
227 /* Now check if the Object Attributes had an Object Name */
228 if (LocalObjectName)
229 {
230 DPRINT("Name Buffer: %x\n", LocalObjectName->Buffer);
231 Status = ObpCaptureObjectName(ObjectName,
232 LocalObjectName,
233 AccessMode);
234 }
235 else
236 {
237 /* He can't have specified a Root Directory */
238 if (ObjectCreateInfo->RootDirectory)
239 {
240 DPRINT1("Invalid name\n");
241 Status = STATUS_OBJECT_NAME_INVALID;
242 }
243 }
244
245 fail:
246 if (!NT_SUCCESS(Status))
247 {
248 DPRINT1("Failed to capture, cleaning up\n");
249 ObpReleaseCapturedAttributes(ObjectCreateInfo);
250 }
251
252 DPRINT("Return to caller\n");
253 return Status;
254 }
255
256
257 VOID
258 STDCALL
259 ObpReleaseCapturedAttributes(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo)
260 {
261 /* Release the SD, it's the only thing we allocated */
262 if (ObjectCreateInfo->SecurityDescriptor)
263 {
264 SeReleaseSecurityDescriptor(ObjectCreateInfo->SecurityDescriptor,
265 ObjectCreateInfo->ProbeMode,
266 TRUE);
267 ObjectCreateInfo->SecurityDescriptor = NULL;
268 }
269 }
270
271
272 /**********************************************************************
273 * NAME PRIVATE
274 * ObFindObject@16
275 *
276 * DESCRIPTION
277 *
278 * ARGUMENTS
279 * ObjectAttributes
280 *
281 * ReturnedObject
282 *
283 * RemainigPath
284 * Pointer to a unicode string that will contain the
285 * remaining path if the function returns successfully.
286 * The caller must free the buffer after use by calling
287 * RtlFreeUnicodeString ().
288 *
289 * ObjectType
290 * Optional pointer to an object type. This is used to
291 * descide if a symbolic link object will be parsed or not.
292 *
293 * RETURN VALUE
294 */
295 NTSTATUS
296 ObFindObject(POBJECT_CREATE_INFORMATION ObjectCreateInfo,
297 PUNICODE_STRING ObjectName,
298 PVOID* ReturnedObject,
299 PUNICODE_STRING RemainingPath,
300 POBJECT_TYPE ObjectType)
301 {
302 PVOID NextObject;
303 PVOID CurrentObject;
304 PVOID RootObject;
305 POBJECT_HEADER CurrentHeader;
306 NTSTATUS Status;
307 PWSTR current;
308 UNICODE_STRING PathString;
309 ULONG Attributes;
310
311 PAGED_CODE();
312
313 DPRINT("ObFindObject(ObjectCreateInfo %x, ReturnedObject %x, "
314 "RemainingPath %x)\n",ObjectCreateInfo,ReturnedObject,RemainingPath);
315
316 RtlInitUnicodeString (RemainingPath, NULL);
317
318 if (ObjectCreateInfo->RootDirectory == NULL)
319 {
320 ObReferenceObjectByPointer(NameSpaceRoot,
321 DIRECTORY_TRAVERSE,
322 NULL,
323 UserMode);
324 CurrentObject = NameSpaceRoot;
325 }
326 else
327 {
328 Status = ObReferenceObjectByHandle(ObjectCreateInfo->RootDirectory,
329 0,
330 NULL,
331 UserMode,
332 &CurrentObject,
333 NULL);
334 if (!NT_SUCCESS(Status))
335 {
336 return Status;
337 }
338 }
339
340 if (ObjectName->Length == 0 ||
341 ObjectName->Buffer[0] == UNICODE_NULL)
342 {
343 *ReturnedObject = CurrentObject;
344 return STATUS_SUCCESS;
345 }
346
347 if (ObjectCreateInfo->RootDirectory == NULL &&
348 ObjectName->Buffer[0] != L'\\')
349 {
350 ObDereferenceObject (CurrentObject);
351 DPRINT1("failed\n");
352 return STATUS_UNSUCCESSFUL;
353 }
354
355 /* Create a zero-terminated copy of the object name */
356 PathString.Length = ObjectName->Length;
357 PathString.MaximumLength = ObjectName->Length + sizeof(WCHAR);
358 PathString.Buffer = ExAllocatePool (NonPagedPool,
359 PathString.MaximumLength);
360 if (PathString.Buffer == NULL)
361 {
362 ObDereferenceObject (CurrentObject);
363 return STATUS_INSUFFICIENT_RESOURCES;
364 }
365
366 RtlCopyMemory (PathString.Buffer,
367 ObjectName->Buffer,
368 ObjectName->Length);
369 PathString.Buffer[PathString.Length / sizeof(WCHAR)] = UNICODE_NULL;
370
371 current = PathString.Buffer;
372
373 RootObject = CurrentObject;
374 Attributes = ObjectCreateInfo->Attributes;
375 if (ObjectType == ObSymbolicLinkType)
376 Attributes |= OBJ_OPENLINK;
377
378 while (TRUE)
379 {
380 DPRINT("current %S\n",current);
381 CurrentHeader = BODY_TO_HEADER(CurrentObject);
382
383 DPRINT("Current ObjectType %wZ\n",
384 &CurrentHeader->Type->Name);
385
386 if (CurrentHeader->Type->TypeInfo.ParseProcedure == NULL)
387 {
388 DPRINT("Current object can't parse\n");
389 break;
390 }
391 Status = CurrentHeader->Type->TypeInfo.ParseProcedure(CurrentObject,
392 &NextObject,
393 &PathString,
394 &current,
395 Attributes);
396 if (Status == STATUS_REPARSE)
397 {
398 /* reparse the object path */
399 NextObject = NameSpaceRoot;
400 current = PathString.Buffer;
401
402 ObReferenceObjectByPointer(NextObject,
403 DIRECTORY_TRAVERSE,
404 NULL,
405 UserMode);
406 }
407
408 if (NextObject == NULL)
409 {
410 break;
411 }
412 ObDereferenceObject(CurrentObject);
413 CurrentObject = NextObject;
414 }
415
416 if (current)
417 {
418 RtlpCreateUnicodeString (RemainingPath, current, NonPagedPool);
419 }
420
421 RtlFreeUnicodeString (&PathString);
422 *ReturnedObject = CurrentObject;
423
424 return STATUS_SUCCESS;
425 }
426
427
428 /**********************************************************************
429 * NAME EXPORTED
430 * ObQueryNameString@16
431 *
432 * DESCRIPTION
433 *
434 * ARGUMENTS
435 *
436 * RETURN VALUE
437 *
438 * @implemented
439 */
440 NTSTATUS
441 STDCALL
442 ObQueryNameString(IN PVOID Object,
443 OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
444 IN ULONG Length,
445 OUT PULONG ReturnLength)
446 {
447 POBJECT_HEADER_NAME_INFO LocalInfo;
448 POBJECT_HEADER ObjectHeader;
449 PDIRECTORY_OBJECT ParentDirectory;
450 ULONG NameSize;
451 PWCH ObjectName;
452 NTSTATUS Status;
453
454 DPRINT("ObQueryNameString: %x, %x\n", Object, ObjectNameInfo);
455
456 /* Get the Kernel Meta-Structures */
457 ObjectHeader = BODY_TO_HEADER(Object);
458 LocalInfo = HEADER_TO_OBJECT_NAME(ObjectHeader);
459
460 /* Check if a Query Name Procedure is available */
461 if (ObjectHeader->Type->TypeInfo.QueryNameProcedure)
462 {
463 /* Call the procedure */
464 DPRINT("Calling Object's Procedure\n");
465 Status = ObjectHeader->Type->TypeInfo.QueryNameProcedure(Object,
466 ObjectNameInfo,
467 Length,
468 ReturnLength);
469
470 /* Return the status */
471 return Status;
472 }
473
474 /* Check if the object doesn't even have a name */
475 if (!LocalInfo || !LocalInfo->Name.Buffer)
476 {
477 /* We're returning the name structure */
478 DPRINT("Nameless Object\n");
479 *ReturnLength = sizeof(OBJECT_NAME_INFORMATION);
480
481 /* Check if we were given enough space */
482 if (*ReturnLength > Length)
483 {
484 DPRINT1("Not enough buffer space\n");
485 return STATUS_INFO_LENGTH_MISMATCH;
486 }
487
488 /* Return an empty buffer */
489 ObjectNameInfo->Name.Length = 0;
490 ObjectNameInfo->Name.MaximumLength = 0;
491 ObjectNameInfo->Name.Buffer = NULL;
492
493 return STATUS_SUCCESS;
494 }
495
496 /*
497 * Find the size needed for the name. We won't do
498 * this during the Name Creation loop because we want
499 * to let the caller know that the buffer isn't big
500 * enough right at the beginning, not work our way through
501 * and find out at the end
502 */
503 if (Object == NameSpaceRoot)
504 {
505 /* Size of the '\' string */
506 DPRINT("Object is Root\n");
507 NameSize = sizeof(UNICODE_PATH_SEP);
508 }
509 else
510 {
511 /* Get the Object Directory and add name of Object */
512 ParentDirectory = LocalInfo->Directory;
513 NameSize = sizeof(UNICODE_PATH_SEP) + LocalInfo->Name.Length;
514
515 /* Loop inside the directory to get the top-most one (meaning root) */
516 while ((ParentDirectory != NameSpaceRoot) && (ParentDirectory))
517 {
518 /* Get the Name Information */
519 LocalInfo = HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(ParentDirectory));
520
521 /* Add the size of the Directory Name */
522 if (LocalInfo && LocalInfo->Directory)
523 {
524 /* Size of the '\' string + Directory Name */
525 NameSize += sizeof(UNICODE_PATH_SEP) + LocalInfo->Name.Length;
526
527 /* Move to next parent Directory */
528 ParentDirectory = LocalInfo->Directory;
529 }
530 else
531 {
532 /* Directory with no name. We append "...\" */
533 DPRINT("Nameless Directory\n");
534 NameSize += sizeof(UNICODE_NO_PATH) + sizeof(UNICODE_PATH_SEP);
535 break;
536 }
537 }
538 }
539
540 /* Finally, add the name of the structure and the null char */
541 *ReturnLength = NameSize + sizeof(OBJECT_NAME_INFORMATION) + sizeof(UNICODE_NULL);
542 DPRINT("Final Length: %x\n", *ReturnLength);
543
544 /* Check if we were given enough space */
545 if (*ReturnLength > Length)
546 {
547 DPRINT1("Not enough buffer space\n");
548 return STATUS_INFO_LENGTH_MISMATCH;
549 }
550
551 /*
552 * Now we will actually create the name. We work backwards because
553 * it's easier to start off from the Name we have and walk up the
554 * parent directories. We use the same logic as Name Length calculation.
555 */
556 LocalInfo = HEADER_TO_OBJECT_NAME(ObjectHeader);
557 ObjectName = (PWCH)((ULONG_PTR)ObjectNameInfo + *ReturnLength);
558 *--ObjectName = UNICODE_NULL;
559
560 if (Object == NameSpaceRoot)
561 {
562 /* This is already the Root Directory, return "\\" */
563 DPRINT("Returning Root Dir\n");
564 *--ObjectName = UNICODE_PATH_SEP;
565 ObjectNameInfo->Name.Length = (USHORT)NameSize;
566 ObjectNameInfo->Name.MaximumLength = (USHORT)(NameSize + sizeof(UNICODE_NULL));
567 ObjectNameInfo->Name.Buffer = ObjectName;
568
569 return STATUS_SUCCESS;
570 }
571 else
572 {
573 /* Start by adding the Object's Name */
574 ObjectName = (PWCH)((ULONG_PTR)ObjectName - LocalInfo->Name.Length);
575 RtlMoveMemory(ObjectName, LocalInfo->Name.Buffer, LocalInfo->Name.Length);
576
577 /* Now parse the Parent directories until we reach the top */
578 ParentDirectory = LocalInfo->Directory;
579 while ((ParentDirectory != NameSpaceRoot) && (ParentDirectory))
580 {
581 /* Get the name information */
582 LocalInfo = HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(ParentDirectory));
583
584 /* Add the "\" */
585 *(--ObjectName) = UNICODE_PATH_SEP;
586
587 /* Add the Parent Directory's Name */
588 if (LocalInfo && LocalInfo->Name.Buffer)
589 {
590 /* Add the name */
591 ObjectName = (PWCH)((ULONG_PTR)ObjectName - LocalInfo->Name.Length);
592 RtlMoveMemory(ObjectName, LocalInfo->Name.Buffer, LocalInfo->Name.Length);
593
594 /* Move to next parent */
595 ParentDirectory = LocalInfo->Directory;
596 }
597 else
598 {
599 /* Directory without a name, we add "..." */
600 DPRINT("Nameless Directory\n");
601 ObjectName -= sizeof(UNICODE_NO_PATH);
602 ObjectName = UNICODE_NO_PATH;
603 break;
604 }
605 }
606
607 /* Add Root Directory Name */
608 *(--ObjectName) = UNICODE_PATH_SEP;
609 DPRINT("Current Buffer: %S\n", ObjectName);
610 ObjectNameInfo->Name.Length = (USHORT)NameSize;
611 ObjectNameInfo->Name.MaximumLength = (USHORT)(NameSize + sizeof(UNICODE_NULL));
612 ObjectNameInfo->Name.Buffer = ObjectName;
613 DPRINT("Complete: %wZ\n", ObjectNameInfo);
614 }
615
616 return STATUS_SUCCESS;
617 }
618
619 NTSTATUS
620 STDCALL
621 ObpAllocateObject(POBJECT_CREATE_INFORMATION ObjectCreateInfo,
622 PUNICODE_STRING ObjectName,
623 POBJECT_TYPE ObjectType,
624 ULONG ObjectSize,
625 POBJECT_HEADER *ObjectHeader)
626 {
627 POBJECT_HEADER Header;
628 BOOLEAN HasHandleInfo = FALSE;
629 BOOLEAN HasNameInfo = FALSE;
630 BOOLEAN HasCreatorInfo = FALSE;
631 POBJECT_HEADER_HANDLE_INFO HandleInfo;
632 POBJECT_HEADER_NAME_INFO NameInfo;
633 POBJECT_HEADER_CREATOR_INFO CreatorInfo;
634 POOL_TYPE PoolType;
635 ULONG FinalSize = ObjectSize;
636 ULONG Tag;
637
638 /* If we don't have an Object Type yet, force NonPaged */
639 DPRINT("ObpAllocateObject\n");
640 if (!ObjectType)
641 {
642 PoolType = NonPagedPool;
643 Tag = TAG('O', 'b', 'j', 'T');
644 }
645 else
646 {
647 PoolType = ObjectType->TypeInfo.PoolType;
648 Tag = ObjectType->Key;
649 }
650
651 DPRINT("Checking ObjectName: %x\n", ObjectName);
652 /* Check if the Object has a name */
653 if (ObjectName->Buffer)
654 {
655 FinalSize += sizeof(OBJECT_HEADER_NAME_INFO);
656 HasNameInfo = TRUE;
657 }
658
659 if (ObjectType)
660 {
661 /* Check if the Object maintains handle counts */
662 DPRINT("Checking ObjectType->TypeInfo: %x\n", &ObjectType->TypeInfo);
663 if (ObjectType->TypeInfo.MaintainHandleCount)
664 {
665 FinalSize += sizeof(OBJECT_HEADER_HANDLE_INFO);
666 HasHandleInfo = TRUE;
667 }
668
669 /* Check if the Object maintains type lists */
670 if (ObjectType->TypeInfo.MaintainTypeList)
671 {
672 FinalSize += sizeof(OBJECT_HEADER_CREATOR_INFO);
673 HasCreatorInfo = TRUE;
674 }
675 }
676
677 /* Allocate memory for the Object and Header */
678 DPRINT("Allocating: %x %x\n", FinalSize, Tag);
679 Header = ExAllocatePoolWithTag(PoolType, FinalSize, Tag);
680 if (!Header) {
681 DPRINT1("Not enough memory!\n");
682 return STATUS_INSUFFICIENT_RESOURCES;
683 }
684
685 /* Initialize Handle Info */
686 if (HasHandleInfo)
687 {
688 HandleInfo = (POBJECT_HEADER_HANDLE_INFO)Header;
689 DPRINT("Info: %x\n", HandleInfo);
690 HandleInfo->SingleEntry.HandleCount = 0;
691 Header = (POBJECT_HEADER)(HandleInfo + 1);
692 }
693
694 /* Initialize the Object Name Info */
695 if (HasNameInfo)
696 {
697 NameInfo = (POBJECT_HEADER_NAME_INFO)Header;
698 DPRINT("Info: %x %wZ\n", NameInfo, ObjectName);
699 NameInfo->Name = *ObjectName;
700 NameInfo->Directory = NULL;
701 Header = (POBJECT_HEADER)(NameInfo + 1);
702 }
703
704 /* Initialize Creator Info */
705 if (HasCreatorInfo)
706 {
707 CreatorInfo = (POBJECT_HEADER_CREATOR_INFO)Header;
708 DPRINT("Info: %x\n", CreatorInfo);
709 /* FIXME: Needs Alex's Init patch
710 * CreatorInfo->CreatorUniqueProcess = PsGetCurrentProcessId();
711 */
712 InitializeListHead(&CreatorInfo->TypeList);
713 Header = (POBJECT_HEADER)(CreatorInfo + 1);
714 }
715
716 /* Initialize the object header */
717 RtlZeroMemory(Header, ObjectSize);
718 DPRINT("Initalized header %p\n", Header);
719 Header->HandleCount = 0;
720 Header->PointerCount = 1;
721 Header->Type = ObjectType;
722 Header->Flags = OB_FLAG_CREATE_INFO;
723
724 /* Set the Offsets for the Info */
725 if (HasHandleInfo)
726 {
727 Header->HandleInfoOffset = HasNameInfo * sizeof(OBJECT_HEADER_NAME_INFO) +
728 sizeof(OBJECT_HEADER_HANDLE_INFO) +
729 HasCreatorInfo * sizeof(OBJECT_HEADER_CREATOR_INFO);
730 Header->Flags |= OB_FLAG_SINGLE_PROCESS;
731 }
732 if (HasNameInfo)
733 {
734 Header->NameInfoOffset = sizeof(OBJECT_HEADER_NAME_INFO) +
735 HasCreatorInfo * sizeof(OBJECT_HEADER_CREATOR_INFO);
736 }
737 if (HasCreatorInfo) Header->Flags |= OB_FLAG_CREATOR_INFO;
738
739 if (ObjectCreateInfo && ObjectCreateInfo->Attributes & OBJ_PERMANENT)
740 {
741 Header->Flags |= OB_FLAG_PERMANENT;
742 }
743 if (ObjectCreateInfo && ObjectCreateInfo->Attributes & OBJ_EXCLUSIVE)
744 {
745 Header->Flags |= OB_FLAG_EXCLUSIVE;
746 }
747
748 /* Link stuff to Object Header */
749 Header->ObjectCreateInfo = ObjectCreateInfo;
750
751 /* Return Header */
752 *ObjectHeader = Header;
753 return STATUS_SUCCESS;
754 }
755
756 /**********************************************************************
757 * NAME EXPORTED
758 * ObCreateObject@36
759 *
760 * DESCRIPTION
761 *
762 * ARGUMENTS
763 *
764 * RETURN VALUE
765 * Status
766 *
767 * @implemented
768 */
769 NTSTATUS
770 STDCALL
771 ObCreateObject(IN KPROCESSOR_MODE ObjectAttributesAccessMode OPTIONAL,
772 IN POBJECT_TYPE Type,
773 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
774 IN KPROCESSOR_MODE AccessMode,
775 IN OUT PVOID ParseContext OPTIONAL,
776 IN ULONG ObjectSize,
777 IN ULONG PagedPoolCharge OPTIONAL,
778 IN ULONG NonPagedPoolCharge OPTIONAL,
779 OUT PVOID *Object)
780 {
781 NTSTATUS Status;
782 POBJECT_CREATE_INFORMATION ObjectCreateInfo;
783 UNICODE_STRING ObjectName;
784 POBJECT_HEADER Header;
785
786 DPRINT("ObCreateObject(Type %p ObjectAttributes %p, Object %p)\n",
787 Type, ObjectAttributes, Object);
788
789 /* Allocate a Buffer for the Object Create Info */
790 DPRINT("Allocating Create Buffer\n");
791 ObjectCreateInfo = ExAllocatePoolWithTag(NonPagedPool,
792 sizeof(*ObjectCreateInfo),
793 TAG('O','b','C', 'I'));
794
795 /* Capture all the info */
796 DPRINT("Capturing Create Info\n");
797 Status = ObpCaptureObjectAttributes(ObjectAttributes,
798 AccessMode,
799 Type,
800 ObjectCreateInfo,
801 &ObjectName);
802
803 if (NT_SUCCESS(Status))
804 {
805 /* Allocate the Object */
806 DPRINT("Allocating: %wZ\n", &ObjectName);
807 Status = ObpAllocateObject(ObjectCreateInfo,
808 &ObjectName,
809 Type,
810 OBJECT_ALLOC_SIZE(ObjectSize),
811 &Header);
812
813 if (NT_SUCCESS(Status))
814 {
815 /* Return the Object */
816 DPRINT("Returning Object\n");
817 *Object = &Header->Body;
818
819 /* Return to caller, leave the Capture Info Alive for ObInsert */
820 return Status;
821 }
822
823 /* Release the Capture Info, we don't need it */
824 DPRINT1("Allocation failed\n");
825 ObpReleaseCapturedAttributes(ObjectCreateInfo);
826 if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
827 }
828
829 /* We failed, so release the Buffer */
830 DPRINT1("Capture failed\n");
831 ExFreePool(ObjectCreateInfo);
832 return Status;
833 }
834
835 /*
836 * FUNCTION: Increments the pointer reference count for a given object
837 * ARGUMENTS:
838 * ObjectBody = Object's body
839 * DesiredAccess = Desired access to the object
840 * ObjectType = Points to the object type structure
841 * AccessMode = Type of access check to perform
842 * RETURNS: Status
843 *
844 * @implemented
845 */
846 NTSTATUS STDCALL
847 ObReferenceObjectByPointer(IN PVOID Object,
848 IN ACCESS_MASK DesiredAccess,
849 IN POBJECT_TYPE ObjectType,
850 IN KPROCESSOR_MODE AccessMode)
851 {
852 POBJECT_HEADER Header;
853
854 /* NOTE: should be possible to reference an object above APC_LEVEL! */
855
856 DPRINT("ObReferenceObjectByPointer(Object %x, ObjectType %x)\n",
857 Object,ObjectType);
858
859 Header = BODY_TO_HEADER(Object);
860
861 if (ObjectType != NULL && Header->Type != ObjectType)
862 {
863 DPRINT("Failed %p (type was %x %wZ) should be %x %wZ\n",
864 Header,
865 Header->Type,
866 &HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(Header->Type))->Name,
867 ObjectType,
868 &HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(ObjectType))->Name);
869 return(STATUS_UNSUCCESSFUL);
870 }
871 if (Header->Type == PsProcessType)
872 {
873 DPRINT("Ref p 0x%x PointerCount %d type %x ",
874 Object, Header->PointerCount, PsProcessType);
875 DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
876 }
877 if (Header->Type == PsThreadType)
878 {
879 DPRINT("Deref t 0x%x with PointerCount %d type %x ",
880 Object, Header->PointerCount, PsThreadType);
881 DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
882 }
883
884 if (Header->PointerCount == 0 && !(Header->Flags & OB_FLAG_PERMANENT))
885 {
886 if (Header->Type == PsProcessType)
887 {
888 return STATUS_PROCESS_IS_TERMINATING;
889 }
890 if (Header->Type == PsThreadType)
891 {
892 return STATUS_THREAD_IS_TERMINATING;
893 }
894 return(STATUS_UNSUCCESSFUL);
895 }
896
897 if (1 == InterlockedIncrement(&Header->PointerCount) && !(Header->Flags & OB_FLAG_PERMANENT))
898 {
899 KEBUGCHECK(0);
900 }
901
902 return(STATUS_SUCCESS);
903 }
904
905
906 /*
907 * @implemented
908 */
909 NTSTATUS STDCALL
910 ObOpenObjectByPointer(IN PVOID Object,
911 IN ULONG HandleAttributes,
912 IN PACCESS_STATE PassedAccessState,
913 IN ACCESS_MASK DesiredAccess,
914 IN POBJECT_TYPE ObjectType,
915 IN KPROCESSOR_MODE AccessMode,
916 OUT PHANDLE Handle)
917 {
918 NTSTATUS Status;
919
920 PAGED_CODE();
921
922 DPRINT("ObOpenObjectByPointer()\n");
923
924 Status = ObReferenceObjectByPointer(Object,
925 0,
926 ObjectType,
927 AccessMode);
928 if (!NT_SUCCESS(Status))
929 {
930 return Status;
931 }
932
933 Status = ObpCreateHandle(PsGetCurrentProcess(),
934 Object,
935 DesiredAccess,
936 (BOOLEAN)(HandleAttributes & OBJ_INHERIT),
937 Handle);
938
939 ObDereferenceObject(Object);
940
941 return STATUS_SUCCESS;
942 }
943
944
945 static NTSTATUS
946 ObpDeleteObject(POBJECT_HEADER Header)
947 {
948 PVOID HeaderLocation = Header;
949 POBJECT_HEADER_HANDLE_INFO HandleInfo;
950 POBJECT_HEADER_NAME_INFO NameInfo;
951 POBJECT_HEADER_CREATOR_INFO CreatorInfo;
952
953 DPRINT("ObpDeleteObject(Header %p)\n", Header);
954 if (KeGetCurrentIrql() != PASSIVE_LEVEL)
955 {
956 DPRINT("ObpDeleteObject called at an unsupported IRQL. Use ObpDeleteObjectDpcLevel instead.\n");
957 KEBUGCHECK(0);
958 }
959
960 if (Header->Type != NULL &&
961 Header->Type->TypeInfo.DeleteProcedure != NULL)
962 {
963 Header->Type->TypeInfo.DeleteProcedure(&Header->Body);
964 }
965
966 if (Header->SecurityDescriptor != NULL)
967 {
968 ObpRemoveSecurityDescriptor(Header->SecurityDescriptor);
969 }
970
971 if (HEADER_TO_OBJECT_NAME(Header))
972 {
973 if(HEADER_TO_OBJECT_NAME(Header)->Name.Buffer)
974 {
975 ExFreePool(HEADER_TO_OBJECT_NAME(Header)->Name.Buffer);
976 }
977 }
978 if (Header->ObjectCreateInfo)
979 {
980 ObpReleaseCapturedAttributes(Header->ObjectCreateInfo);
981 ExFreePool(Header->ObjectCreateInfo);
982 }
983
984 /* To find the header, walk backwards from how we allocated */
985 if ((CreatorInfo = HEADER_TO_CREATOR_INFO(Header)))
986 {
987 HeaderLocation = CreatorInfo;
988 }
989 if ((NameInfo = HEADER_TO_OBJECT_NAME(Header)))
990 {
991 HeaderLocation = NameInfo;
992 }
993 if ((HandleInfo = HEADER_TO_HANDLE_INFO(Header)))
994 {
995 HeaderLocation = HandleInfo;
996 }
997
998 DPRINT("ObPerformRetentionChecks() = Freeing object\n");
999 ExFreePool(HeaderLocation);
1000
1001 return(STATUS_SUCCESS);
1002 }
1003
1004
1005 VOID STDCALL
1006 ObpDeleteObjectWorkRoutine (IN PVOID Parameter)
1007 {
1008 PRETENTION_CHECK_PARAMS Params = (PRETENTION_CHECK_PARAMS)Parameter;
1009 /* ULONG Tag; */ /* See below */
1010
1011 ASSERT(Params);
1012 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); /* We need PAGED_CODE somewhere... */
1013
1014 /* Turn this on when we have ExFreePoolWithTag
1015 Tag = Params->ObjectHeader->Type->Tag; */
1016 ObpDeleteObject(Params->ObjectHeader);
1017 ExFreePool(Params);
1018 /* ExFreePoolWithTag(Params, Tag); */
1019 }
1020
1021
1022 STATIC NTSTATUS
1023 ObpDeleteObjectDpcLevel(IN POBJECT_HEADER ObjectHeader,
1024 IN LONG OldPointerCount)
1025 {
1026 #if 0
1027 if (ObjectHeader->PointerCount < 0)
1028 {
1029 CPRINT("Object %p/%p has invalid reference count (%d)\n",
1030 ObjectHeader, HEADER_TO_BODY(ObjectHeader),
1031 ObjectHeader->PointerCount);
1032 KEBUGCHECK(0);
1033 }
1034
1035 if (ObjectHeader->HandleCount < 0)
1036 {
1037 CPRINT("Object %p/%p has invalid handle count (%d)\n",
1038 ObjectHeader, HEADER_TO_BODY(ObjectHeader),
1039 ObjectHeader->HandleCount);
1040 KEBUGCHECK(0);
1041 }
1042 #endif
1043
1044
1045 switch (KeGetCurrentIrql ())
1046 {
1047 case PASSIVE_LEVEL:
1048 return ObpDeleteObject (ObjectHeader);
1049
1050 case APC_LEVEL:
1051 case DISPATCH_LEVEL:
1052 {
1053 PRETENTION_CHECK_PARAMS Params;
1054
1055 /*
1056 We use must succeed pool here because if the allocation fails
1057 then we leak memory.
1058 */
1059 Params = (PRETENTION_CHECK_PARAMS)
1060 ExAllocatePoolWithTag(NonPagedPoolMustSucceed,
1061 sizeof(RETENTION_CHECK_PARAMS),
1062 ObjectHeader->Type->Key);
1063 Params->ObjectHeader = ObjectHeader;
1064 ExInitializeWorkItem(&Params->WorkItem,
1065 ObpDeleteObjectWorkRoutine,
1066 (PVOID)Params);
1067 ExQueueWorkItem(&Params->WorkItem,
1068 CriticalWorkQueue);
1069 }
1070 return STATUS_PENDING;
1071
1072 default:
1073 DPRINT("ObpDeleteObjectDpcLevel called at unsupported "
1074 "IRQL %u!\n", KeGetCurrentIrql());
1075 KEBUGCHECK(0);
1076 return STATUS_UNSUCCESSFUL;
1077 }
1078
1079 return STATUS_SUCCESS;
1080 }
1081
1082
1083 /**********************************************************************
1084 * NAME EXPORTED
1085 * ObfReferenceObject@4
1086 *
1087 * DESCRIPTION
1088 * Increments a given object's reference count and performs
1089 * retention checks.
1090 *
1091 * ARGUMENTS
1092 * ObjectBody = Body of the object.
1093 *
1094 * RETURN VALUE
1095 * None.
1096 *
1097 * @implemented
1098 */
1099 VOID FASTCALL
1100 ObfReferenceObject(IN PVOID Object)
1101 {
1102 POBJECT_HEADER Header;
1103
1104 ASSERT(Object);
1105
1106 Header = BODY_TO_HEADER(Object);
1107
1108 /* No one should be referencing an object once we are deleting it. */
1109 if (InterlockedIncrement(&Header->PointerCount) == 1 && !(Header->Flags & OB_FLAG_PERMANENT))
1110 {
1111 KEBUGCHECK(0);
1112 }
1113
1114 }
1115
1116 /**********************************************************************
1117 * NAME EXPORTED
1118 * ObfDereferenceObject@4
1119 *
1120 * DESCRIPTION
1121 * Decrements a given object's reference count and performs
1122 * retention checks.
1123 *
1124 * ARGUMENTS
1125 * ObjectBody = Body of the object.
1126 *
1127 * RETURN VALUE
1128 * None.
1129 *
1130 * @implemented
1131 */
1132 VOID FASTCALL
1133 ObfDereferenceObject(IN PVOID Object)
1134 {
1135 POBJECT_HEADER Header;
1136 LONG NewPointerCount;
1137 BOOL Permanent;
1138
1139 ASSERT(Object);
1140
1141 /* Extract the object header. */
1142 Header = BODY_TO_HEADER(Object);
1143 Permanent = Header->Flags & OB_FLAG_PERMANENT;
1144
1145 /*
1146 Drop our reference and get the new count so we can tell if this was the
1147 last reference.
1148 */
1149 NewPointerCount = InterlockedDecrement(&Header->PointerCount);
1150 DPRINT("ObfDereferenceObject(0x%x)==%d\n", Object, NewPointerCount);
1151 ASSERT(NewPointerCount >= 0);
1152
1153 /* Check whether the object can now be deleted. */
1154 if (NewPointerCount == 0 &&
1155 !Permanent)
1156 {
1157 ObpDeleteObjectDpcLevel(Header, NewPointerCount);
1158 }
1159 }
1160
1161 VOID
1162 FASTCALL
1163 ObInitializeFastReference(IN PEX_FAST_REF FastRef,
1164 PVOID Object)
1165 {
1166 /* FIXME: Fast Referencing is Unimplemented */
1167 FastRef->Object = Object;
1168 }
1169
1170
1171 PVOID
1172 FASTCALL
1173 ObFastReferenceObject(IN PEX_FAST_REF FastRef)
1174 {
1175 /* FIXME: Fast Referencing is Unimplemented */
1176
1177 /* Do a normal Reference */
1178 ObReferenceObject(FastRef->Object);
1179
1180 /* Return the Object */
1181 return FastRef->Object;
1182 }
1183
1184 VOID
1185 FASTCALL
1186 ObFastDereferenceObject(IN PEX_FAST_REF FastRef,
1187 PVOID Object)
1188 {
1189 /* FIXME: Fast Referencing is Unimplemented */
1190
1191 /* Do a normal Dereference */
1192 ObDereferenceObject(FastRef->Object);
1193 }
1194
1195 PVOID
1196 FASTCALL
1197 ObFastReplaceObject(IN PEX_FAST_REF FastRef,
1198 PVOID Object)
1199 {
1200 PVOID OldObject = FastRef->Object;
1201
1202 /* FIXME: Fast Referencing is Unimplemented */
1203 FastRef->Object = Object;
1204
1205 /* Do a normal Dereference */
1206 ObDereferenceObject(OldObject);
1207
1208 /* Return old Object*/
1209 return OldObject;
1210 }
1211
1212 /**********************************************************************
1213 * NAME EXPORTED
1214 * ObGetObjectPointerCount@4
1215 *
1216 * DESCRIPTION
1217 * Retrieves the pointer(reference) count of the given object.
1218 *
1219 * ARGUMENTS
1220 * ObjectBody = Body of the object.
1221 *
1222 * RETURN VALUE
1223 * Reference count.
1224 *
1225 * @implemented
1226 */
1227 ULONG STDCALL
1228 ObGetObjectPointerCount(PVOID Object)
1229 {
1230 POBJECT_HEADER Header;
1231
1232 PAGED_CODE();
1233
1234 ASSERT(Object);
1235 Header = BODY_TO_HEADER(Object);
1236
1237 return Header->PointerCount;
1238 }
1239
1240
1241 /**********************************************************************
1242 * NAME INTERNAL
1243 * ObGetObjectHandleCount@4
1244 *
1245 * DESCRIPTION
1246 * Retrieves the handle count of the given object.
1247 *
1248 * ARGUMENTS
1249 * ObjectBody = Body of the object.
1250 *
1251 * RETURN VALUE
1252 * Reference count.
1253 */
1254 ULONG
1255 ObGetObjectHandleCount(PVOID Object)
1256 {
1257 POBJECT_HEADER Header;
1258
1259 PAGED_CODE();
1260
1261 ASSERT(Object);
1262 Header = BODY_TO_HEADER(Object);
1263
1264 return Header->HandleCount;
1265 }
1266
1267
1268 /**********************************************************************
1269 * NAME EXPORTED
1270 * ObDereferenceObject@4
1271 *
1272 * DESCRIPTION
1273 * Decrements a given object's reference count and performs
1274 * retention checks.
1275 *
1276 * ARGUMENTS
1277 * ObjectBody = Body of the object.
1278 *
1279 * RETURN VALUE
1280 * None.
1281 *
1282 * @implemented
1283 */
1284
1285 #ifdef ObDereferenceObject
1286 #undef ObDereferenceObject
1287 #endif
1288
1289 VOID STDCALL
1290 ObDereferenceObject(IN PVOID Object)
1291 {
1292 ObfDereferenceObject(Object);
1293 }
1294
1295 /* EOF */