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