1 /* $Id: object.c,v 1.84 2004/10/22 20:43:58 ekohl Exp $
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 * PROGRAMMERS David Welch (welch@cwcom.net), Skywing (skywing@valhallalegends.com)
10 * 09/13/03: Fixed various ObXxx routines to not call retention
11 * checks directly at a raised IRQL.
14 /* INCLUDES *****************************************************************/
18 #include <internal/debug.h>
21 typedef struct _RETENTION_CHECK_PARAMS
23 WORK_QUEUE_ITEM WorkItem
;
24 POBJECT_HEADER ObjectHeader
;
25 } RETENTION_CHECK_PARAMS
, *PRETENTION_CHECK_PARAMS
;
28 /* FUNCTIONS ************************************************************/
30 PVOID
HEADER_TO_BODY(POBJECT_HEADER obj
)
32 return(((char*)obj
)+sizeof(OBJECT_HEADER
)-sizeof(COMMON_BODY_HEADER
));
36 POBJECT_HEADER
BODY_TO_HEADER(PVOID body
)
38 PCOMMON_BODY_HEADER chdr
= (PCOMMON_BODY_HEADER
)body
;
39 return(CONTAINING_RECORD((&(chdr
->Type
)),OBJECT_HEADER
,Type
));
43 /**********************************************************************
55 * Pointer to a unicode string that will contain the
56 * remaining path if the function returns successfully.
57 * The caller must free the buffer after use by calling
58 * RtlFreeUnicodeString ().
61 * Optional pointer to an object type. This is used to
62 * descide if a symbolic link object will be parsed or not.
67 ObFindObject(POBJECT_ATTRIBUTES ObjectAttributes
,
68 PVOID
* ReturnedObject
,
69 PUNICODE_STRING RemainingPath
,
70 POBJECT_TYPE ObjectType
)
75 POBJECT_HEADER CurrentHeader
;
78 UNICODE_STRING PathString
;
80 PUNICODE_STRING ObjectName
;
82 DPRINT("ObFindObject(ObjectAttributes %x, ReturnedObject %x, "
83 "RemainingPath %x)\n",ObjectAttributes
,ReturnedObject
,RemainingPath
);
84 DPRINT("ObjectAttributes->ObjectName %wZ\n",
85 ObjectAttributes
->ObjectName
);
87 RtlInitUnicodeString (RemainingPath
, NULL
);
89 if (ObjectAttributes
->RootDirectory
== NULL
)
91 ObReferenceObjectByPointer(NameSpaceRoot
,
95 CurrentObject
= NameSpaceRoot
;
99 Status
= ObReferenceObjectByHandle(ObjectAttributes
->RootDirectory
,
105 if (!NT_SUCCESS(Status
))
111 ObjectName
= ObjectAttributes
->ObjectName
;
112 if (ObjectName
->Length
== 0 ||
113 ObjectName
->Buffer
[0] == UNICODE_NULL
)
115 *ReturnedObject
= CurrentObject
;
116 return STATUS_SUCCESS
;
119 if (ObjectAttributes
->RootDirectory
== NULL
&&
120 ObjectName
->Buffer
[0] != L
'\\')
122 ObDereferenceObject (CurrentObject
);
123 return STATUS_UNSUCCESSFUL
;
126 /* Create a zero-terminated copy of the object name */
127 PathString
.Length
= ObjectName
->Length
;
128 PathString
.MaximumLength
= ObjectName
->Length
+ sizeof(WCHAR
);
129 PathString
.Buffer
= ExAllocatePool (NonPagedPool
,
130 PathString
.MaximumLength
);
131 if (PathString
.Buffer
== NULL
)
133 ObDereferenceObject (CurrentObject
);
134 return STATUS_INSUFFICIENT_RESOURCES
;
137 RtlCopyMemory (PathString
.Buffer
,
140 PathString
.Buffer
[PathString
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
142 current
= PathString
.Buffer
;
144 RootObject
= CurrentObject
;
145 Attributes
= ObjectAttributes
->Attributes
;
146 if (ObjectType
== ObSymbolicLinkType
)
147 Attributes
|= OBJ_OPENLINK
;
151 DPRINT("current %S\n",current
);
152 CurrentHeader
= BODY_TO_HEADER(CurrentObject
);
154 DPRINT("Current ObjectType %wZ\n",
155 &CurrentHeader
->ObjectType
->TypeName
);
157 if (CurrentHeader
->ObjectType
->Parse
== NULL
)
159 DPRINT("Current object can't parse\n");
162 Status
= CurrentHeader
->ObjectType
->Parse(CurrentObject
,
167 if (Status
== STATUS_REPARSE
)
169 /* reparse the object path */
170 NextObject
= NameSpaceRoot
;
171 current
= PathString
.Buffer
;
173 ObReferenceObjectByPointer(NextObject
,
179 if (NextObject
== NULL
)
183 ObDereferenceObject(CurrentObject
);
184 CurrentObject
= NextObject
;
188 RtlCreateUnicodeString (RemainingPath
, current
);
189 RtlFreeUnicodeString (&PathString
);
190 *ReturnedObject
= CurrentObject
;
192 return STATUS_SUCCESS
;
196 /**********************************************************************
198 * ObQueryNameString@16
209 ObQueryNameString (IN PVOID Object
,
210 OUT POBJECT_NAME_INFORMATION ObjectNameInfo
,
212 OUT PULONG ReturnLength
)
214 POBJECT_NAME_INFORMATION LocalInfo
;
215 POBJECT_HEADER ObjectHeader
;
216 ULONG LocalReturnLength
;
221 if (Length
< sizeof(OBJECT_NAME_INFORMATION
) + sizeof(WCHAR
))
222 return STATUS_INVALID_BUFFER_SIZE
;
224 ObjectNameInfo
->Name
.MaximumLength
= (USHORT
)(Length
- sizeof(OBJECT_NAME_INFORMATION
));
225 ObjectNameInfo
->Name
.Length
= 0;
226 ObjectNameInfo
->Name
.Buffer
=
227 (PWCHAR
)((ULONG_PTR
)ObjectNameInfo
+ sizeof(OBJECT_NAME_INFORMATION
));
228 ObjectNameInfo
->Name
.Buffer
[0] = 0;
230 ObjectHeader
= BODY_TO_HEADER(Object
);
232 if (ObjectHeader
->ObjectType
!= NULL
&&
233 ObjectHeader
->ObjectType
->QueryName
!= NULL
)
235 DPRINT ("Calling %x\n", ObjectHeader
->ObjectType
->QueryName
);
236 Status
= ObjectHeader
->ObjectType
->QueryName (Object
,
241 else if (ObjectHeader
->Name
.Length
> 0 && ObjectHeader
->Name
.Buffer
!= NULL
)
243 DPRINT ("Object does not have a 'QueryName' function\n");
245 if (ObjectHeader
->Parent
== NameSpaceRoot
)
247 DPRINT ("Reached the root directory\n");
248 ObjectNameInfo
->Name
.Length
= 0;
249 ObjectNameInfo
->Name
.Buffer
[0] = 0;
250 Status
= STATUS_SUCCESS
;
252 else if (ObjectHeader
->Parent
!= NULL
)
254 LocalInfo
= ExAllocatePool (NonPagedPool
,
255 sizeof(OBJECT_NAME_INFORMATION
) +
256 MAX_PATH
* sizeof(WCHAR
));
257 if (LocalInfo
== NULL
)
258 return STATUS_INSUFFICIENT_RESOURCES
;
260 Status
= ObQueryNameString (ObjectHeader
->Parent
,
262 MAX_PATH
* sizeof(WCHAR
),
264 if (!NT_SUCCESS (Status
))
266 ExFreePool (LocalInfo
);
270 Status
= RtlAppendUnicodeStringToString (&ObjectNameInfo
->Name
,
273 ExFreePool (LocalInfo
);
275 if (!NT_SUCCESS (Status
))
279 DPRINT ("Object path %wZ\n", &ObjectHeader
->Name
);
280 Status
= RtlAppendUnicodeToString (&ObjectNameInfo
->Name
,
282 if (!NT_SUCCESS (Status
))
285 Status
= RtlAppendUnicodeStringToString (&ObjectNameInfo
->Name
,
286 &ObjectHeader
->Name
);
290 DPRINT ("Object is unnamed\n");
292 ObjectNameInfo
->Name
.MaximumLength
= 0;
293 ObjectNameInfo
->Name
.Length
= 0;
294 ObjectNameInfo
->Name
.Buffer
= NULL
;
296 Status
= STATUS_SUCCESS
;
299 if (NT_SUCCESS (Status
))
301 ObjectNameInfo
->Name
.MaximumLength
=
302 (ObjectNameInfo
->Name
.Length
) ? ObjectNameInfo
->Name
.Length
+ sizeof(WCHAR
) : 0;
304 sizeof(OBJECT_NAME_INFORMATION
) + ObjectNameInfo
->Name
.MaximumLength
;
305 DPRINT ("Returned object path: %wZ\n", &ObjectNameInfo
->Name
);
312 /**********************************************************************
326 ObCreateObject (IN KPROCESSOR_MODE ObjectAttributesAccessMode OPTIONAL
,
327 IN POBJECT_TYPE Type
,
328 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
329 IN KPROCESSOR_MODE AccessMode
,
330 IN OUT PVOID ParseContext OPTIONAL
,
332 IN ULONG PagedPoolCharge OPTIONAL
,
333 IN ULONG NonPagedPoolCharge OPTIONAL
,
337 UNICODE_STRING RemainingPath
;
338 POBJECT_HEADER Header
;
339 POBJECT_HEADER ParentHeader
= NULL
;
341 BOOLEAN ObjectAttached
= FALSE
;
343 PSECURITY_DESCRIPTOR NewSecurityDescriptor
= NULL
;
344 SECURITY_SUBJECT_CONTEXT SubjectContext
;
346 ASSERT_IRQL(APC_LEVEL
);
348 DPRINT("ObCreateObject(Type %p ObjectAttributes %p, Object %p)\n",
349 Type
, ObjectAttributes
, Object
);
353 DPRINT1("Invalid object type!\n");
354 return STATUS_INVALID_PARAMETER
;
357 if (ObjectAttributes
!= NULL
&&
358 ObjectAttributes
->ObjectName
!= NULL
&&
359 ObjectAttributes
->ObjectName
->Buffer
!= NULL
)
361 Status
= ObFindObject(ObjectAttributes
,
365 if (!NT_SUCCESS(Status
))
367 DPRINT("ObFindObject() failed! (Status 0x%x)\n", Status
);
373 RtlInitUnicodeString(&RemainingPath
, NULL
);
376 Header
= (POBJECT_HEADER
)ExAllocatePoolWithTag(NonPagedPool
,
377 OBJECT_ALLOC_SIZE(ObjectSize
),
380 return STATUS_INSUFFICIENT_RESOURCES
;
381 RtlZeroMemory(Header
, OBJECT_ALLOC_SIZE(ObjectSize
));
383 /* Initialize the object header */
384 Header
->HandleCount
= 0;
385 Header
->RefCount
= 1;
386 Header
->ObjectType
= Type
;
387 if (ObjectAttributes
!= NULL
&&
388 ObjectAttributes
->Attributes
& OBJ_PERMANENT
)
390 Header
->Permanent
= TRUE
;
394 Header
->Permanent
= FALSE
;
397 if (ObjectAttributes
!= NULL
&&
398 ObjectAttributes
->Attributes
& OBJ_INHERIT
)
400 Header
->Inherit
= TRUE
;
404 Header
->Inherit
= FALSE
;
407 RtlInitUnicodeString(&(Header
->Name
),NULL
);
411 ParentHeader
= BODY_TO_HEADER(Parent
);
414 if (ParentHeader
!= NULL
&&
415 ParentHeader
->ObjectType
== ObDirectoryType
&&
416 RemainingPath
.Buffer
!= NULL
)
418 NamePtr
= RemainingPath
.Buffer
;
419 if (*NamePtr
== L
'\\')
422 ObpAddEntryDirectory(Parent
,
426 ObjectAttached
= TRUE
;
429 if (Header
->ObjectType
->Create
!= NULL
)
431 DPRINT("Calling %x\n", Header
->ObjectType
->Create
);
432 Status
= Header
->ObjectType
->Create(HEADER_TO_BODY(Header
),
434 RemainingPath
.Buffer
,
436 if (!NT_SUCCESS(Status
))
438 if (ObjectAttached
== TRUE
)
440 ObpRemoveEntryDirectory(Header
);
444 ObDereferenceObject(Parent
);
446 RtlFreeUnicodeString(&Header
->Name
);
447 RtlFreeUnicodeString(&RemainingPath
);
452 RtlFreeUnicodeString(&RemainingPath
);
454 SeCaptureSubjectContext(&SubjectContext
);
456 /* Build the new security descriptor */
457 Status
= SeAssignSecurity((ParentHeader
!= NULL
) ? ParentHeader
->SecurityDescriptor
: NULL
,
458 (ObjectAttributes
!= NULL
) ? ObjectAttributes
->SecurityDescriptor
: NULL
,
459 &NewSecurityDescriptor
,
460 (Header
->ObjectType
== ObDirectoryType
),
462 Header
->ObjectType
->Mapping
,
464 if (NT_SUCCESS(Status
))
466 DPRINT("NewSecurityDescriptor %p\n", NewSecurityDescriptor
);
468 if (Header
->ObjectType
->Security
!= NULL
)
470 /* Call the security method */
471 Status
= Header
->ObjectType
->Security(HEADER_TO_BODY(Header
),
472 AssignSecurityDescriptor
,
474 NewSecurityDescriptor
,
479 /* Assign the security descriptor to the object header */
480 Status
= ObpAddSecurityDescriptor(NewSecurityDescriptor
,
481 &Header
->SecurityDescriptor
);
482 DPRINT("Object security descriptor %p\n", Header
->SecurityDescriptor
);
485 /* Release the new security descriptor */
486 SeDeassignSecurity(&NewSecurityDescriptor
);
489 SeReleaseSubjectContext(&SubjectContext
);
493 *Object
= HEADER_TO_BODY(Header
);
496 return STATUS_SUCCESS
;
501 * FUNCTION: Increments the pointer reference count for a given object
503 * ObjectBody = Object's body
504 * DesiredAccess = Desired access to the object
505 * ObjectType = Points to the object type structure
506 * AccessMode = Type of access check to perform
512 ObReferenceObjectByPointer(IN PVOID Object
,
513 IN ACCESS_MASK DesiredAccess
,
514 IN POBJECT_TYPE ObjectType
,
515 IN KPROCESSOR_MODE AccessMode
)
517 POBJECT_HEADER Header
;
519 DPRINT("ObReferenceObjectByPointer(Object %x, ObjectType %x)\n",
522 Header
= BODY_TO_HEADER(Object
);
524 if (ObjectType
!= NULL
&& Header
->ObjectType
!= ObjectType
)
526 DPRINT("Failed %x (type was %x %S) should be %x %S\n",
529 Header
->ObjectType
->TypeName
.Buffer
,
531 ObjectType
->TypeName
.Buffer
);
532 return(STATUS_UNSUCCESSFUL
);
534 if (Header
->ObjectType
== PsProcessType
)
536 DPRINT("Ref p 0x%x refcount %d type %x ",
537 Object
, Header
->RefCount
, PsProcessType
);
538 DPRINT("eip %x\n", ((PULONG
)&Object
)[-1]);
540 if (Header
->ObjectType
== PsThreadType
)
542 DPRINT("Deref t 0x%x with refcount %d type %x ",
543 Object
, Header
->RefCount
, PsThreadType
);
544 DPRINT("eip %x\n", ((PULONG
)&Object
)[-1]);
547 if (Header
->CloseInProcess
)
549 if (Header
->ObjectType
== PsProcessType
)
551 return STATUS_PROCESS_IS_TERMINATING
;
553 if (Header
->ObjectType
== PsThreadType
)
555 return STATUS_THREAD_IS_TERMINATING
;
557 return(STATUS_UNSUCCESSFUL
);
560 InterlockedIncrement(&Header
->RefCount
);
562 return(STATUS_SUCCESS
);
570 ObOpenObjectByPointer(IN POBJECT Object
,
571 IN ULONG HandleAttributes
,
572 IN PACCESS_STATE PassedAccessState
,
573 IN ACCESS_MASK DesiredAccess
,
574 IN POBJECT_TYPE ObjectType
,
575 IN KPROCESSOR_MODE AccessMode
,
580 DPRINT("ObOpenObjectByPointer()\n");
582 Status
= ObReferenceObjectByPointer(Object
,
586 if (!NT_SUCCESS(Status
))
591 Status
= ObCreateHandle(PsGetCurrentProcess(),
594 (BOOLEAN
)(HandleAttributes
& OBJ_INHERIT
),
597 ObDereferenceObject(Object
);
599 return STATUS_SUCCESS
;
604 ObpDeleteObject(POBJECT_HEADER Header
)
606 DPRINT("ObpDeleteObject(Header %p)\n", Header
);
607 if (KeGetCurrentIrql() != PASSIVE_LEVEL
)
609 DPRINT("ObpDeleteObject called at an unsupported IRQL. Use ObpDeleteObjectDpcLevel instead.\n");
613 if (Header
->SecurityDescriptor
!= NULL
)
615 ObpRemoveSecurityDescriptor(Header
->SecurityDescriptor
);
618 if (Header
->ObjectType
!= NULL
&&
619 Header
->ObjectType
->Delete
!= NULL
)
621 Header
->ObjectType
->Delete(HEADER_TO_BODY(Header
));
624 if (Header
->Name
.Buffer
!= NULL
)
626 ObpRemoveEntryDirectory(Header
);
627 RtlFreeUnicodeString(&Header
->Name
);
630 DPRINT("ObPerformRetentionChecks() = Freeing object\n");
633 return(STATUS_SUCCESS
);
638 ObpDeleteObjectWorkRoutine (IN PVOID Parameter
)
640 PRETENTION_CHECK_PARAMS Params
= (PRETENTION_CHECK_PARAMS
)Parameter
;
641 /* ULONG Tag; */ /* See below */
644 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL
); /* We need PAGED_CODE somewhere... */
646 /* Turn this on when we have ExFreePoolWithTag
647 Tag = Params->ObjectHeader->ObjectType->Tag; */
648 ObpDeleteObject(Params
->ObjectHeader
);
650 /* ExFreePoolWithTag(Params, Tag); */
655 ObpDeleteObjectDpcLevel(IN POBJECT_HEADER ObjectHeader
,
658 if (ObjectHeader
->RefCount
< 0)
660 CPRINT("Object %p/%p has invalid reference count (%d)\n",
661 ObjectHeader
, HEADER_TO_BODY(ObjectHeader
),
662 ObjectHeader
->RefCount
);
666 if (ObjectHeader
->HandleCount
< 0)
668 CPRINT("Object %p/%p has invalid handle count (%d)\n",
669 ObjectHeader
, HEADER_TO_BODY(ObjectHeader
),
670 ObjectHeader
->HandleCount
);
674 if (ObjectHeader
->CloseInProcess
)
677 return STATUS_UNSUCCESSFUL
;
679 ObjectHeader
->CloseInProcess
= TRUE
;
681 switch (KeGetCurrentIrql ())
684 return ObpDeleteObject (ObjectHeader
);
689 PRETENTION_CHECK_PARAMS Params
;
692 We use must succeed pool here because if the allocation fails
695 Params
= (PRETENTION_CHECK_PARAMS
)
696 ExAllocatePoolWithTag(NonPagedPoolMustSucceed
,
697 sizeof(RETENTION_CHECK_PARAMS
),
698 ObjectHeader
->ObjectType
->Tag
);
699 Params
->ObjectHeader
= ObjectHeader
;
700 ExInitializeWorkItem(&Params
->WorkItem
,
701 ObpDeleteObjectWorkRoutine
,
703 ExQueueWorkItem(&Params
->WorkItem
,
706 return STATUS_PENDING
;
709 DPRINT("ObpDeleteObjectDpcLevel called at unsupported "
710 "IRQL %u!\n", KeGetCurrentIrql());
712 return STATUS_UNSUCCESSFUL
;
715 return STATUS_SUCCESS
;
719 /**********************************************************************
721 * ObfReferenceObject@4
724 * Increments a given object's reference count and performs
728 * ObjectBody = Body of the object.
736 ObfReferenceObject(IN PVOID Object
)
738 POBJECT_HEADER Header
;
742 Header
= BODY_TO_HEADER(Object
);
744 /* No one should be referencing an object once we are deleting it. */
745 if (Header
->CloseInProcess
)
750 (VOID
)InterlockedIncrement(&Header
->RefCount
);
754 /**********************************************************************
756 * ObfDereferenceObject@4
759 * Decrements a given object's reference count and performs
763 * ObjectBody = Body of the object.
771 ObfDereferenceObject(IN PVOID Object
)
773 POBJECT_HEADER Header
;
780 /* Extract the object header. */
781 Header
= BODY_TO_HEADER(Object
);
782 Permanent
= Header
->Permanent
;
783 HandleCount
= Header
->HandleCount
;
786 Drop our reference and get the new count so we can tell if this was the
789 NewRefCount
= InterlockedDecrement(&Header
->RefCount
);
790 ASSERT(NewRefCount
>= 0);
792 /* Check whether the object can now be deleted. */
793 if (NewRefCount
== 0 &&
797 ObpDeleteObjectDpcLevel(Header
, NewRefCount
);
802 /**********************************************************************
804 * ObGetObjectPointerCount@4
807 * Retrieves the pointer(reference) count of the given object.
810 * ObjectBody = Body of the object.
818 ObGetObjectPointerCount(PVOID Object
)
820 POBJECT_HEADER Header
;
823 Header
= BODY_TO_HEADER(Object
);
825 return Header
->RefCount
;
829 /**********************************************************************
831 * ObGetObjectHandleCount@4
834 * Retrieves the handle count of the given object.
837 * ObjectBody = Body of the object.
843 ObGetObjectHandleCount(PVOID Object
)
845 POBJECT_HEADER Header
;
848 Header
= BODY_TO_HEADER(Object
);
850 return Header
->HandleCount
;
854 /**********************************************************************
856 * ObDereferenceObject@4
859 * Decrements a given object's reference count and performs
863 * ObjectBody = Body of the object.
871 #ifdef ObDereferenceObject
872 #undef ObDereferenceObject
876 ObDereferenceObject(IN PVOID Object
)
878 ObfDereferenceObject(Object
);