2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ob/oblife.c
5 * PURPOSE: Manages the lifetime of an Object, including its creation,
6 * and deletion, as well as setting or querying any of its
7 * information while it is active. Since Object Types are also
8 * Objects, those are also managed here.
9 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
11 * Thomas Weidenmueller (w3seek@reactos.org)
14 /* INCLUDES ******************************************************************/
20 extern ULONG NtGlobalFlag
;
22 POBJECT_TYPE ObpTypeObjectType
= NULL
;
23 KEVENT ObpDefaultObject
;
24 KGUARDED_MUTEX ObpDeviceMapLock
;
26 GENERAL_LOOKASIDE ObpNameBufferLookasideList
, ObpCreateInfoLookasideList
;
28 WORK_QUEUE_ITEM ObpReaperWorkItem
;
29 volatile PVOID ObpReaperList
;
31 ULONG ObpObjectsCreated
, ObpObjectsWithName
, ObpObjectsWithPoolQuota
;
32 ULONG ObpObjectsWithHandleDB
, ObpObjectsWithCreatorInfo
;
33 POBJECT_TYPE ObpObjectTypes
[32];
35 /* PRIVATE FUNCTIONS *********************************************************/
39 ObpDeallocateObject(IN PVOID Object
)
42 POBJECT_HEADER Header
;
43 POBJECT_TYPE ObjectType
;
44 POBJECT_HEADER_HANDLE_INFO HandleInfo
;
45 POBJECT_HEADER_NAME_INFO NameInfo
;
46 POBJECT_HEADER_CREATOR_INFO CreatorInfo
;
47 POBJECT_HEADER_QUOTA_INFO QuotaInfo
;
48 ULONG PagedPoolCharge
, NonPagedPoolCharge
;
51 /* Get the header and assume this is what we'll free */
52 Header
= OBJECT_TO_OBJECT_HEADER(Object
);
53 ObjectType
= Header
->Type
;
54 HeaderLocation
= Header
;
56 /* To find the header, walk backwards from how we allocated */
57 if ((CreatorInfo
= OBJECT_HEADER_TO_CREATOR_INFO(Header
)))
59 HeaderLocation
= CreatorInfo
;
61 if ((NameInfo
= OBJECT_HEADER_TO_NAME_INFO(Header
)))
63 HeaderLocation
= NameInfo
;
65 if ((HandleInfo
= OBJECT_HEADER_TO_HANDLE_INFO(Header
)))
67 HeaderLocation
= HandleInfo
;
69 if ((QuotaInfo
= OBJECT_HEADER_TO_QUOTA_INFO(Header
)))
71 HeaderLocation
= QuotaInfo
;
74 /* Decrease the total */
75 InterlockedDecrement((PLONG
)&ObjectType
->TotalNumberOfObjects
);
77 /* Check if we have create info */
78 if (Header
->Flags
& OB_FLAG_CREATE_INFO
)
80 /* Double-check that it exists */
81 if (Header
->ObjectCreateInfo
)
84 ObpFreeObjectCreateInformation(Header
->ObjectCreateInfo
);
85 Header
->ObjectCreateInfo
= NULL
;
90 /* Check if it has a quota block */
91 if (Header
->QuotaBlockCharged
)
93 /* Check if we have quota information */
96 /* Get charges from quota information */
97 PagedPoolCharge
= QuotaInfo
->PagedPoolCharge
+
98 QuotaInfo
->SecurityDescriptorCharge
;
99 NonPagedPoolCharge
= QuotaInfo
->NonPagedPoolCharge
;
103 /* Get charges from object type */
104 PagedPoolCharge
= ObjectType
->TypeInfo
.DefaultPagedPoolCharge
;
105 NonPagedPoolCharge
= ObjectType
->
106 TypeInfo
.DefaultNonPagedPoolCharge
;
108 /* Add the SD charge too */
109 if (Header
->Flags
& OB_FLAG_SECURITY
) PagedPoolCharge
+= 2048;
112 /* Return the quota */
113 DPRINT("FIXME: Should return quotas: %lx %lx\n", PagedPoolCharge
, NonPagedPoolCharge
);
115 PsReturnSharedPoolQuota(ObjectHeader
->QuotaBlockCharged
,
123 /* Check if a handle database was active */
124 if ((HandleInfo
) && !(Header
->Flags
& OB_FLAG_SINGLE_PROCESS
))
127 ExFreePool(HandleInfo
->HandleCountDatabase
);
128 HandleInfo
->HandleCountDatabase
= NULL
;
131 /* Check if we have a name */
132 if ((NameInfo
) && (NameInfo
->Name
.Buffer
))
135 ExFreePool(NameInfo
->Name
.Buffer
);
136 NameInfo
->Name
.Buffer
= NULL
;
139 /* Catch invalid access */
140 Header
->Type
= (POBJECT_TYPE
)(ULONG_PTR
)0xBAADB0B0BAADB0B0ULL
;
142 /* Free the object using the same allocation tag */
143 ExFreePoolWithTag(HeaderLocation
, ObjectType
->Key
);
148 ObpDeleteObject(IN PVOID Object
,
149 IN BOOLEAN CalledFromWorkerThread
)
151 POBJECT_HEADER Header
;
152 POBJECT_TYPE ObjectType
;
153 POBJECT_HEADER_NAME_INFO NameInfo
;
154 POBJECT_HEADER_CREATOR_INFO CreatorInfo
;
158 /* Get the header and type */
159 Header
= OBJECT_TO_OBJECT_HEADER(Object
);
160 ObjectType
= Header
->Type
;
162 /* Get creator and name information */
163 NameInfo
= OBJECT_HEADER_TO_NAME_INFO(Header
);
164 CreatorInfo
= OBJECT_HEADER_TO_CREATOR_INFO(Header
);
166 /* Check if the object is on a type list */
167 if ((CreatorInfo
) && !(IsListEmpty(&CreatorInfo
->TypeList
)))
169 /* Lock the object type */
170 ObpEnterObjectTypeMutex(ObjectType
);
172 /* Remove the object from the type list */
173 RemoveEntryList(&CreatorInfo
->TypeList
);
175 /* Release the lock */
176 ObpLeaveObjectTypeMutex(ObjectType
);
179 /* Check if we have a name */
180 if ((NameInfo
) && (NameInfo
->Name
.Buffer
))
183 ExFreePool(NameInfo
->Name
.Buffer
);
184 RtlInitEmptyUnicodeString(&NameInfo
->Name
, NULL
, 0);
187 /* Check if we have a security descriptor */
188 if (Header
->SecurityDescriptor
)
190 /* Call the security procedure to delete it */
191 ObpCalloutStart(&CalloutIrql
);
192 ObjectType
->TypeInfo
.SecurityProcedure(Object
,
193 DeleteSecurityDescriptor
,
197 &Header
->SecurityDescriptor
,
200 ObpCalloutEnd(CalloutIrql
, "Security", ObjectType
, Object
);
203 /* Check if we have a delete procedure */
204 if (ObjectType
->TypeInfo
.DeleteProcedure
)
206 /* Save whether we were deleted from worker thread or not */
207 if (!CalledFromWorkerThread
) Header
->Flags
|= OB_FLAG_DEFER_DELETE
;
210 ObpCalloutStart(&CalloutIrql
);
211 ObjectType
->TypeInfo
.DeleteProcedure(Object
);
212 ObpCalloutEnd(CalloutIrql
, "Delete", ObjectType
, Object
);
215 /* Now de-allocate all object members */
216 ObpDeallocateObject(Object
);
221 ObpReapObject(IN PVOID Parameter
)
223 POBJECT_HEADER ReapObject
, NextObject
;
228 /* Get the reap object */
229 ReapObject
= InterlockedExchangePointer(&ObpReaperList
, (PVOID
)1);
231 /* Start deletion loop */
234 /* Get the next object */
235 NextObject
= ReapObject
->NextToFree
;
237 /* Delete the object */
238 ObpDeleteObject(&ReapObject
->Body
, TRUE
);
240 /* Move to the next one */
241 ReapObject
= NextObject
;
242 } while ((ReapObject
) && (ReapObject
!= (PVOID
)1));
243 } while ((ObpReaperList
!= (PVOID
)1) ||
244 (InterlockedCompareExchange((PLONG
)&ObpReaperList
, 0, 1) != 1));
248 * @name ObpSetPermanentObject
250 * The ObpSetPermanentObject routine makes an sets or clears the permanent
251 * flag of an object, thus making it either permanent or temporary.
254 * Pointer to the object to make permanent or temporary.
257 * Flag specifying which operation to perform.
261 * @remarks If the object is being made temporary, then it will be checked
262 * as a candidate for immediate removal from the namespace.
267 ObpSetPermanentObject(IN PVOID ObjectBody
,
268 IN BOOLEAN Permanent
)
270 POBJECT_HEADER ObjectHeader
;
273 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(ObjectBody
);
275 /* Acquire object lock */
276 ObpAcquireObjectLock(ObjectHeader
);
278 /* Check what we're doing to it */
281 /* Set it to permanent */
282 ObjectHeader
->Flags
|= OB_FLAG_PERMANENT
;
284 /* Release the lock */
285 ObpReleaseObjectLock(ObjectHeader
);
289 /* Remove the flag */
290 ObjectHeader
->Flags
&= ~OB_FLAG_PERMANENT
;
292 /* Release the lock */
293 ObpReleaseObjectLock(ObjectHeader
);
295 /* Check if we should delete the object now */
296 ObpDeleteNameCheck(ObjectBody
);
302 ObpAllocateObjectNameBuffer(IN ULONG Length
,
303 IN BOOLEAN UseLookaside
,
304 IN OUT PUNICODE_STRING ObjectName
)
309 /* Set the maximum length to the length plus the terminator */
310 MaximumLength
= Length
+ sizeof(UNICODE_NULL
);
312 /* Check if we should use the lookaside buffer */
313 if (!(UseLookaside
) || (MaximumLength
> OBP_NAME_LOOKASIDE_MAX_SIZE
))
315 /* Nope, allocate directly from pool */
316 /* Since we later use MaximumLength to detect that we're not allocating
317 * from a list, we need at least MaximumLength + sizeof(UNICODE_NULL)
320 * People do call this with UseLookasideList FALSE so the distinction
323 if (MaximumLength
<= OBP_NAME_LOOKASIDE_MAX_SIZE
)
325 MaximumLength
= OBP_NAME_LOOKASIDE_MAX_SIZE
+ sizeof(UNICODE_NULL
);
327 Buffer
= ExAllocatePoolWithTag(PagedPool
,
333 /* Allocate from the lookaside */
334 MaximumLength
= OBP_NAME_LOOKASIDE_MAX_SIZE
;
335 Buffer
= ObpAllocateObjectCreateInfoBuffer(LookasideNameBufferList
);
338 /* Setup the string */
339 ObjectName
->MaximumLength
= (USHORT
)MaximumLength
;
340 ObjectName
->Length
= (USHORT
)Length
;
341 ObjectName
->Buffer
= Buffer
;
347 ObpFreeObjectNameBuffer(IN PUNICODE_STRING Name
)
349 PVOID Buffer
= Name
->Buffer
;
351 /* We know this is a pool-allocation if the size doesn't match */
352 if (Name
->MaximumLength
!= OBP_NAME_LOOKASIDE_MAX_SIZE
)
355 * Free it from the pool.
357 * We cannot use here ExFreePoolWithTag(..., OB_NAME_TAG); , because
358 * the object name may have been massaged during operation by different
359 * object parse routines. If the latter ones have to resolve a symbolic
360 * link (e.g. as is done by CmpParseKey() and CmpGetSymbolicLink()),
361 * the original object name is freed and re-allocated from the pool,
362 * possibly with a different pool tag. At the end of the day, the new
363 * object name can be reallocated and completely different, but we
364 * should still be able to free it!
370 /* Otherwise, free from the lookaside */
371 ObpFreeCapturedAttributes(Buffer
, LookasideNameBufferList
);
377 ObpCaptureObjectName(IN OUT PUNICODE_STRING CapturedName
,
378 IN PUNICODE_STRING ObjectName
,
379 IN KPROCESSOR_MODE AccessMode
,
380 IN BOOLEAN UseLookaside
)
382 NTSTATUS Status
= STATUS_SUCCESS
;
384 PWCHAR _SEH2_VOLATILE StringBuffer
= NULL
;
385 UNICODE_STRING LocalName
;
388 /* Initialize the Input String */
389 RtlInitEmptyUnicodeString(CapturedName
, NULL
, 0);
391 /* Protect everything */
394 /* Check if we came from user mode */
395 if (AccessMode
!= KernelMode
)
397 /* First Probe the String */
398 LocalName
= ProbeForReadUnicodeString(ObjectName
);
399 ProbeForRead(LocalName
.Buffer
, LocalName
.Length
, sizeof(WCHAR
));
403 /* No probing needed */
404 LocalName
= *ObjectName
;
407 /* Make sure there really is a string */
408 StringLength
= LocalName
.Length
;
411 /* Check that the size is a valid WCHAR multiple */
412 if ((StringLength
& (sizeof(WCHAR
) - 1)) ||
413 /* Check that the NULL-termination below will work */
414 (StringLength
== (MAXUSHORT
- sizeof(UNICODE_NULL
) + 1)))
416 /* PS: Please keep the checks above expanded for clarity */
417 Status
= STATUS_OBJECT_NAME_INVALID
;
421 /* Allocate the string buffer */
422 StringBuffer
= ObpAllocateObjectNameBuffer(StringLength
,
427 /* Set failure code */
428 Status
= STATUS_INSUFFICIENT_RESOURCES
;
433 RtlCopyMemory(StringBuffer
, LocalName
.Buffer
, StringLength
);
434 StringBuffer
[StringLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
439 _SEH2_EXCEPT(ExSystemExceptionFilter())
441 /* Handle exception and free the string buffer */
442 Status
= _SEH2_GetExceptionCode();
445 ObpFreeObjectNameBuffer(CapturedName
);
456 ObpCaptureObjectCreateInformation(IN POBJECT_ATTRIBUTES ObjectAttributes
,
457 IN KPROCESSOR_MODE AccessMode
,
458 IN KPROCESSOR_MODE CreatorMode
,
459 IN BOOLEAN AllocateFromLookaside
,
460 IN POBJECT_CREATE_INFORMATION ObjectCreateInfo
,
461 OUT PUNICODE_STRING ObjectName
)
463 ULONG SdCharge
, QuotaInfoSize
;
464 NTSTATUS Status
= STATUS_SUCCESS
;
465 PSECURITY_DESCRIPTOR SecurityDescriptor
;
466 PSECURITY_QUALITY_OF_SERVICE SecurityQos
;
467 PUNICODE_STRING LocalObjectName
= NULL
;
470 /* Zero out the Capture Data */
471 RtlZeroMemory(ObjectCreateInfo
, sizeof(OBJECT_CREATE_INFORMATION
));
473 /* SEH everything here for protection */
476 /* Check if we got attributes */
477 if (ObjectAttributes
)
479 /* Check if we're in user mode */
480 if (AccessMode
!= KernelMode
)
482 /* Probe the attributes */
483 ProbeForRead(ObjectAttributes
,
484 sizeof(OBJECT_ATTRIBUTES
),
488 /* Validate the Size and Attributes */
489 if ((ObjectAttributes
->Length
!= sizeof(OBJECT_ATTRIBUTES
)) ||
490 (ObjectAttributes
->Attributes
& ~OBJ_VALID_KERNEL_ATTRIBUTES
))
492 /* Invalid combination, fail */
493 _SEH2_YIELD(return STATUS_INVALID_PARAMETER
);
496 /* Set some Create Info and do not allow user-mode kernel handles */
497 ObjectCreateInfo
->RootDirectory
= ObjectAttributes
->RootDirectory
;
498 ObjectCreateInfo
->Attributes
= ObjectAttributes
->Attributes
& OBJ_VALID_KERNEL_ATTRIBUTES
;
499 if (CreatorMode
!= KernelMode
) ObjectCreateInfo
->Attributes
&= ~OBJ_KERNEL_HANDLE
;
500 LocalObjectName
= ObjectAttributes
->ObjectName
;
501 SecurityDescriptor
= ObjectAttributes
->SecurityDescriptor
;
502 SecurityQos
= ObjectAttributes
->SecurityQualityOfService
;
504 /* Check if we have a security descriptor */
505 if (SecurityDescriptor
)
507 /* Capture it. Note: This has an implicit memory barrier due
508 to the function call, so cleanup is safe here.) */
509 Status
= SeCaptureSecurityDescriptor(SecurityDescriptor
,
515 if (!NT_SUCCESS(Status
))
517 /* Capture failed, quit */
518 ObjectCreateInfo
->SecurityDescriptor
= NULL
;
519 _SEH2_YIELD(return Status
);
523 * By default, assume a SD size of 1024 and allow twice its
525 * If SD size happen to be bigger than that, then allow it
528 SeComputeQuotaInformationSize(ObjectCreateInfo
->SecurityDescriptor
,
530 if ((2 * QuotaInfoSize
) > 2048)
532 SdCharge
= 2 * QuotaInfoSize
;
535 /* Save the probe mode and security descriptor size */
536 ObjectCreateInfo
->SecurityDescriptorCharge
= SdCharge
;
537 ObjectCreateInfo
->ProbeMode
= AccessMode
;
540 /* Check if we have QoS */
543 /* Check if we came from user mode */
544 if (AccessMode
!= KernelMode
)
546 /* Validate the QoS */
547 ProbeForRead(SecurityQos
,
548 sizeof(SECURITY_QUALITY_OF_SERVICE
),
553 ObjectCreateInfo
->SecurityQualityOfService
= *SecurityQos
;
554 ObjectCreateInfo
->SecurityQos
=
555 &ObjectCreateInfo
->SecurityQualityOfService
;
560 /* We don't have a name */
561 LocalObjectName
= NULL
;
564 _SEH2_EXCEPT(ExSystemExceptionFilter())
566 /* Cleanup and return the exception code */
567 ObpReleaseObjectCreateInformation(ObjectCreateInfo
);
568 _SEH2_YIELD(return _SEH2_GetExceptionCode());
572 /* Now check if the Object Attributes had an Object Name */
575 Status
= ObpCaptureObjectName(ObjectName
,
578 AllocateFromLookaside
);
582 /* Clear the string */
583 RtlInitEmptyUnicodeString(ObjectName
, NULL
, 0);
585 /* It cannot have specified a Root Directory */
586 if (ObjectCreateInfo
->RootDirectory
)
588 Status
= STATUS_OBJECT_NAME_INVALID
;
592 /* Cleanup if we failed */
593 if (!NT_SUCCESS(Status
))
595 ObpReleaseObjectCreateInformation(ObjectCreateInfo
);
598 /* Return status to caller */
604 ObFreeObjectCreateInfoBuffer(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo
)
606 /* Call the macro. We use this function to isolate Ob internals from Io */
607 ObpFreeCapturedAttributes(ObjectCreateInfo
, LookasideCreateInfoList
);
612 ObpAllocateObject(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo
,
613 IN PUNICODE_STRING ObjectName
,
614 IN POBJECT_TYPE ObjectType
,
616 IN KPROCESSOR_MODE PreviousMode
,
617 IN POBJECT_HEADER
*ObjectHeader
)
619 POBJECT_HEADER Header
;
620 ULONG QuotaSize
, HandleSize
, NameSize
, CreatorSize
;
621 POBJECT_HEADER_HANDLE_INFO HandleInfo
;
622 POBJECT_HEADER_NAME_INFO NameInfo
;
623 POBJECT_HEADER_CREATOR_INFO CreatorInfo
;
624 POBJECT_HEADER_QUOTA_INFO QuotaInfo
;
633 /* Check if we don't have an Object Type yet */
636 /* Use default tag and non-paged pool */
637 PoolType
= NonPagedPool
;
642 /* Use the pool and tag given */
643 PoolType
= ObjectType
->TypeInfo
.PoolType
;
644 Tag
= ObjectType
->Key
;
647 /* Check if we have no create information (ie: we're an object type) */
648 if (!ObjectCreateInfo
)
651 QuotaSize
= HandleSize
= 0;
652 NameSize
= sizeof(OBJECT_HEADER_NAME_INFO
);
653 CreatorSize
= sizeof(OBJECT_HEADER_CREATOR_INFO
);
657 /* Check if we have quota */
658 if ((((ObjectCreateInfo
->PagedPoolCharge
!=
659 ObjectType
->TypeInfo
.DefaultPagedPoolCharge
) ||
660 (ObjectCreateInfo
->NonPagedPoolCharge
!=
661 ObjectType
->TypeInfo
.DefaultNonPagedPoolCharge
) ||
662 (ObjectCreateInfo
->SecurityDescriptorCharge
> 2048)) &&
663 (PsGetCurrentProcess() != PsInitialSystemProcess
)) ||
664 (ObjectCreateInfo
->Attributes
& OBJ_EXCLUSIVE
))
667 QuotaSize
= sizeof(OBJECT_HEADER_QUOTA_INFO
);
668 ObpObjectsWithPoolQuota
++;
676 /* Check if we have a handle database */
677 if (ObjectType
->TypeInfo
.MaintainHandleCount
)
679 /* Set handle database size */
680 HandleSize
= sizeof(OBJECT_HEADER_HANDLE_INFO
);
681 ObpObjectsWithHandleDB
++;
689 /* Check if the Object has a name */
690 if (ObjectName
->Buffer
)
693 NameSize
= sizeof(OBJECT_HEADER_NAME_INFO
);
694 ObpObjectsWithName
++;
702 /* Check if the Object maintains type lists */
703 if (ObjectType
->TypeInfo
.MaintainTypeList
)
705 /* Set owner/creator size */
706 CreatorSize
= sizeof(OBJECT_HEADER_CREATOR_INFO
);
707 ObpObjectsWithCreatorInfo
++;
716 /* Set final header size */
717 FinalSize
= QuotaSize
+
721 FIELD_OFFSET(OBJECT_HEADER
, Body
);
723 /* Allocate memory for the Object and Header */
724 Header
= ExAllocatePoolWithTag(PoolType
, FinalSize
+ ObjectSize
, Tag
);
725 if (!Header
) return STATUS_INSUFFICIENT_RESOURCES
;
727 /* Check if we have a quota header */
730 /* Initialize quota info */
731 QuotaInfo
= (POBJECT_HEADER_QUOTA_INFO
)Header
;
732 QuotaInfo
->PagedPoolCharge
= ObjectCreateInfo
->PagedPoolCharge
;
733 QuotaInfo
->NonPagedPoolCharge
= ObjectCreateInfo
->NonPagedPoolCharge
;
734 QuotaInfo
->SecurityDescriptorCharge
= ObjectCreateInfo
->SecurityDescriptorCharge
;
735 QuotaInfo
->ExclusiveProcess
= NULL
;
736 Header
= (POBJECT_HEADER
)(QuotaInfo
+ 1);
739 /* Check if we have a handle database header */
742 /* Initialize Handle Info */
743 HandleInfo
= (POBJECT_HEADER_HANDLE_INFO
)Header
;
744 HandleInfo
->SingleEntry
.HandleCount
= 0;
745 Header
= (POBJECT_HEADER
)(HandleInfo
+ 1);
748 /* Check if we have a name header */
751 /* Initialize the Object Name Info */
752 NameInfo
= (POBJECT_HEADER_NAME_INFO
)Header
;
753 NameInfo
->Name
= *ObjectName
;
754 NameInfo
->Directory
= NULL
;
755 NameInfo
->QueryReferences
= 1;
757 /* Check if this is a call with the special protection flag */
758 if ((PreviousMode
== KernelMode
) &&
759 (ObjectCreateInfo
) &&
760 (ObjectCreateInfo
->Attributes
& OBJ_KERNEL_EXCLUSIVE
))
762 /* Set flag which will make the object protected from user-mode */
763 NameInfo
->QueryReferences
|= OB_FLAG_KERNEL_EXCLUSIVE
;
766 /* Set the header pointer */
767 Header
= (POBJECT_HEADER
)(NameInfo
+ 1);
770 /* Check if we have a creator header */
773 /* Initialize Creator Info */
774 CreatorInfo
= (POBJECT_HEADER_CREATOR_INFO
)Header
;
775 CreatorInfo
->CreatorBackTraceIndex
= 0;
776 CreatorInfo
->CreatorUniqueProcess
= PsGetCurrentProcessId();
777 InitializeListHead(&CreatorInfo
->TypeList
);
778 Header
= (POBJECT_HEADER
)(CreatorInfo
+ 1);
781 /* Check for quota information */
785 Header
->QuotaInfoOffset
= (UCHAR
)(QuotaSize
+
793 Header
->QuotaInfoOffset
= 0;
796 /* Check for handle information */
800 Header
->HandleInfoOffset
= (UCHAR
)(HandleSize
+
807 Header
->HandleInfoOffset
= 0;
810 /* Check for name information */
814 Header
->NameInfoOffset
= (UCHAR
)(NameSize
+ CreatorSize
);
819 Header
->NameInfoOffset
= 0;
822 /* Set the new object flag */
823 Header
->Flags
= OB_FLAG_CREATE_INFO
;
825 /* Remember if we have creator info */
826 if (CreatorSize
) Header
->Flags
|= OB_FLAG_CREATOR_INFO
;
828 /* Remember if we have handle info */
829 if (HandleSize
) Header
->Flags
|= OB_FLAG_SINGLE_PROCESS
;
831 /* Initialize the object header */
832 Header
->PointerCount
= 1;
833 Header
->HandleCount
= 0;
834 Header
->Type
= ObjectType
;
835 Header
->ObjectCreateInfo
= ObjectCreateInfo
;
836 Header
->SecurityDescriptor
= NULL
;
838 /* Check if this is a permanent object */
839 if ((ObjectCreateInfo
) && (ObjectCreateInfo
->Attributes
& OBJ_PERMANENT
))
841 /* Set the needed flag so we can check */
842 Header
->Flags
|= OB_FLAG_PERMANENT
;
845 /* Check if this is an exclusive object */
846 if ((ObjectCreateInfo
) && (ObjectCreateInfo
->Attributes
& OBJ_EXCLUSIVE
))
848 /* Set the needed flag so we can check */
849 Header
->Flags
|= OB_FLAG_EXCLUSIVE
;
852 /* Set kernel-mode flag */
853 if (PreviousMode
== KernelMode
) Header
->Flags
|= OB_FLAG_KERNEL_MODE
;
855 /* Check if we have a type */
858 /* Increase the number of objects of this type */
859 InterlockedIncrement((PLONG
)&ObjectType
->TotalNumberOfObjects
);
861 /* Update the high water */
862 ObjectType
->HighWaterNumberOfObjects
= max(ObjectType
->
863 TotalNumberOfObjects
,
865 HighWaterNumberOfObjects
);
869 *ObjectHeader
= Header
;
870 return STATUS_SUCCESS
;
875 ObQueryTypeInfo(IN POBJECT_TYPE ObjectType
,
876 OUT POBJECT_TYPE_INFORMATION ObjectTypeInfo
,
878 OUT PULONG ReturnLength
)
880 NTSTATUS Status
= STATUS_SUCCESS
;
886 /* Set return length aligned to 4-byte boundary */
887 *ReturnLength
+= sizeof(*ObjectTypeInfo
) +
888 ALIGN_UP(ObjectType
->Name
.MaximumLength
, ULONG
);
890 /* Check if thats too much though. */
891 if (Length
< *ReturnLength
)
893 _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH
);
897 ObjectTypeInfo
->TotalNumberOfHandles
=
898 ObjectType
->TotalNumberOfHandles
;
899 ObjectTypeInfo
->TotalNumberOfObjects
=
900 ObjectType
->TotalNumberOfObjects
;
901 ObjectTypeInfo
->HighWaterNumberOfHandles
=
902 ObjectType
->HighWaterNumberOfHandles
;
903 ObjectTypeInfo
->HighWaterNumberOfObjects
=
904 ObjectType
->HighWaterNumberOfObjects
;
905 ObjectTypeInfo
->PoolType
=
906 ObjectType
->TypeInfo
.PoolType
;
907 ObjectTypeInfo
->DefaultNonPagedPoolCharge
=
908 ObjectType
->TypeInfo
.DefaultNonPagedPoolCharge
;
909 ObjectTypeInfo
->DefaultPagedPoolCharge
=
910 ObjectType
->TypeInfo
.DefaultPagedPoolCharge
;
911 ObjectTypeInfo
->ValidAccessMask
=
912 ObjectType
->TypeInfo
.ValidAccessMask
;
913 ObjectTypeInfo
->SecurityRequired
=
914 ObjectType
->TypeInfo
.SecurityRequired
;
915 ObjectTypeInfo
->InvalidAttributes
=
916 ObjectType
->TypeInfo
.InvalidAttributes
;
917 ObjectTypeInfo
->GenericMapping
=
918 ObjectType
->TypeInfo
.GenericMapping
;
919 ObjectTypeInfo
->MaintainHandleCount
=
920 ObjectType
->TypeInfo
.MaintainHandleCount
;
922 /* Setup the name buffer */
923 InfoBuffer
= (PWSTR
)(ObjectTypeInfo
+ 1);
924 ObjectTypeInfo
->TypeName
.Buffer
= InfoBuffer
;
925 ObjectTypeInfo
->TypeName
.MaximumLength
= ObjectType
->Name
.MaximumLength
;
926 ObjectTypeInfo
->TypeName
.Length
= ObjectType
->Name
.Length
;
929 RtlCopyMemory(InfoBuffer
,
930 ObjectType
->Name
.Buffer
,
931 ObjectType
->Name
.Length
);
933 /* Null-terminate it */
934 (InfoBuffer
)[ObjectType
->Name
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
936 _SEH2_EXCEPT(ExSystemExceptionFilter())
938 /* Otherwise, get the exception code */
939 Status
= _SEH2_GetExceptionCode();
943 /* Return status to caller */
948 /* PUBLIC FUNCTIONS **********************************************************/
952 ObCreateObject(IN KPROCESSOR_MODE ProbeMode OPTIONAL
,
953 IN POBJECT_TYPE Type
,
954 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
955 IN KPROCESSOR_MODE AccessMode
,
956 IN OUT PVOID ParseContext OPTIONAL
,
958 IN ULONG PagedPoolCharge OPTIONAL
,
959 IN ULONG NonPagedPoolCharge OPTIONAL
,
963 POBJECT_CREATE_INFORMATION ObjectCreateInfo
;
964 UNICODE_STRING ObjectName
;
965 POBJECT_HEADER Header
;
967 /* Allocate a capture buffer */
968 ObjectCreateInfo
= ObpAllocateObjectCreateInfoBuffer(LookasideCreateInfoList
);
969 if (!ObjectCreateInfo
) return STATUS_INSUFFICIENT_RESOURCES
;
971 /* Capture all the info */
972 Status
= ObpCaptureObjectCreateInformation(ObjectAttributes
,
978 if (NT_SUCCESS(Status
))
980 /* Validate attributes */
981 if (Type
->TypeInfo
.InvalidAttributes
& ObjectCreateInfo
->Attributes
)
984 Status
= STATUS_INVALID_PARAMETER
;
988 /* Check if we have a paged charge */
989 if (!PagedPoolCharge
)
992 PagedPoolCharge
= Type
->TypeInfo
.DefaultPagedPoolCharge
;
995 /* Check for nonpaged charge */
996 if (!NonPagedPoolCharge
)
999 NonPagedPoolCharge
= Type
->TypeInfo
.DefaultNonPagedPoolCharge
;
1002 /* Write the pool charges */
1003 ObjectCreateInfo
->PagedPoolCharge
= PagedPoolCharge
;
1004 ObjectCreateInfo
->NonPagedPoolCharge
= NonPagedPoolCharge
;
1006 /* Allocate the Object */
1007 Status
= ObpAllocateObject(ObjectCreateInfo
,
1013 if (NT_SUCCESS(Status
))
1015 /* Return the Object */
1016 *Object
= &Header
->Body
;
1018 /* Check if this is a permanent object */
1019 if (Header
->Flags
& OB_FLAG_PERMANENT
)
1021 /* Do the privilege check */
1022 if (!SeSinglePrivilegeCheck(SeCreatePermanentPrivilege
,
1026 ObpDeallocateObject(*Object
);
1027 Status
= STATUS_PRIVILEGE_NOT_HELD
;
1036 /* Release the Capture Info, we don't need it */
1037 ObpFreeObjectCreateInformation(ObjectCreateInfo
);
1038 if (ObjectName
.Buffer
) ObpFreeObjectNameBuffer(&ObjectName
);
1041 /* We failed, so release the Buffer */
1042 ObpFreeCapturedAttributes(ObjectCreateInfo
, LookasideCreateInfoList
);
1048 ObCreateObjectType(IN PUNICODE_STRING TypeName
,
1049 IN POBJECT_TYPE_INITIALIZER ObjectTypeInitializer
,
1051 OUT POBJECT_TYPE
*ObjectType
)
1053 POBJECT_HEADER Header
;
1054 POBJECT_TYPE LocalObjectType
;
1057 OBP_LOOKUP_CONTEXT Context
;
1060 UNICODE_STRING ObjectName
;
1061 ANSI_STRING AnsiName
;
1062 POBJECT_HEADER_CREATOR_INFO CreatorInfo
;
1064 /* Verify parameters */
1066 !(TypeName
->Length
) ||
1067 (TypeName
->Length
% sizeof(WCHAR
)) ||
1068 !(ObjectTypeInitializer
) ||
1069 (ObjectTypeInitializer
->Length
!= sizeof(*ObjectTypeInitializer
)) ||
1070 (ObjectTypeInitializer
->InvalidAttributes
& ~OBJ_VALID_KERNEL_ATTRIBUTES
) ||
1071 (ObjectTypeInitializer
->MaintainHandleCount
&&
1072 (!(ObjectTypeInitializer
->OpenProcedure
) &&
1073 !ObjectTypeInitializer
->CloseProcedure
)) ||
1074 ((!ObjectTypeInitializer
->UseDefaultObject
) &&
1075 (ObjectTypeInitializer
->PoolType
!= NonPagedPool
)))
1078 return STATUS_INVALID_PARAMETER
;
1081 /* Make sure the name doesn't have a separator */
1082 p
= TypeName
->Buffer
;
1083 i
= TypeName
->Length
/ sizeof(WCHAR
);
1086 /* Check for one and fail */
1087 if (*p
++ == OBJ_NAME_PATH_SEPARATOR
) return STATUS_OBJECT_NAME_INVALID
;
1090 /* Setup a lookup context */
1091 ObpInitializeLookupContext(&Context
);
1093 /* Check if we've already created the directory of types */
1094 if (ObpTypeDirectoryObject
)
1096 /* Acquire the directory lock */
1097 ObpAcquireDirectoryLockExclusive(ObpTypeDirectoryObject
, &Context
);
1100 if (ObpLookupEntryDirectory(ObpTypeDirectoryObject
,
1102 OBJ_CASE_INSENSITIVE
,
1106 /* We have already created it, so fail */
1107 ObpReleaseLookupContext(&Context
);
1108 return STATUS_OBJECT_NAME_COLLISION
;
1112 /* Now make a copy of the object name */
1113 ObjectName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1114 TypeName
->MaximumLength
,
1116 if (!ObjectName
.Buffer
)
1118 /* Out of memory, fail */
1119 ObpReleaseLookupContext(&Context
);
1120 return STATUS_INSUFFICIENT_RESOURCES
;
1123 /* Set the length and copy the name */
1124 ObjectName
.MaximumLength
= TypeName
->MaximumLength
;
1125 RtlCopyUnicodeString(&ObjectName
, TypeName
);
1127 /* Allocate the Object */
1128 Status
= ObpAllocateObject(NULL
,
1131 sizeof(OBJECT_TYPE
),
1134 if (!NT_SUCCESS(Status
))
1136 /* Free the name and fail */
1137 ObpReleaseLookupContext(&Context
);
1138 ExFreePool(ObjectName
.Buffer
);
1142 /* Setup the flags and name */
1143 LocalObjectType
= (POBJECT_TYPE
)&Header
->Body
;
1144 LocalObjectType
->Name
= ObjectName
;
1145 Header
->Flags
|= OB_FLAG_KERNEL_MODE
| OB_FLAG_PERMANENT
;
1147 /* Clear accounting data */
1148 LocalObjectType
->TotalNumberOfObjects
=
1149 LocalObjectType
->TotalNumberOfHandles
=
1150 LocalObjectType
->HighWaterNumberOfObjects
=
1151 LocalObjectType
->HighWaterNumberOfHandles
= 0;
1153 /* Check if this is the first Object Type */
1154 if (!ObpTypeObjectType
)
1156 /* It is, so set this as the type object */
1157 ObpTypeObjectType
= LocalObjectType
;
1158 Header
->Type
= ObpTypeObjectType
;
1160 /* Set the hard-coded key and object count */
1161 LocalObjectType
->TotalNumberOfObjects
= 1;
1162 LocalObjectType
->Key
= 'TjbO';
1166 /* Convert the tag to ASCII */
1167 Status
= RtlUnicodeStringToAnsiString(&AnsiName
, TypeName
, TRUE
);
1168 if (NT_SUCCESS(Status
))
1170 /* For every missing character, use a space */
1171 for (i
= 3; i
>= AnsiName
.Length
; i
--) AnsiName
.Buffer
[i
] = ' ';
1173 /* Set the key and free the converted name */
1174 LocalObjectType
->Key
= *(PULONG
)AnsiName
.Buffer
;
1175 RtlFreeAnsiString(&AnsiName
);
1179 /* Just copy the characters */
1180 LocalObjectType
->Key
= *(PULONG
)TypeName
->Buffer
;
1184 /* Set up the type information */
1185 LocalObjectType
->TypeInfo
= *ObjectTypeInitializer
;
1186 LocalObjectType
->TypeInfo
.PoolType
= ObjectTypeInitializer
->PoolType
;
1188 /* Check if we have to maintain a type list */
1189 if (NtGlobalFlag
& FLG_MAINTAIN_OBJECT_TYPELIST
)
1191 /* Enable support */
1192 LocalObjectType
->TypeInfo
.MaintainTypeList
= TRUE
;
1195 /* Calculate how much space our header'll take up */
1196 HeaderSize
= sizeof(OBJECT_HEADER
) +
1197 sizeof(OBJECT_HEADER_NAME_INFO
) +
1198 (ObjectTypeInitializer
->MaintainHandleCount
?
1199 sizeof(OBJECT_HEADER_HANDLE_INFO
) : 0);
1201 /* Check the pool type */
1202 if (ObjectTypeInitializer
->PoolType
== NonPagedPool
)
1204 /* Update the NonPaged Pool charge */
1205 LocalObjectType
->TypeInfo
.DefaultNonPagedPoolCharge
+= HeaderSize
;
1209 /* Update the Paged Pool charge */
1210 LocalObjectType
->TypeInfo
.DefaultPagedPoolCharge
+= HeaderSize
;
1213 /* All objects types need a security procedure */
1214 if (!ObjectTypeInitializer
->SecurityProcedure
)
1216 LocalObjectType
->TypeInfo
.SecurityProcedure
= SeDefaultObjectMethod
;
1219 /* Select the Wait Object */
1220 if (LocalObjectType
->TypeInfo
.UseDefaultObject
)
1222 /* Add the SYNCHRONIZE access mask since it's waitable */
1223 LocalObjectType
->TypeInfo
.ValidAccessMask
|= SYNCHRONIZE
;
1225 /* Use the "Default Object", a simple event */
1226 LocalObjectType
->DefaultObject
= &ObpDefaultObject
;
1228 /* The File Object gets an optimized hack so it can be waited on */
1229 else if ((TypeName
->Length
== 8) && !(wcscmp(TypeName
->Buffer
, L
"File")))
1231 /* Wait on the File Object's event directly */
1232 LocalObjectType
->DefaultObject
= UlongToPtr(FIELD_OFFSET(FILE_OBJECT
,
1235 else if ((TypeName
->Length
== 24) && !(wcscmp(TypeName
->Buffer
, L
"WaitablePort")))
1237 /* Wait on the LPC Port's object directly */
1238 LocalObjectType
->DefaultObject
= UlongToPtr(FIELD_OFFSET(LPCP_PORT_OBJECT
,
1243 /* No default Object */
1244 LocalObjectType
->DefaultObject
= NULL
;
1247 /* Initialize Object Type components */
1248 ExInitializeResourceLite(&LocalObjectType
->Mutex
);
1249 for (i
= 0; i
< 4; i
++)
1251 /* Initialize the object locks */
1252 ExInitializeResourceLite(&LocalObjectType
->ObjectLocks
[i
]);
1254 InitializeListHead(&LocalObjectType
->TypeList
);
1256 /* Lock the object type */
1257 ObpEnterObjectTypeMutex(ObpTypeObjectType
);
1259 /* Get creator info and insert it into the type list */
1260 CreatorInfo
= OBJECT_HEADER_TO_CREATOR_INFO(Header
);
1263 InsertTailList(&ObpTypeObjectType
->TypeList
,
1264 &CreatorInfo
->TypeList
);
1266 /* CORE-8423: Avoid inserting this a second time if someone creates a
1267 * handle to the object type (bug in Windows 2003) */
1268 Header
->Flags
&= ~OB_FLAG_CREATE_INFO
;
1271 /* Set the index and the entry into the object type array */
1272 LocalObjectType
->Index
= ObpTypeObjectType
->TotalNumberOfObjects
;
1274 ASSERT(LocalObjectType
->Index
!= 0);
1276 if (LocalObjectType
->Index
< RTL_NUMBER_OF(ObpObjectTypes
))
1278 /* It fits, insert it */
1279 ObpObjectTypes
[LocalObjectType
->Index
- 1] = LocalObjectType
;
1282 /* Release the object type */
1283 ObpLeaveObjectTypeMutex(ObpTypeObjectType
);
1285 /* Check if we're actually creating the directory object itself */
1286 if (!(ObpTypeDirectoryObject
) ||
1287 (ObpInsertEntryDirectory(ObpTypeDirectoryObject
, &Context
, Header
)))
1289 /* Check if the type directory exists */
1290 if (ObpTypeDirectoryObject
)
1293 ObReferenceObject(ObpTypeDirectoryObject
);
1296 /* Cleanup the lookup context */
1297 ObpReleaseLookupContext(&Context
);
1299 /* Return the object type and success */
1300 *ObjectType
= LocalObjectType
;
1301 return STATUS_SUCCESS
;
1304 /* If we got here, then we failed */
1305 ObpReleaseLookupContext(&Context
);
1306 return STATUS_INSUFFICIENT_RESOURCES
;
1311 ObDeleteCapturedInsertInfo(IN PVOID Object
)
1313 POBJECT_HEADER ObjectHeader
;
1316 /* Check if there is anything to free */
1317 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
1318 if ((ObjectHeader
->Flags
& OB_FLAG_CREATE_INFO
) &&
1319 (ObjectHeader
->ObjectCreateInfo
!= NULL
))
1321 /* Free the create info */
1322 ObpFreeObjectCreateInformation(ObjectHeader
->ObjectCreateInfo
);
1323 ObjectHeader
->ObjectCreateInfo
= NULL
;
1329 ObpDeleteObjectType(IN PVOID Object
)
1332 POBJECT_TYPE ObjectType
= (PVOID
)Object
;
1334 /* Loop our locks */
1335 for (i
= 0; i
< 4; i
++)
1337 /* Delete each one */
1338 ExDeleteResourceLite(&ObjectType
->ObjectLocks
[i
]);
1341 /* Delete our main mutex */
1342 ExDeleteResourceLite(&ObjectType
->Mutex
);
1346 * @name ObMakeTemporaryObject
1349 * The ObMakeTemporaryObject routine <FILLMEIN>
1361 ObMakeTemporaryObject(IN PVOID ObjectBody
)
1365 /* Call the internal API */
1366 ObpSetPermanentObject(ObjectBody
, FALSE
);
1370 * @name NtMakeTemporaryObject
1373 * The NtMakeTemporaryObject routine <FILLMEIN>
1375 * @param ObjectHandle
1378 * @return STATUS_SUCCESS or appropriate error value.
1385 NtMakeTemporaryObject(IN HANDLE ObjectHandle
)
1391 /* Reference the object for DELETE access */
1392 Status
= ObReferenceObjectByHandle(ObjectHandle
,
1395 KeGetPreviousMode(),
1398 if (Status
!= STATUS_SUCCESS
) return Status
;
1400 /* Set it as temporary and dereference it */
1401 ObpSetPermanentObject(ObjectBody
, FALSE
);
1402 ObDereferenceObject(ObjectBody
);
1403 return STATUS_SUCCESS
;
1407 * @name NtMakePermanentObject
1410 * The NtMakePermanentObject routine <FILLMEIN>
1412 * @param ObjectHandle
1415 * @return STATUS_SUCCESS or appropriate error value.
1422 NtMakePermanentObject(IN HANDLE ObjectHandle
)
1426 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1429 /* Make sure that the caller has SeCreatePermanentPrivilege */
1430 Status
= SeSinglePrivilegeCheck(SeCreatePermanentPrivilege
,
1432 if (!NT_SUCCESS(Status
)) return STATUS_PRIVILEGE_NOT_HELD
;
1434 /* Reference the object */
1435 Status
= ObReferenceObjectByHandle(ObjectHandle
,
1441 if (Status
!= STATUS_SUCCESS
) return Status
;
1443 /* Set it as permanent and dereference it */
1444 ObpSetPermanentObject(ObjectBody
, TRUE
);
1445 ObDereferenceObject(ObjectBody
);
1446 return STATUS_SUCCESS
;
1450 * @name NtQueryObject
1453 * The NtQueryObject routine <FILLMEIN>
1455 * @param ObjectHandle
1458 * @param ObjectInformationClass
1461 * @param ObjectInformation
1467 * @param ResultLength
1470 * @return STATUS_SUCCESS or appropriate error value.
1477 NtQueryObject(IN HANDLE ObjectHandle
,
1478 IN OBJECT_INFORMATION_CLASS ObjectInformationClass
,
1479 OUT PVOID ObjectInformation
,
1481 OUT PULONG ResultLength OPTIONAL
)
1483 OBJECT_HANDLE_INFORMATION HandleInfo
;
1484 POBJECT_HEADER ObjectHeader
= NULL
;
1485 POBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleFlags
;
1486 POBJECT_BASIC_INFORMATION BasicInfo
;
1487 ULONG InfoLength
= 0;
1488 PVOID Object
= NULL
;
1490 POBJECT_HEADER_QUOTA_INFO ObjectQuota
;
1491 SECURITY_INFORMATION SecurityInformation
;
1492 POBJECT_TYPE ObjectType
;
1493 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1496 /* Check if the caller is from user mode */
1497 if (PreviousMode
!= KernelMode
)
1499 /* Protect validation with SEH */
1502 /* Probe the input structure */
1503 ProbeForWrite(ObjectInformation
, Length
, sizeof(UCHAR
));
1505 /* If we have a result length, probe it too */
1506 if (ResultLength
) ProbeForWriteUlong(ResultLength
);
1508 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1510 /* Return the exception code */
1511 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1517 * Make sure this isn't a generic type query, since the caller doesn't
1518 * have to give a handle for it
1520 if (ObjectInformationClass
!= ObjectTypesInformation
)
1522 /* Reference the object */
1523 Status
= ObReferenceObjectByHandle(ObjectHandle
,
1526 KeGetPreviousMode(),
1529 if (!NT_SUCCESS (Status
)) return Status
;
1531 /* Get the object header */
1532 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
1533 ObjectType
= ObjectHeader
->Type
;
1538 /* Check the information class */
1539 switch (ObjectInformationClass
)
1542 case ObjectBasicInformation
:
1544 /* Validate length */
1545 InfoLength
= sizeof(OBJECT_BASIC_INFORMATION
);
1546 if (Length
!= sizeof(OBJECT_BASIC_INFORMATION
))
1549 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1553 /* Fill out the basic information */
1554 BasicInfo
= (POBJECT_BASIC_INFORMATION
)ObjectInformation
;
1555 BasicInfo
->Attributes
= HandleInfo
.HandleAttributes
;
1556 BasicInfo
->GrantedAccess
= HandleInfo
.GrantedAccess
;
1557 BasicInfo
->HandleCount
= ObjectHeader
->HandleCount
;
1558 BasicInfo
->PointerCount
= ObjectHeader
->PointerCount
;
1560 /* Permanent/Exclusive Flags are NOT in Handle attributes! */
1561 if (ObjectHeader
->Flags
& OB_FLAG_EXCLUSIVE
)
1564 BasicInfo
->Attributes
|= OBJ_EXCLUSIVE
;
1566 if (ObjectHeader
->Flags
& OB_FLAG_PERMANENT
)
1569 BasicInfo
->Attributes
|= OBJ_PERMANENT
;
1572 /* Copy quota information */
1573 ObjectQuota
= OBJECT_HEADER_TO_QUOTA_INFO(ObjectHeader
);
1574 if (ObjectQuota
!= NULL
)
1576 BasicInfo
->PagedPoolCharge
= ObjectQuota
->PagedPoolCharge
;
1577 BasicInfo
->NonPagedPoolCharge
= ObjectQuota
->NonPagedPoolCharge
;
1581 BasicInfo
->PagedPoolCharge
= 0;
1582 BasicInfo
->NonPagedPoolCharge
= 0;
1585 /* Copy name information */
1586 BasicInfo
->NameInfoSize
= 0; /* FIXME*/
1587 BasicInfo
->TypeInfoSize
= 0; /* FIXME*/
1589 /* Check if this is a symlink */
1590 if (ObjectHeader
->Type
== ObpSymbolicLinkObjectType
)
1592 /* Return the creation time */
1593 BasicInfo
->CreationTime
.QuadPart
=
1594 ((POBJECT_SYMBOLIC_LINK
)Object
)->CreationTime
.QuadPart
;
1598 /* Otherwise return 0 */
1599 BasicInfo
->CreationTime
.QuadPart
= (ULONGLONG
)0;
1602 /* Copy security information */
1603 BasicInfo
->SecurityDescriptorSize
= 0;
1604 if (BooleanFlagOn(HandleInfo
.GrantedAccess
, READ_CONTROL
) &&
1605 ObjectHeader
->SecurityDescriptor
!= NULL
)
1607 SecurityInformation
= OWNER_SECURITY_INFORMATION
|
1608 GROUP_SECURITY_INFORMATION
|
1609 DACL_SECURITY_INFORMATION
|
1610 SACL_SECURITY_INFORMATION
;
1612 ObjectType
->TypeInfo
.SecurityProcedure(Object
,
1613 QuerySecurityDescriptor
,
1614 &SecurityInformation
,
1616 &BasicInfo
->SecurityDescriptorSize
,
1617 &ObjectHeader
->SecurityDescriptor
,
1618 ObjectType
->TypeInfo
.PoolType
,
1619 &ObjectType
->TypeInfo
.GenericMapping
);
1622 /* Break out with success */
1623 Status
= STATUS_SUCCESS
;
1626 /* Name information */
1627 case ObjectNameInformation
:
1629 /* Call the helper and break out */
1630 Status
= ObQueryNameString(Object
,
1631 (POBJECT_NAME_INFORMATION
)
1637 /* Information about this type */
1638 case ObjectTypeInformation
:
1640 /* Call the helper and break out */
1641 Status
= ObQueryTypeInfo(ObjectHeader
->Type
,
1642 (POBJECT_TYPE_INFORMATION
)
1648 /* Information about all types */
1649 case ObjectTypesInformation
:
1650 DPRINT1("NOT IMPLEMENTED!\n");
1651 InfoLength
= Length
;
1652 Status
= STATUS_NOT_IMPLEMENTED
;
1655 /* Information about the handle flags */
1656 case ObjectHandleFlagInformation
:
1658 /* Validate length */
1659 InfoLength
= sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION
);
1660 if (Length
!= sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION
))
1662 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1666 /* Get the structure */
1667 HandleFlags
= (POBJECT_HANDLE_ATTRIBUTE_INFORMATION
)
1671 HandleFlags
->Inherit
= HandleInfo
.HandleAttributes
& OBJ_INHERIT
;
1672 HandleFlags
->ProtectFromClose
= (HandleInfo
.HandleAttributes
&
1673 OBJ_PROTECT_CLOSE
) != 0;
1675 /* Break out with success */
1676 Status
= STATUS_SUCCESS
;
1683 InfoLength
= Length
;
1684 Status
= STATUS_INVALID_INFO_CLASS
;
1688 /* Check if the caller wanted the return length */
1691 /* Write the length */
1692 *ResultLength
= InfoLength
;
1695 _SEH2_EXCEPT(ExSystemExceptionFilter())
1697 /* Otherwise, get the exception code */
1698 Status
= _SEH2_GetExceptionCode();
1702 /* Dereference the object if we had referenced it */
1703 if (Object
) ObDereferenceObject(Object
);
1710 * @name NtSetInformationObject
1713 * The NtSetInformationObject routine <FILLMEIN>
1715 * @param ObjectHandle
1718 * @param ObjectInformationClass
1721 * @param ObjectInformation
1727 * @return STATUS_SUCCESS or appropriate error value.
1734 NtSetInformationObject(IN HANDLE ObjectHandle
,
1735 IN OBJECT_INFORMATION_CLASS ObjectInformationClass
,
1736 IN PVOID ObjectInformation
,
1740 OBP_SET_HANDLE_ATTRIBUTES_CONTEXT Context
;
1742 KAPC_STATE ApcState
;
1743 POBJECT_DIRECTORY Directory
;
1744 KPROCESSOR_MODE PreviousMode
;
1745 BOOLEAN AttachedToProcess
= FALSE
;
1748 /* Validate the information class */
1749 switch (ObjectInformationClass
)
1751 case ObjectHandleFlagInformation
:
1753 /* Validate the length */
1754 if (Length
!= sizeof(OBJECT_HANDLE_ATTRIBUTE_INFORMATION
))
1756 /* Invalid length */
1757 return STATUS_INFO_LENGTH_MISMATCH
;
1760 /* Save the previous mode */
1761 Context
.PreviousMode
= ExGetPreviousMode();
1763 /* Check if we were called from user mode */
1764 if (Context
.PreviousMode
!= KernelMode
)
1769 /* Probe and capture the attribute buffer */
1770 ProbeForRead(ObjectInformation
,
1771 sizeof(OBJECT_HANDLE_ATTRIBUTE_INFORMATION
),
1773 Context
.Information
= *(POBJECT_HANDLE_ATTRIBUTE_INFORMATION
)
1776 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1778 /* Return the exception code */
1779 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1785 /* Just copy the buffer directly */
1786 Context
.Information
= *(POBJECT_HANDLE_ATTRIBUTE_INFORMATION
)
1790 /* Check if this is a kernel handle */
1791 if (ObpIsKernelHandle(ObjectHandle
, Context
.PreviousMode
))
1793 /* Get the actual handle */
1794 ObjectHandle
= ObKernelHandleToHandle(ObjectHandle
);
1795 ObjectTable
= ObpKernelHandleTable
;
1797 /* Check if we're not in the system process */
1798 if (PsGetCurrentProcess() != PsInitialSystemProcess
)
1801 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
1802 AttachedToProcess
= TRUE
;
1807 /* Use the current table */
1808 ObjectTable
= PsGetCurrentProcess()->ObjectTable
;
1811 /* Change the handle attributes */
1812 if (!ExChangeHandle(ObjectTable
,
1814 ObpSetHandleAttributes
,
1815 (ULONG_PTR
)&Context
))
1818 Status
= STATUS_ACCESS_DENIED
;
1823 Status
= STATUS_SUCCESS
;
1826 /* De-attach if we were attached, and return status */
1827 if (AttachedToProcess
) KeUnstackDetachProcess(&ApcState
);
1830 case ObjectSessionInformation
:
1832 /* Only a system process can do this */
1833 PreviousMode
= ExGetPreviousMode();
1834 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
, PreviousMode
))
1837 DPRINT1("Privilege not held\n");
1838 Status
= STATUS_PRIVILEGE_NOT_HELD
;
1842 /* Get the object directory */
1843 Status
= ObReferenceObjectByHandle(ObjectHandle
,
1845 ObpDirectoryObjectType
,
1849 if (NT_SUCCESS(Status
))
1851 /* FIXME: Missng locks */
1852 /* Set its session ID */
1853 Directory
->SessionId
= PsGetCurrentProcessSessionId();
1854 ObDereferenceObject(Directory
);
1860 /* Unsupported class */
1861 Status
= STATUS_INVALID_INFO_CLASS
;