62ab62f7af3a3959d0941350fb17e9f47ecd9a85
[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->SecurityDescriptor != NULL)
805 {
806 ObpRemoveSecurityDescriptor(Header->SecurityDescriptor);
807 }
808
809 if (Header->NameInfo && Header->NameInfo->Name.Buffer)
810 {
811 ExFreePool(Header->NameInfo->Name.Buffer);
812 }
813
814 if (Header->ObjectType != NULL &&
815 Header->ObjectType->TypeInfo.DeleteProcedure != NULL)
816 {
817 Header->ObjectType->TypeInfo.DeleteProcedure(HEADER_TO_BODY(Header));
818 }
819
820 DPRINT("ObPerformRetentionChecks() = Freeing object\n");
821 ExFreePool(Header);
822
823 return(STATUS_SUCCESS);
824 }
825
826
827 VOID STDCALL
828 ObpDeleteObjectWorkRoutine (IN PVOID Parameter)
829 {
830 PRETENTION_CHECK_PARAMS Params = (PRETENTION_CHECK_PARAMS)Parameter;
831 /* ULONG Tag; */ /* See below */
832
833 ASSERT(Params);
834 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); /* We need PAGED_CODE somewhere... */
835
836 /* Turn this on when we have ExFreePoolWithTag
837 Tag = Params->ObjectHeader->ObjectType->Tag; */
838 ObpDeleteObject(Params->ObjectHeader);
839 ExFreePool(Params);
840 /* ExFreePoolWithTag(Params, Tag); */
841 }
842
843
844 STATIC NTSTATUS
845 ObpDeleteObjectDpcLevel(IN POBJECT_HEADER ObjectHeader,
846 IN LONG OldRefCount)
847 {
848 #if 0
849 if (ObjectHeader->RefCount < 0)
850 {
851 CPRINT("Object %p/%p has invalid reference count (%d)\n",
852 ObjectHeader, HEADER_TO_BODY(ObjectHeader),
853 ObjectHeader->RefCount);
854 KEBUGCHECK(0);
855 }
856
857 if (ObjectHeader->HandleCount < 0)
858 {
859 CPRINT("Object %p/%p has invalid handle count (%d)\n",
860 ObjectHeader, HEADER_TO_BODY(ObjectHeader),
861 ObjectHeader->HandleCount);
862 KEBUGCHECK(0);
863 }
864 #endif
865
866
867 switch (KeGetCurrentIrql ())
868 {
869 case PASSIVE_LEVEL:
870 return ObpDeleteObject (ObjectHeader);
871
872 case APC_LEVEL:
873 case DISPATCH_LEVEL:
874 {
875 PRETENTION_CHECK_PARAMS Params;
876
877 /*
878 We use must succeed pool here because if the allocation fails
879 then we leak memory.
880 */
881 Params = (PRETENTION_CHECK_PARAMS)
882 ExAllocatePoolWithTag(NonPagedPoolMustSucceed,
883 sizeof(RETENTION_CHECK_PARAMS),
884 ObjectHeader->ObjectType->Key);
885 Params->ObjectHeader = ObjectHeader;
886 ExInitializeWorkItem(&Params->WorkItem,
887 ObpDeleteObjectWorkRoutine,
888 (PVOID)Params);
889 ExQueueWorkItem(&Params->WorkItem,
890 CriticalWorkQueue);
891 }
892 return STATUS_PENDING;
893
894 default:
895 DPRINT("ObpDeleteObjectDpcLevel called at unsupported "
896 "IRQL %u!\n", KeGetCurrentIrql());
897 KEBUGCHECK(0);
898 return STATUS_UNSUCCESSFUL;
899 }
900
901 return STATUS_SUCCESS;
902 }
903
904
905 /**********************************************************************
906 * NAME EXPORTED
907 * ObfReferenceObject@4
908 *
909 * DESCRIPTION
910 * Increments a given object's reference count and performs
911 * retention checks.
912 *
913 * ARGUMENTS
914 * ObjectBody = Body of the object.
915 *
916 * RETURN VALUE
917 * None.
918 *
919 * @implemented
920 */
921 VOID FASTCALL
922 ObfReferenceObject(IN PVOID Object)
923 {
924 POBJECT_HEADER Header;
925
926 ASSERT(Object);
927
928 Header = BODY_TO_HEADER(Object);
929
930 /* No one should be referencing an object once we are deleting it. */
931 if (InterlockedIncrement(&Header->RefCount) == 1 && !Header->Permanent)
932 {
933 KEBUGCHECK(0);
934 }
935
936 }
937
938 /**********************************************************************
939 * NAME EXPORTED
940 * ObfDereferenceObject@4
941 *
942 * DESCRIPTION
943 * Decrements a given object's reference count and performs
944 * retention checks.
945 *
946 * ARGUMENTS
947 * ObjectBody = Body of the object.
948 *
949 * RETURN VALUE
950 * None.
951 *
952 * @implemented
953 */
954 VOID FASTCALL
955 ObfDereferenceObject(IN PVOID Object)
956 {
957 POBJECT_HEADER Header;
958 LONG NewRefCount;
959 BOOL Permanent;
960
961 ASSERT(Object);
962
963 /* Extract the object header. */
964 Header = BODY_TO_HEADER(Object);
965 Permanent = Header->Permanent;
966
967 /*
968 Drop our reference and get the new count so we can tell if this was the
969 last reference.
970 */
971 NewRefCount = InterlockedDecrement(&Header->RefCount);
972 DPRINT("ObfDereferenceObject(0x%x)==%d\n", Object, NewRefCount);
973 ASSERT(NewRefCount >= 0);
974
975 /* Check whether the object can now be deleted. */
976 if (NewRefCount == 0 &&
977 !Permanent)
978 {
979 ObpDeleteObjectDpcLevel(Header, NewRefCount);
980 }
981 }
982
983 VOID
984 FASTCALL
985 ObInitializeFastReference(IN PEX_FAST_REF FastRef,
986 PVOID Object)
987 {
988 /* FIXME: Fast Referencing is Unimplemented */
989 FastRef->Object = Object;
990 }
991
992
993 PVOID
994 FASTCALL
995 ObFastReferenceObject(IN PEX_FAST_REF FastRef)
996 {
997 /* FIXME: Fast Referencing is Unimplemented */
998
999 /* Do a normal Reference */
1000 ObReferenceObject(FastRef->Object);
1001
1002 /* Return the Object */
1003 return FastRef->Object;
1004 }
1005
1006 VOID
1007 FASTCALL
1008 ObFastDereferenceObject(IN PEX_FAST_REF FastRef,
1009 PVOID Object)
1010 {
1011 /* FIXME: Fast Referencing is Unimplemented */
1012
1013 /* Do a normal Dereference */
1014 ObDereferenceObject(FastRef->Object);
1015 }
1016
1017 PVOID
1018 FASTCALL
1019 ObFastReplaceObject(IN PEX_FAST_REF FastRef,
1020 PVOID Object)
1021 {
1022 PVOID OldObject = FastRef->Object;
1023
1024 /* FIXME: Fast Referencing is Unimplemented */
1025 FastRef->Object = Object;
1026
1027 /* Do a normal Dereference */
1028 ObDereferenceObject(OldObject);
1029
1030 /* Return old Object*/
1031 return OldObject;
1032 }
1033
1034 /**********************************************************************
1035 * NAME EXPORTED
1036 * ObGetObjectPointerCount@4
1037 *
1038 * DESCRIPTION
1039 * Retrieves the pointer(reference) count of the given object.
1040 *
1041 * ARGUMENTS
1042 * ObjectBody = Body of the object.
1043 *
1044 * RETURN VALUE
1045 * Reference count.
1046 *
1047 * @implemented
1048 */
1049 ULONG STDCALL
1050 ObGetObjectPointerCount(PVOID Object)
1051 {
1052 POBJECT_HEADER Header;
1053
1054 PAGED_CODE();
1055
1056 ASSERT(Object);
1057 Header = BODY_TO_HEADER(Object);
1058
1059 return Header->RefCount;
1060 }
1061
1062
1063 /**********************************************************************
1064 * NAME INTERNAL
1065 * ObGetObjectHandleCount@4
1066 *
1067 * DESCRIPTION
1068 * Retrieves the handle count of the given object.
1069 *
1070 * ARGUMENTS
1071 * ObjectBody = Body of the object.
1072 *
1073 * RETURN VALUE
1074 * Reference count.
1075 */
1076 ULONG
1077 ObGetObjectHandleCount(PVOID Object)
1078 {
1079 POBJECT_HEADER Header;
1080
1081 PAGED_CODE();
1082
1083 ASSERT(Object);
1084 Header = BODY_TO_HEADER(Object);
1085
1086 return Header->HandleCount;
1087 }
1088
1089
1090 /**********************************************************************
1091 * NAME EXPORTED
1092 * ObDereferenceObject@4
1093 *
1094 * DESCRIPTION
1095 * Decrements a given object's reference count and performs
1096 * retention checks.
1097 *
1098 * ARGUMENTS
1099 * ObjectBody = Body of the object.
1100 *
1101 * RETURN VALUE
1102 * None.
1103 *
1104 * @implemented
1105 */
1106
1107 #ifdef ObDereferenceObject
1108 #undef ObDereferenceObject
1109 #endif
1110
1111 VOID STDCALL
1112 ObDereferenceObject(IN PVOID Object)
1113 {
1114 ObfDereferenceObject(Object);
1115 }
1116
1117 /* EOF */