xref: /reactos/ntoskrnl/ob/oblife.c (revision 0c42866e)
1 /*
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)
10  *                  Eric Kohl
11  *                  Thomas Weidenmueller (w3seek@reactos.org)
12  */
13 
14 /* INCLUDES ******************************************************************/
15 
16 #include <ntoskrnl.h>
17 #define NDEBUG
18 #include <debug.h>
19 
20 extern ULONG NtGlobalFlag;
21 
22 POBJECT_TYPE ObpTypeObjectType = NULL;
23 KEVENT ObpDefaultObject;
24 KGUARDED_MUTEX ObpDeviceMapLock;
25 
26 GENERAL_LOOKASIDE ObpNameBufferLookasideList, ObpCreateInfoLookasideList;
27 
28 WORK_QUEUE_ITEM ObpReaperWorkItem;
29 volatile PVOID ObpReaperList;
30 
31 ULONG ObpObjectsCreated, ObpObjectsWithName, ObpObjectsWithPoolQuota;
32 ULONG ObpObjectsWithHandleDB, ObpObjectsWithCreatorInfo;
33 POBJECT_TYPE ObpObjectTypes[32];
34 
35 /* PRIVATE FUNCTIONS *********************************************************/
36 
37 VOID
38 FASTCALL
39 ObpDeallocateObject(IN PVOID Object)
40 {
41     PVOID HeaderLocation;
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;
49     PAGED_CODE();
50 
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;
55 
56     /* To find the header, walk backwards from how we allocated */
57     if ((CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(Header)))
58     {
59         HeaderLocation = CreatorInfo;
60     }
61     if ((NameInfo = OBJECT_HEADER_TO_NAME_INFO(Header)))
62     {
63         HeaderLocation = NameInfo;
64     }
65     if ((HandleInfo = OBJECT_HEADER_TO_HANDLE_INFO(Header)))
66     {
67         HeaderLocation = HandleInfo;
68     }
69     if ((QuotaInfo = OBJECT_HEADER_TO_QUOTA_INFO(Header)))
70     {
71         HeaderLocation = QuotaInfo;
72     }
73 
74     /* Decrease the total */
75     InterlockedDecrement((PLONG)&ObjectType->TotalNumberOfObjects);
76 
77     /* Check if we have create info */
78     if (Header->Flags & OB_FLAG_CREATE_INFO)
79     {
80         /* Double-check that it exists */
81         if (Header->ObjectCreateInfo)
82         {
83             /* Free it */
84             ObpFreeObjectCreateInformation(Header->ObjectCreateInfo);
85             Header->ObjectCreateInfo = NULL;
86         }
87     }
88     else
89     {
90         /* Check if it has a quota block */
91         if (Header->QuotaBlockCharged)
92         {
93             /* Check if we have quota information */
94             if (QuotaInfo)
95             {
96                 /* Get charges from quota information */
97                 PagedPoolCharge = QuotaInfo->PagedPoolCharge +
98                                   QuotaInfo->SecurityDescriptorCharge;
99                 NonPagedPoolCharge = QuotaInfo->NonPagedPoolCharge;
100             }
101             else
102             {
103                 /* Get charges from object type */
104                 PagedPoolCharge = ObjectType->TypeInfo.DefaultPagedPoolCharge;
105                 NonPagedPoolCharge = ObjectType->
106                                      TypeInfo.DefaultNonPagedPoolCharge;
107 
108                 /* Add the SD charge too */
109                 if (Header->Flags & OB_FLAG_SECURITY) PagedPoolCharge += 2048;
110             }
111 
112             /* Return the quota */
113             if (Header->QuotaBlockCharged != OBP_SYSTEM_PROCESS_QUOTA)
114             {
115                 PsReturnSharedPoolQuota(Header->QuotaBlockCharged,
116                                         PagedPoolCharge,
117                                         NonPagedPoolCharge);
118             }
119         }
120     }
121 
122     /* Check if a handle database was active */
123     if ((HandleInfo) && !(Header->Flags & OB_FLAG_SINGLE_PROCESS))
124     {
125         /* Free it */
126         ExFreePool(HandleInfo->HandleCountDatabase);
127         HandleInfo->HandleCountDatabase = NULL;
128     }
129 
130     /* Check if we have a name */
131     if ((NameInfo) && (NameInfo->Name.Buffer))
132     {
133         /* Free it */
134         ExFreePool(NameInfo->Name.Buffer);
135         NameInfo->Name.Buffer = NULL;
136     }
137 
138     /* Catch invalid access */
139     Header->Type = (POBJECT_TYPE)(ULONG_PTR)0xBAADB0B0BAADB0B0ULL;
140 
141     /* Free the object using the same allocation tag */
142     ExFreePoolWithTag(HeaderLocation, ObjectType->Key);
143 }
144 
145 VOID
146 NTAPI
147 ObpDeleteObject(IN PVOID Object,
148                 IN BOOLEAN CalledFromWorkerThread)
149 {
150     POBJECT_HEADER Header;
151     POBJECT_TYPE ObjectType;
152     POBJECT_HEADER_NAME_INFO NameInfo;
153     POBJECT_HEADER_CREATOR_INFO CreatorInfo;
154     KIRQL CalloutIrql;
155     PAGED_CODE();
156 
157     /* Get the header and type */
158     Header = OBJECT_TO_OBJECT_HEADER(Object);
159     ObjectType = Header->Type;
160 
161     /* Get creator and name information */
162     NameInfo = OBJECT_HEADER_TO_NAME_INFO(Header);
163     CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(Header);
164 
165     /* Check if the object is on a type list */
166     if ((CreatorInfo) && !(IsListEmpty(&CreatorInfo->TypeList)))
167     {
168         /* Lock the object type */
169         ObpEnterObjectTypeMutex(ObjectType);
170 
171         /* Remove the object from the type list */
172         RemoveEntryList(&CreatorInfo->TypeList);
173 
174         /* Release the lock */
175         ObpLeaveObjectTypeMutex(ObjectType);
176     }
177 
178     /* Check if we have a name */
179     if ((NameInfo) && (NameInfo->Name.Buffer))
180     {
181         /* Free it */
182         ExFreePool(NameInfo->Name.Buffer);
183         RtlInitEmptyUnicodeString(&NameInfo->Name, NULL, 0);
184     }
185 
186     /* Check if we have a security descriptor */
187     if (Header->SecurityDescriptor)
188     {
189         /* Call the security procedure to delete it */
190         ObpCalloutStart(&CalloutIrql);
191         ObjectType->TypeInfo.SecurityProcedure(Object,
192                                                DeleteSecurityDescriptor,
193                                                0,
194                                                NULL,
195                                                NULL,
196                                                &Header->SecurityDescriptor,
197                                                0,
198                                                NULL);
199         ObpCalloutEnd(CalloutIrql, "Security", ObjectType, Object);
200     }
201 
202     /* Check if we have a delete procedure */
203     if (ObjectType->TypeInfo.DeleteProcedure)
204     {
205         /* Save whether we were deleted from worker thread or not */
206         if (!CalledFromWorkerThread) Header->Flags |= OB_FLAG_DEFER_DELETE;
207 
208         /* Call it */
209         ObpCalloutStart(&CalloutIrql);
210         ObjectType->TypeInfo.DeleteProcedure(Object);
211         ObpCalloutEnd(CalloutIrql, "Delete", ObjectType, Object);
212     }
213 
214     /* Now de-allocate all object members */
215     ObpDeallocateObject(Object);
216 }
217 
218 VOID
219 NTAPI
220 ObpReapObject(IN PVOID Parameter)
221 {
222     POBJECT_HEADER ReapObject, NextObject;
223 
224     /* Start reaping */
225     do
226     {
227         /* Get the reap object */
228         ReapObject = InterlockedExchangePointer(&ObpReaperList, (PVOID)1);
229 
230         /* Start deletion loop */
231         do
232         {
233             /* Get the next object */
234             NextObject = ReapObject->NextToFree;
235 
236             /* Delete the object */
237             ObpDeleteObject(&ReapObject->Body, TRUE);
238 
239             /* Move to the next one */
240             ReapObject = NextObject;
241         } while ((ReapObject) && (ReapObject != (PVOID)1));
242     } while ((ObpReaperList != (PVOID)1) ||
243              (InterlockedCompareExchange((PLONG)&ObpReaperList, 0, 1) != 1));
244 }
245 
246 /*++
247 * @name ObpSetPermanentObject
248 *
249 *     The ObpSetPermanentObject routine makes an sets or clears the permanent
250 *     flag of an object, thus making it either permanent or temporary.
251 *
252 * @param ObjectBody
253 *        Pointer to the object to make permanent or temporary.
254 *
255 * @param Permanent
256 *        Flag specifying which operation to perform.
257 *
258 * @return None.
259 *
260 * @remarks If the object is being made temporary, then it will be checked
261 *          as a candidate for immediate removal from the namespace.
262 *
263 *--*/
264 VOID
265 FASTCALL
266 ObpSetPermanentObject(IN PVOID ObjectBody,
267                       IN BOOLEAN Permanent)
268 {
269     POBJECT_HEADER ObjectHeader;
270 
271     /* Get the header */
272     ObjectHeader = OBJECT_TO_OBJECT_HEADER(ObjectBody);
273 
274     /* Acquire object lock */
275     ObpAcquireObjectLock(ObjectHeader);
276 
277     /* Check what we're doing to it */
278     if (Permanent)
279     {
280         /* Set it to permanent */
281         ObjectHeader->Flags |= OB_FLAG_PERMANENT;
282 
283         /* Release the lock */
284         ObpReleaseObjectLock(ObjectHeader);
285     }
286     else
287     {
288         /* Remove the flag */
289         ObjectHeader->Flags &= ~OB_FLAG_PERMANENT;
290 
291         /* Release the lock */
292         ObpReleaseObjectLock(ObjectHeader);
293 
294         /* Check if we should delete the object now */
295         ObpDeleteNameCheck(ObjectBody);
296     }
297 }
298 
299 PWCHAR
300 NTAPI
301 ObpAllocateObjectNameBuffer(IN ULONG Length,
302                             IN BOOLEAN UseLookaside,
303                             IN OUT PUNICODE_STRING ObjectName)
304 {
305     ULONG MaximumLength;
306     PVOID Buffer;
307 
308     /* Set the maximum length to the length plus the terminator */
309     MaximumLength = Length + sizeof(UNICODE_NULL);
310 
311     /* Check if we should use the lookaside buffer */
312     if (!(UseLookaside) || (MaximumLength > OBP_NAME_LOOKASIDE_MAX_SIZE))
313     {
314         /* Nope, allocate directly from pool */
315         /* Since we later use MaximumLength to detect that we're not allocating
316          * from a list, we need at least MaximumLength + sizeof(UNICODE_NULL)
317          * here.
318          *
319          * People do call this with UseLookasideList FALSE so the distinction
320          * is critical.
321          */
322         if (MaximumLength <= OBP_NAME_LOOKASIDE_MAX_SIZE)
323         {
324             MaximumLength = OBP_NAME_LOOKASIDE_MAX_SIZE + sizeof(UNICODE_NULL);
325         }
326         Buffer = ExAllocatePoolWithTag(PagedPool,
327                                        MaximumLength,
328                                        OB_NAME_TAG);
329     }
330     else
331     {
332         /* Allocate from the lookaside */
333         MaximumLength = OBP_NAME_LOOKASIDE_MAX_SIZE;
334         Buffer = ObpAllocateObjectCreateInfoBuffer(LookasideNameBufferList);
335     }
336 
337     /* Setup the string */
338     ObjectName->MaximumLength = (USHORT)MaximumLength;
339     ObjectName->Length = (USHORT)Length;
340     ObjectName->Buffer = Buffer;
341     return Buffer;
342 }
343 
344 VOID
345 NTAPI
346 ObpFreeObjectNameBuffer(IN PUNICODE_STRING Name)
347 {
348     PVOID Buffer = Name->Buffer;
349 
350     /* We know this is a pool-allocation if the size doesn't match */
351     if (Name->MaximumLength != OBP_NAME_LOOKASIDE_MAX_SIZE)
352     {
353         /*
354          * Free it from the pool.
355          *
356          * We cannot use here ExFreePoolWithTag(..., OB_NAME_TAG); , because
357          * the object name may have been massaged during operation by different
358          * object parse routines. If the latter ones have to resolve a symbolic
359          * link (e.g. as is done by CmpParseKey() and CmpGetSymbolicLink()),
360          * the original object name is freed and re-allocated from the pool,
361          * possibly with a different pool tag. At the end of the day, the new
362          * object name can be reallocated and completely different, but we
363          * should still be able to free it!
364          */
365         ExFreePool(Buffer);
366     }
367     else
368     {
369         /* Otherwise, free from the lookaside */
370         ObpFreeCapturedAttributes(Buffer, LookasideNameBufferList);
371     }
372 }
373 
374 NTSTATUS
375 NTAPI
376 ObpCaptureObjectName(IN OUT PUNICODE_STRING CapturedName,
377                      IN PUNICODE_STRING ObjectName,
378                      IN KPROCESSOR_MODE AccessMode,
379                      IN BOOLEAN UseLookaside)
380 {
381     NTSTATUS Status = STATUS_SUCCESS;
382     ULONG StringLength;
383     PWCHAR _SEH2_VOLATILE StringBuffer = NULL;
384     UNICODE_STRING LocalName;
385     PAGED_CODE();
386 
387     /* Initialize the Input String */
388     RtlInitEmptyUnicodeString(CapturedName, NULL, 0);
389 
390     /* Protect everything */
391     _SEH2_TRY
392     {
393         /* Check if we came from user mode */
394         if (AccessMode != KernelMode)
395         {
396             /* First Probe the String */
397             LocalName = ProbeForReadUnicodeString(ObjectName);
398             ProbeForRead(LocalName.Buffer, LocalName.Length, sizeof(WCHAR));
399         }
400         else
401         {
402             /* No probing needed */
403             LocalName = *ObjectName;
404         }
405 
406         /* Make sure there really is a string */
407         StringLength = LocalName.Length;
408         if (StringLength)
409         {
410             /* Check that the size is a valid WCHAR multiple */
411             if ((StringLength & (sizeof(WCHAR) - 1)) ||
412                 /* Check that the NULL-termination below will work */
413                 (StringLength == (MAXUSHORT - sizeof(UNICODE_NULL) + 1)))
414             {
415                 /* PS: Please keep the checks above expanded for clarity */
416                 Status = STATUS_OBJECT_NAME_INVALID;
417             }
418             else
419             {
420                 /* Allocate the string buffer */
421                 StringBuffer = ObpAllocateObjectNameBuffer(StringLength,
422                                                            UseLookaside,
423                                                            CapturedName);
424                 if (!StringBuffer)
425                 {
426                     /* Set failure code */
427                     Status = STATUS_INSUFFICIENT_RESOURCES;
428                 }
429                 else
430                 {
431                     /* Copy the name */
432                     RtlCopyMemory(StringBuffer, LocalName.Buffer, StringLength);
433                     StringBuffer[StringLength / sizeof(WCHAR)] = UNICODE_NULL;
434                 }
435             }
436         }
437     }
438     _SEH2_EXCEPT(ExSystemExceptionFilter())
439     {
440         /* Handle exception and free the string buffer */
441         Status = _SEH2_GetExceptionCode();
442         if (StringBuffer)
443         {
444             ObpFreeObjectNameBuffer(CapturedName);
445         }
446     }
447     _SEH2_END;
448 
449     /* Return */
450     return Status;
451 }
452 
453 NTSTATUS
454 NTAPI
455 ObpCaptureObjectCreateInformation(IN POBJECT_ATTRIBUTES ObjectAttributes,
456                                   IN KPROCESSOR_MODE AccessMode,
457                                   IN KPROCESSOR_MODE CreatorMode,
458                                   IN BOOLEAN AllocateFromLookaside,
459                                   IN POBJECT_CREATE_INFORMATION ObjectCreateInfo,
460                                   OUT PUNICODE_STRING ObjectName)
461 {
462     ULONG SdCharge, QuotaInfoSize;
463     NTSTATUS Status = STATUS_SUCCESS;
464     PSECURITY_DESCRIPTOR SecurityDescriptor;
465     PSECURITY_QUALITY_OF_SERVICE SecurityQos;
466     PUNICODE_STRING LocalObjectName = NULL;
467     PAGED_CODE();
468 
469     /* Zero out the Capture Data */
470     RtlZeroMemory(ObjectCreateInfo, sizeof(OBJECT_CREATE_INFORMATION));
471 
472     /* SEH everything here for protection */
473     _SEH2_TRY
474     {
475         /* Check if we got attributes */
476         if (ObjectAttributes)
477         {
478             /* Check if we're in user mode */
479             if (AccessMode != KernelMode)
480             {
481                 /* Probe the attributes */
482                 ProbeForRead(ObjectAttributes,
483                              sizeof(OBJECT_ATTRIBUTES),
484                              sizeof(ULONG));
485             }
486 
487             /* Validate the Size and Attributes */
488             if ((ObjectAttributes->Length != sizeof(OBJECT_ATTRIBUTES)) ||
489                 (ObjectAttributes->Attributes & ~OBJ_VALID_KERNEL_ATTRIBUTES))
490             {
491                 /* Invalid combination, fail */
492                 _SEH2_YIELD(return STATUS_INVALID_PARAMETER);
493             }
494 
495             /* Set some Create Info and do not allow user-mode kernel handles */
496             ObjectCreateInfo->RootDirectory = ObjectAttributes->RootDirectory;
497             ObjectCreateInfo->Attributes = ObjectAttributes->Attributes & OBJ_VALID_KERNEL_ATTRIBUTES;
498             if (CreatorMode != KernelMode) ObjectCreateInfo->Attributes &= ~OBJ_KERNEL_HANDLE;
499             LocalObjectName = ObjectAttributes->ObjectName;
500             SecurityDescriptor = ObjectAttributes->SecurityDescriptor;
501             SecurityQos = ObjectAttributes->SecurityQualityOfService;
502 
503             /* Check if we have a security descriptor */
504             if (SecurityDescriptor)
505             {
506                 /* Capture it. Note: This has an implicit memory barrier due
507                    to the function call, so cleanup is safe here.) */
508                 Status = SeCaptureSecurityDescriptor(SecurityDescriptor,
509                                                      AccessMode,
510                                                      NonPagedPool,
511                                                      TRUE,
512                                                      &ObjectCreateInfo->
513                                                      SecurityDescriptor);
514                 if (!NT_SUCCESS(Status))
515                 {
516                     /* Capture failed, quit */
517                     ObjectCreateInfo->SecurityDescriptor = NULL;
518                     _SEH2_YIELD(return Status);
519                 }
520 
521                 /*
522                  * By default, assume a SD size of 1024 and allow twice its
523                  * size.
524                  * If SD size happen to be bigger than that, then allow it
525                  */
526                 SdCharge = 2048;
527                 SeComputeQuotaInformationSize(ObjectCreateInfo->SecurityDescriptor,
528                                               &QuotaInfoSize);
529                 if ((2 * QuotaInfoSize) > 2048)
530                 {
531                     SdCharge = 2 * QuotaInfoSize;
532                 }
533 
534                 /* Save the probe mode and security descriptor size */
535                 ObjectCreateInfo->SecurityDescriptorCharge = SdCharge;
536                 ObjectCreateInfo->ProbeMode = AccessMode;
537             }
538 
539             /* Check if we have QoS */
540             if (SecurityQos)
541             {
542                 /* Check if we came from user mode */
543                 if (AccessMode != KernelMode)
544                 {
545                     /* Validate the QoS */
546                     ProbeForRead(SecurityQos,
547                                  sizeof(SECURITY_QUALITY_OF_SERVICE),
548                                  sizeof(ULONG));
549                 }
550 
551                 /* Save Info */
552                 ObjectCreateInfo->SecurityQualityOfService = *SecurityQos;
553                 ObjectCreateInfo->SecurityQos =
554                     &ObjectCreateInfo->SecurityQualityOfService;
555             }
556         }
557         else
558         {
559             /* We don't have a name */
560             LocalObjectName = NULL;
561         }
562     }
563     _SEH2_EXCEPT(ExSystemExceptionFilter())
564     {
565         /* Cleanup and return the exception code */
566         ObpReleaseObjectCreateInformation(ObjectCreateInfo);
567         _SEH2_YIELD(return _SEH2_GetExceptionCode());
568     }
569     _SEH2_END;
570 
571     /* Now check if the Object Attributes had an Object Name */
572     if (LocalObjectName)
573     {
574         Status = ObpCaptureObjectName(ObjectName,
575                                       LocalObjectName,
576                                       AccessMode,
577                                       AllocateFromLookaside);
578     }
579     else
580     {
581         /* Clear the string */
582         RtlInitEmptyUnicodeString(ObjectName, NULL, 0);
583 
584         /* It cannot have specified a Root Directory */
585         if (ObjectCreateInfo->RootDirectory)
586         {
587             Status = STATUS_OBJECT_NAME_INVALID;
588         }
589     }
590 
591     /* Cleanup if we failed */
592     if (!NT_SUCCESS(Status))
593     {
594         ObpReleaseObjectCreateInformation(ObjectCreateInfo);
595     }
596 
597     /* Return status to caller */
598     return Status;
599 }
600 
601 VOID
602 NTAPI
603 ObFreeObjectCreateInfoBuffer(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo)
604 {
605     /* Call the macro. We use this function to isolate Ob internals from Io */
606     ObpFreeCapturedAttributes(ObjectCreateInfo, LookasideCreateInfoList);
607 }
608 
609 NTSTATUS
610 NTAPI
611 ObpAllocateObject(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo,
612                   IN PUNICODE_STRING ObjectName,
613                   IN POBJECT_TYPE ObjectType,
614                   IN ULONG ObjectSize,
615                   IN KPROCESSOR_MODE PreviousMode,
616                   IN POBJECT_HEADER *ObjectHeader)
617 {
618     POBJECT_HEADER Header;
619     ULONG QuotaSize, HandleSize, NameSize, CreatorSize;
620     POBJECT_HEADER_HANDLE_INFO HandleInfo;
621     POBJECT_HEADER_NAME_INFO NameInfo;
622     POBJECT_HEADER_CREATOR_INFO CreatorInfo;
623     POBJECT_HEADER_QUOTA_INFO QuotaInfo;
624     POOL_TYPE PoolType;
625     ULONG FinalSize;
626     ULONG Tag;
627     PAGED_CODE();
628 
629     /* Accounting */
630     ObpObjectsCreated++;
631 
632     /* Check if we don't have an Object Type yet */
633     if (!ObjectType)
634     {
635         /* Use default tag and non-paged pool */
636         PoolType = NonPagedPool;
637         Tag = TAG_OBJECT_TYPE;
638     }
639     else
640     {
641         /* Use the pool and tag given */
642         PoolType = ObjectType->TypeInfo.PoolType;
643         Tag = ObjectType->Key;
644     }
645 
646     /* Check if we have no create information (ie: we're an object type) */
647     if (!ObjectCreateInfo)
648     {
649         /* Use defaults */
650         QuotaSize = HandleSize = 0;
651         NameSize = sizeof(OBJECT_HEADER_NAME_INFO);
652         CreatorSize = sizeof(OBJECT_HEADER_CREATOR_INFO);
653     }
654     else
655     {
656         /* Check if we have quota */
657         if ((((ObjectCreateInfo->PagedPoolCharge !=
658                ObjectType->TypeInfo.DefaultPagedPoolCharge) ||
659               (ObjectCreateInfo->NonPagedPoolCharge !=
660                ObjectType->TypeInfo.DefaultNonPagedPoolCharge) ||
661               (ObjectCreateInfo->SecurityDescriptorCharge > 2048)) &&
662              (PsGetCurrentProcess() != PsInitialSystemProcess)) ||
663             (ObjectCreateInfo->Attributes & OBJ_EXCLUSIVE))
664         {
665             /* Set quota size */
666             QuotaSize = sizeof(OBJECT_HEADER_QUOTA_INFO);
667             ObpObjectsWithPoolQuota++;
668         }
669         else
670         {
671             /* No Quota */
672             QuotaSize = 0;
673         }
674 
675         /* Check if we have a handle database */
676         if (ObjectType->TypeInfo.MaintainHandleCount)
677         {
678             /* Set handle database size */
679             HandleSize = sizeof(OBJECT_HEADER_HANDLE_INFO);
680             ObpObjectsWithHandleDB++;
681         }
682         else
683         {
684             /* None */
685             HandleSize = 0;
686         }
687 
688         /* Check if the Object has a name */
689         if (ObjectName->Buffer)
690         {
691             /* Set name size */
692             NameSize = sizeof(OBJECT_HEADER_NAME_INFO);
693             ObpObjectsWithName++;
694         }
695         else
696         {
697             /* No name */
698             NameSize = 0;
699         }
700 
701         /* Check if the Object maintains type lists */
702         if (ObjectType->TypeInfo.MaintainTypeList)
703         {
704             /* Set owner/creator size */
705             CreatorSize = sizeof(OBJECT_HEADER_CREATOR_INFO);
706             ObpObjectsWithCreatorInfo++;
707         }
708         else
709         {
710             /* No info */
711             CreatorSize = 0;
712         }
713     }
714 
715     /* Set final header size */
716     FinalSize = QuotaSize +
717                 HandleSize +
718                 NameSize +
719                 CreatorSize +
720                 FIELD_OFFSET(OBJECT_HEADER, Body);
721 
722     /* Allocate memory for the Object and Header */
723     Header = ExAllocatePoolWithTag(PoolType, FinalSize + ObjectSize, Tag);
724     if (!Header) return STATUS_INSUFFICIENT_RESOURCES;
725 
726     /* Check if we have a quota header */
727     if (QuotaSize)
728     {
729         /* Initialize quota info */
730         QuotaInfo = (POBJECT_HEADER_QUOTA_INFO)Header;
731         QuotaInfo->PagedPoolCharge = ObjectCreateInfo->PagedPoolCharge;
732         QuotaInfo->NonPagedPoolCharge = ObjectCreateInfo->NonPagedPoolCharge;
733         QuotaInfo->SecurityDescriptorCharge = ObjectCreateInfo->SecurityDescriptorCharge;
734         QuotaInfo->ExclusiveProcess = NULL;
735         Header = (POBJECT_HEADER)(QuotaInfo + 1);
736     }
737 
738     /* Check if we have a handle database header */
739     if (HandleSize)
740     {
741         /* Initialize Handle Info */
742         HandleInfo = (POBJECT_HEADER_HANDLE_INFO)Header;
743         HandleInfo->SingleEntry.HandleCount = 0;
744         Header = (POBJECT_HEADER)(HandleInfo + 1);
745     }
746 
747     /* Check if we have a name header */
748     if (NameSize)
749     {
750         /* Initialize the Object Name Info */
751         NameInfo = (POBJECT_HEADER_NAME_INFO)Header;
752         NameInfo->Name = *ObjectName;
753         NameInfo->Directory = NULL;
754         NameInfo->QueryReferences = 1;
755 
756         /* Check if this is a call with the special protection flag */
757         if ((PreviousMode == KernelMode) &&
758             (ObjectCreateInfo) &&
759             (ObjectCreateInfo->Attributes & OBJ_KERNEL_EXCLUSIVE))
760         {
761             /* Set flag which will make the object protected from user-mode */
762             NameInfo->QueryReferences |= OB_FLAG_KERNEL_EXCLUSIVE;
763         }
764 
765         /* Set the header pointer */
766         Header = (POBJECT_HEADER)(NameInfo + 1);
767     }
768 
769     /* Check if we have a creator header */
770     if (CreatorSize)
771     {
772         /* Initialize Creator Info */
773         CreatorInfo = (POBJECT_HEADER_CREATOR_INFO)Header;
774         CreatorInfo->CreatorBackTraceIndex = 0;
775         CreatorInfo->CreatorUniqueProcess = PsGetCurrentProcessId();
776         InitializeListHead(&CreatorInfo->TypeList);
777         Header = (POBJECT_HEADER)(CreatorInfo + 1);
778     }
779 
780     /* Check for quota information */
781     if (QuotaSize)
782     {
783         /* Set the offset */
784         Header->QuotaInfoOffset = (UCHAR)(QuotaSize +
785                                           HandleSize +
786                                           NameSize +
787                                           CreatorSize);
788     }
789     else
790     {
791         /* No offset */
792         Header->QuotaInfoOffset = 0;
793     }
794 
795     /* Check for handle information */
796     if (HandleSize)
797     {
798         /* Set the offset */
799         Header->HandleInfoOffset = (UCHAR)(HandleSize +
800                                            NameSize +
801                                            CreatorSize);
802     }
803     else
804     {
805         /* No offset */
806         Header->HandleInfoOffset = 0;
807     }
808 
809     /* Check for name information */
810     if (NameSize)
811     {
812         /* Set the offset */
813         Header->NameInfoOffset = (UCHAR)(NameSize + CreatorSize);
814     }
815     else
816     {
817         /* No Name */
818         Header->NameInfoOffset = 0;
819     }
820 
821     /* Set the new object flag */
822     Header->Flags = OB_FLAG_CREATE_INFO;
823 
824     /* Remember if we have creator info */
825     if (CreatorSize) Header->Flags |= OB_FLAG_CREATOR_INFO;
826 
827     /* Remember if we have handle info */
828     if (HandleSize) Header->Flags |= OB_FLAG_SINGLE_PROCESS;
829 
830     /* Initialize the object header */
831     Header->PointerCount = 1;
832     Header->HandleCount = 0;
833     Header->Type = ObjectType;
834     Header->ObjectCreateInfo = ObjectCreateInfo;
835     Header->SecurityDescriptor = NULL;
836 
837     /* Check if this is a permanent object */
838     if ((ObjectCreateInfo) && (ObjectCreateInfo->Attributes & OBJ_PERMANENT))
839     {
840         /* Set the needed flag so we can check */
841         Header->Flags |= OB_FLAG_PERMANENT;
842     }
843 
844     /* Check if this is an exclusive object */
845     if ((ObjectCreateInfo) && (ObjectCreateInfo->Attributes & OBJ_EXCLUSIVE))
846     {
847         /* Set the needed flag so we can check */
848         Header->Flags |= OB_FLAG_EXCLUSIVE;
849     }
850 
851     /* Set kernel-mode flag */
852     if (PreviousMode == KernelMode) Header->Flags |= OB_FLAG_KERNEL_MODE;
853 
854     /* Check if we have a type */
855     if (ObjectType)
856     {
857         /* Increase the number of objects of this type */
858         InterlockedIncrement((PLONG)&ObjectType->TotalNumberOfObjects);
859 
860         /* Update the high water */
861         ObjectType->HighWaterNumberOfObjects = max(ObjectType->
862                                                    TotalNumberOfObjects,
863                                                    ObjectType->
864                                                    HighWaterNumberOfObjects);
865     }
866 
867     /* Return Header */
868     *ObjectHeader = Header;
869     return STATUS_SUCCESS;
870 }
871 
872 NTSTATUS
873 NTAPI
874 ObQueryTypeInfo(IN POBJECT_TYPE ObjectType,
875                 OUT POBJECT_TYPE_INFORMATION ObjectTypeInfo,
876                 IN ULONG Length,
877                 OUT PULONG ReturnLength)
878 {
879     NTSTATUS Status = STATUS_SUCCESS;
880     PWSTR InfoBuffer;
881 
882     /* Enter SEH */
883     _SEH2_TRY
884     {
885         /* Set return length aligned to 4-byte boundary */
886         *ReturnLength += sizeof(*ObjectTypeInfo) +
887                          ALIGN_UP(ObjectType->Name.MaximumLength, ULONG);
888 
889         /* Check if thats too much though. */
890         if (Length < *ReturnLength)
891         {
892             _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH);
893         }
894 
895         /* Build the data */
896         ObjectTypeInfo->TotalNumberOfHandles =
897             ObjectType->TotalNumberOfHandles;
898         ObjectTypeInfo->TotalNumberOfObjects =
899             ObjectType->TotalNumberOfObjects;
900         ObjectTypeInfo->HighWaterNumberOfHandles =
901             ObjectType->HighWaterNumberOfHandles;
902         ObjectTypeInfo->HighWaterNumberOfObjects =
903             ObjectType->HighWaterNumberOfObjects;
904         ObjectTypeInfo->PoolType =
905             ObjectType->TypeInfo.PoolType;
906         ObjectTypeInfo->DefaultNonPagedPoolCharge =
907             ObjectType->TypeInfo.DefaultNonPagedPoolCharge;
908         ObjectTypeInfo->DefaultPagedPoolCharge =
909             ObjectType->TypeInfo.DefaultPagedPoolCharge;
910         ObjectTypeInfo->ValidAccessMask =
911             ObjectType->TypeInfo.ValidAccessMask;
912         ObjectTypeInfo->SecurityRequired =
913             ObjectType->TypeInfo.SecurityRequired;
914         ObjectTypeInfo->InvalidAttributes =
915             ObjectType->TypeInfo.InvalidAttributes;
916         ObjectTypeInfo->GenericMapping =
917             ObjectType->TypeInfo.GenericMapping;
918         ObjectTypeInfo->MaintainHandleCount =
919             ObjectType->TypeInfo.MaintainHandleCount;
920 
921         /* Setup the name buffer */
922         InfoBuffer = (PWSTR)(ObjectTypeInfo + 1);
923         ObjectTypeInfo->TypeName.Buffer = InfoBuffer;
924         ObjectTypeInfo->TypeName.MaximumLength = ObjectType->Name.MaximumLength;
925         ObjectTypeInfo->TypeName.Length = ObjectType->Name.Length;
926 
927         /* Copy it */
928         RtlCopyMemory(InfoBuffer,
929                       ObjectType->Name.Buffer,
930                       ObjectType->Name.Length);
931 
932         /* Null-terminate it */
933         (InfoBuffer)[ObjectType->Name.Length / sizeof(WCHAR)] = UNICODE_NULL;
934     }
935     _SEH2_EXCEPT(ExSystemExceptionFilter())
936     {
937         /* Otherwise, get the exception code */
938         Status = _SEH2_GetExceptionCode();
939     }
940     _SEH2_END;
941 
942     /* Return status to caller */
943     return Status;
944 }
945 
946 
947 /* PUBLIC FUNCTIONS **********************************************************/
948 
949 NTSTATUS
950 NTAPI
951 ObCreateObject(IN KPROCESSOR_MODE ProbeMode OPTIONAL,
952                IN POBJECT_TYPE Type,
953                IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
954                IN KPROCESSOR_MODE AccessMode,
955                IN OUT PVOID ParseContext OPTIONAL,
956                IN ULONG ObjectSize,
957                IN ULONG PagedPoolCharge OPTIONAL,
958                IN ULONG NonPagedPoolCharge OPTIONAL,
959                OUT PVOID *Object)
960 {
961     NTSTATUS Status;
962     POBJECT_CREATE_INFORMATION ObjectCreateInfo;
963     UNICODE_STRING ObjectName;
964     POBJECT_HEADER Header;
965 
966     /* Allocate a capture buffer */
967     ObjectCreateInfo = ObpAllocateObjectCreateInfoBuffer(LookasideCreateInfoList);
968     if (!ObjectCreateInfo) return STATUS_INSUFFICIENT_RESOURCES;
969 
970     /* Capture all the info */
971     Status = ObpCaptureObjectCreateInformation(ObjectAttributes,
972                                                ProbeMode,
973                                                AccessMode,
974                                                FALSE,
975                                                ObjectCreateInfo,
976                                                &ObjectName);
977     if (NT_SUCCESS(Status))
978     {
979         /* Validate attributes */
980         if (Type->TypeInfo.InvalidAttributes & ObjectCreateInfo->Attributes)
981         {
982             /* Fail */
983             Status = STATUS_INVALID_PARAMETER;
984         }
985         else
986         {
987             /* Check if we have a paged charge */
988             if (!PagedPoolCharge)
989             {
990                 /* Save it */
991                 PagedPoolCharge = Type->TypeInfo.DefaultPagedPoolCharge;
992             }
993 
994             /* Check for nonpaged charge */
995             if (!NonPagedPoolCharge)
996             {
997                 /* Save it */
998                 NonPagedPoolCharge = Type->TypeInfo.DefaultNonPagedPoolCharge;
999             }
1000 
1001             /* Write the pool charges */
1002             ObjectCreateInfo->PagedPoolCharge = PagedPoolCharge;
1003             ObjectCreateInfo->NonPagedPoolCharge = NonPagedPoolCharge;
1004 
1005             /* Allocate the Object */
1006             Status = ObpAllocateObject(ObjectCreateInfo,
1007                                        &ObjectName,
1008                                        Type,
1009                                        ObjectSize,
1010                                        AccessMode,
1011                                        &Header);
1012             if (NT_SUCCESS(Status))
1013             {
1014                 /* Return the Object */
1015                 *Object = &Header->Body;
1016 
1017                 /* Check if this is a permanent object */
1018                 if (Header->Flags & OB_FLAG_PERMANENT)
1019                 {
1020                     /* Do the privilege check */
1021                     if (!SeSinglePrivilegeCheck(SeCreatePermanentPrivilege,
1022                                                 ProbeMode))
1023                     {
1024                         /* Fail */
1025                         ObpDeallocateObject(*Object);
1026                         Status = STATUS_PRIVILEGE_NOT_HELD;
1027                     }
1028                 }
1029 
1030                 /* Return status */
1031                 return Status;
1032             }
1033         }
1034 
1035         /* Release the Capture Info, we don't need it */
1036         ObpFreeObjectCreateInformation(ObjectCreateInfo);
1037         if (ObjectName.Buffer) ObpFreeObjectNameBuffer(&ObjectName);
1038     }
1039 
1040     /* We failed, so release the Buffer */
1041     ObpFreeCapturedAttributes(ObjectCreateInfo, LookasideCreateInfoList);
1042     return Status;
1043 }
1044 
1045 NTSTATUS
1046 NTAPI
1047 ObCreateObjectType(IN PUNICODE_STRING TypeName,
1048                    IN POBJECT_TYPE_INITIALIZER ObjectTypeInitializer,
1049                    IN PVOID Reserved,
1050                    OUT POBJECT_TYPE *ObjectType)
1051 {
1052     POBJECT_HEADER Header;
1053     POBJECT_TYPE LocalObjectType;
1054     ULONG HeaderSize;
1055     NTSTATUS Status;
1056     OBP_LOOKUP_CONTEXT Context;
1057     PWCHAR p;
1058     ULONG i;
1059     UNICODE_STRING ObjectName;
1060     ANSI_STRING AnsiName;
1061     POBJECT_HEADER_CREATOR_INFO CreatorInfo;
1062 
1063     /* Verify parameters */
1064     if (!(TypeName) ||
1065         !(TypeName->Length) ||
1066         (TypeName->Length % sizeof(WCHAR)) ||
1067         !(ObjectTypeInitializer) ||
1068         (ObjectTypeInitializer->Length != sizeof(*ObjectTypeInitializer)) ||
1069         (ObjectTypeInitializer->InvalidAttributes & ~OBJ_VALID_KERNEL_ATTRIBUTES) ||
1070         (ObjectTypeInitializer->MaintainHandleCount &&
1071          (!(ObjectTypeInitializer->OpenProcedure) &&
1072           !ObjectTypeInitializer->CloseProcedure)) ||
1073         ((!ObjectTypeInitializer->UseDefaultObject) &&
1074          (ObjectTypeInitializer->PoolType != NonPagedPool)))
1075     {
1076         /* Fail */
1077         return STATUS_INVALID_PARAMETER;
1078     }
1079 
1080     /* Make sure the name doesn't have a separator */
1081     p = TypeName->Buffer;
1082     i = TypeName->Length / sizeof(WCHAR);
1083     while (i--)
1084     {
1085         /* Check for one and fail */
1086         if (*p++ == OBJ_NAME_PATH_SEPARATOR) return STATUS_OBJECT_NAME_INVALID;
1087     }
1088 
1089     /* Setup a lookup context */
1090     ObpInitializeLookupContext(&Context);
1091 
1092     /* Check if we've already created the directory of types */
1093     if (ObpTypeDirectoryObject)
1094     {
1095         /* Lock the lookup context */
1096         ObpAcquireLookupContextLock(&Context, ObpTypeDirectoryObject);
1097 
1098         /* Do the lookup */
1099         if (ObpLookupEntryDirectory(ObpTypeDirectoryObject,
1100                                     TypeName,
1101                                     OBJ_CASE_INSENSITIVE,
1102                                     FALSE,
1103                                     &Context))
1104         {
1105             /* We have already created it, so fail */
1106             ObpReleaseLookupContext(&Context);
1107             return STATUS_OBJECT_NAME_COLLISION;
1108         }
1109     }
1110 
1111     /* Now make a copy of the object name */
1112     ObjectName.Buffer = ExAllocatePoolWithTag(PagedPool,
1113                                               TypeName->MaximumLength,
1114                                               OB_NAME_TAG);
1115     if (!ObjectName.Buffer)
1116     {
1117         /* Out of memory, fail */
1118         ObpReleaseLookupContext(&Context);
1119         return STATUS_INSUFFICIENT_RESOURCES;
1120     }
1121 
1122     /* Set the length and copy the name */
1123     ObjectName.MaximumLength = TypeName->MaximumLength;
1124     RtlCopyUnicodeString(&ObjectName, TypeName);
1125 
1126     /* Allocate the Object */
1127     Status = ObpAllocateObject(NULL,
1128                                &ObjectName,
1129                                ObpTypeObjectType,
1130                                sizeof(OBJECT_TYPE),
1131                                KernelMode,
1132                                &Header);
1133     if (!NT_SUCCESS(Status))
1134     {
1135         /* Free the name and fail */
1136         ObpReleaseLookupContext(&Context);
1137         ExFreePool(ObjectName.Buffer);
1138         return Status;
1139     }
1140 
1141     /* Setup the flags and name */
1142     LocalObjectType = (POBJECT_TYPE)&Header->Body;
1143     LocalObjectType->Name = ObjectName;
1144     Header->Flags |= OB_FLAG_KERNEL_MODE | OB_FLAG_PERMANENT;
1145 
1146     /* Clear accounting data */
1147     LocalObjectType->TotalNumberOfObjects =
1148     LocalObjectType->TotalNumberOfHandles =
1149     LocalObjectType->HighWaterNumberOfObjects =
1150     LocalObjectType->HighWaterNumberOfHandles = 0;
1151 
1152     /* Check if this is the first Object Type */
1153     if (!ObpTypeObjectType)
1154     {
1155         /* It is, so set this as the type object */
1156         ObpTypeObjectType = LocalObjectType;
1157         Header->Type = ObpTypeObjectType;
1158 
1159         /* Set the hard-coded key and object count */
1160         LocalObjectType->TotalNumberOfObjects = 1;
1161         LocalObjectType->Key = TAG_OBJECT_TYPE;
1162     }
1163     else
1164     {
1165         /* Convert the tag to ASCII */
1166         Status = RtlUnicodeStringToAnsiString(&AnsiName, TypeName, TRUE);
1167         if (NT_SUCCESS(Status))
1168         {
1169             /* For every missing character, use a space */
1170             for (i = 3; i >= AnsiName.Length; i--) AnsiName.Buffer[i] = ' ';
1171 
1172             /* Set the key and free the converted name */
1173             LocalObjectType->Key = *(PULONG)AnsiName.Buffer;
1174             RtlFreeAnsiString(&AnsiName);
1175         }
1176         else
1177         {
1178             /* Just copy the characters */
1179             LocalObjectType->Key = *(PULONG)TypeName->Buffer;
1180         }
1181     }
1182 
1183     /* Set up the type information */
1184     LocalObjectType->TypeInfo = *ObjectTypeInitializer;
1185     LocalObjectType->TypeInfo.PoolType = ObjectTypeInitializer->PoolType;
1186 
1187     /* Check if we have to maintain a type list */
1188     if (NtGlobalFlag & FLG_MAINTAIN_OBJECT_TYPELIST)
1189     {
1190         /* Enable support */
1191         LocalObjectType->TypeInfo.MaintainTypeList = TRUE;
1192     }
1193 
1194     /* Calculate how much space our header'll take up */
1195     HeaderSize = sizeof(OBJECT_HEADER) +
1196                  sizeof(OBJECT_HEADER_NAME_INFO) +
1197                  (ObjectTypeInitializer->MaintainHandleCount ?
1198                   sizeof(OBJECT_HEADER_HANDLE_INFO) : 0);
1199 
1200     /* Check the pool type */
1201     if (ObjectTypeInitializer->PoolType == NonPagedPool)
1202     {
1203         /* Update the NonPaged Pool charge */
1204         LocalObjectType->TypeInfo.DefaultNonPagedPoolCharge += HeaderSize;
1205     }
1206     else
1207     {
1208         /* Update the Paged Pool charge */
1209         LocalObjectType->TypeInfo.DefaultPagedPoolCharge += HeaderSize;
1210     }
1211 
1212     /* All objects types need a security procedure */
1213     if (!ObjectTypeInitializer->SecurityProcedure)
1214     {
1215         LocalObjectType->TypeInfo.SecurityProcedure = SeDefaultObjectMethod;
1216     }
1217 
1218     /* Select the Wait Object */
1219     if (LocalObjectType->TypeInfo.UseDefaultObject)
1220     {
1221         /* Add the SYNCHRONIZE access mask since it's waitable */
1222         LocalObjectType->TypeInfo.ValidAccessMask |= SYNCHRONIZE;
1223 
1224         /* Use the "Default Object", a simple event */
1225         LocalObjectType->DefaultObject = &ObpDefaultObject;
1226     }
1227     /* The File Object gets an optimized hack so it can be waited on */
1228     else if ((TypeName->Length == 8) && !(wcscmp(TypeName->Buffer, L"File")))
1229     {
1230         /* Wait on the File Object's event directly */
1231         LocalObjectType->DefaultObject = UlongToPtr(FIELD_OFFSET(FILE_OBJECT,
1232                                                                  Event));
1233     }
1234     else if ((TypeName->Length == 24) && !(wcscmp(TypeName->Buffer, L"WaitablePort")))
1235     {
1236         /* Wait on the LPC Port's object directly */
1237         LocalObjectType->DefaultObject = UlongToPtr(FIELD_OFFSET(LPCP_PORT_OBJECT,
1238                                                                  WaitEvent));
1239     }
1240     else
1241     {
1242         /* No default Object */
1243         LocalObjectType->DefaultObject = NULL;
1244     }
1245 
1246     /* Initialize Object Type components */
1247     ExInitializeResourceLite(&LocalObjectType->Mutex);
1248     for (i = 0; i < 4; i++)
1249     {
1250         /* Initialize the object locks */
1251         ExInitializeResourceLite(&LocalObjectType->ObjectLocks[i]);
1252     }
1253     InitializeListHead(&LocalObjectType->TypeList);
1254 
1255     /* Lock the object type */
1256     ObpEnterObjectTypeMutex(ObpTypeObjectType);
1257 
1258     /* Get creator info and insert it into the type list */
1259     CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(Header);
1260     if (CreatorInfo)
1261     {
1262         InsertTailList(&ObpTypeObjectType->TypeList,
1263                        &CreatorInfo->TypeList);
1264 
1265         /* CORE-8423: Avoid inserting this a second time if someone creates a
1266          * handle to the object type (bug in Windows 2003) */
1267         Header->Flags &= ~OB_FLAG_CREATE_INFO;
1268     }
1269 
1270     /* Set the index and the entry into the object type array */
1271     LocalObjectType->Index = ObpTypeObjectType->TotalNumberOfObjects;
1272 
1273     ASSERT(LocalObjectType->Index != 0);
1274 
1275     if (LocalObjectType->Index < RTL_NUMBER_OF(ObpObjectTypes))
1276     {
1277         /* It fits, insert it */
1278         ObpObjectTypes[LocalObjectType->Index - 1] = LocalObjectType;
1279     }
1280 
1281     /* Release the object type */
1282     ObpLeaveObjectTypeMutex(ObpTypeObjectType);
1283 
1284     /* Check if we're actually creating the directory object itself */
1285     if (!(ObpTypeDirectoryObject) ||
1286         (ObpInsertEntryDirectory(ObpTypeDirectoryObject, &Context, Header)))
1287     {
1288         /* Check if the type directory exists */
1289         if (ObpTypeDirectoryObject)
1290         {
1291             /* Reference it */
1292             ObReferenceObject(ObpTypeDirectoryObject);
1293         }
1294 
1295         /* Cleanup the lookup context */
1296         ObpReleaseLookupContext(&Context);
1297 
1298         /* Return the object type and success */
1299         *ObjectType = LocalObjectType;
1300         return STATUS_SUCCESS;
1301     }
1302 
1303     /* If we got here, then we failed */
1304     ObpReleaseLookupContext(&Context);
1305     return STATUS_INSUFFICIENT_RESOURCES;
1306 }
1307 
1308 VOID
1309 NTAPI
1310 ObDeleteCapturedInsertInfo(IN PVOID Object)
1311 {
1312     POBJECT_HEADER ObjectHeader;
1313     PAGED_CODE();
1314 
1315     /* Check if there is anything to free */
1316     ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
1317     if ((ObjectHeader->Flags & OB_FLAG_CREATE_INFO) &&
1318         (ObjectHeader->ObjectCreateInfo != NULL))
1319     {
1320         /* Free the create info */
1321         ObpFreeObjectCreateInformation(ObjectHeader->ObjectCreateInfo);
1322         ObjectHeader->ObjectCreateInfo = NULL;
1323     }
1324 }
1325 
1326 VOID
1327 NTAPI
1328 ObpDeleteObjectType(IN PVOID Object)
1329 {
1330     ULONG i;
1331     POBJECT_TYPE ObjectType = (PVOID)Object;
1332 
1333     /* Loop our locks */
1334     for (i = 0; i < 4; i++)
1335     {
1336         /* Delete each one */
1337         ExDeleteResourceLite(&ObjectType->ObjectLocks[i]);
1338     }
1339 
1340     /* Delete our main mutex */
1341     ExDeleteResourceLite(&ObjectType->Mutex);
1342 }
1343 
1344 /*++
1345 * @name ObMakeTemporaryObject
1346 * @implemented NT4
1347 *
1348 *     The ObMakeTemporaryObject routine <FILLMEIN>
1349 *
1350 * @param ObjectBody
1351 *        <FILLMEIN>
1352 *
1353 * @return None.
1354 *
1355 * @remarks None.
1356 *
1357 *--*/
1358 VOID
1359 NTAPI
1360 ObMakeTemporaryObject(IN PVOID ObjectBody)
1361 {
1362     PAGED_CODE();
1363 
1364     /* Call the internal API */
1365     ObpSetPermanentObject(ObjectBody, FALSE);
1366 }
1367 
1368 /*++
1369 * @name NtMakeTemporaryObject
1370 * @implemented NT4
1371 *
1372 *     The NtMakeTemporaryObject routine <FILLMEIN>
1373 *
1374 * @param ObjectHandle
1375 *        <FILLMEIN>
1376 *
1377 * @return STATUS_SUCCESS or appropriate error value.
1378 *
1379 * @remarks None.
1380 *
1381 *--*/
1382 NTSTATUS
1383 NTAPI
1384 NtMakeTemporaryObject(IN HANDLE ObjectHandle)
1385 {
1386     PVOID ObjectBody;
1387     NTSTATUS Status;
1388     PAGED_CODE();
1389 
1390     /* Reference the object for DELETE access */
1391     Status = ObReferenceObjectByHandle(ObjectHandle,
1392                                        DELETE,
1393                                        NULL,
1394                                        KeGetPreviousMode(),
1395                                        &ObjectBody,
1396                                        NULL);
1397     if (Status != STATUS_SUCCESS) return Status;
1398 
1399     /* Set it as temporary and dereference it */
1400     ObpSetPermanentObject(ObjectBody, FALSE);
1401     ObDereferenceObject(ObjectBody);
1402     return STATUS_SUCCESS;
1403 }
1404 
1405 /*++
1406 * @name NtMakePermanentObject
1407 * @implemented NT4
1408 *
1409 *     The NtMakePermanentObject routine <FILLMEIN>
1410 *
1411 * @param ObjectHandle
1412 *        <FILLMEIN>
1413 *
1414 * @return STATUS_SUCCESS or appropriate error value.
1415 *
1416 * @remarks None.
1417 *
1418 *--*/
1419 NTSTATUS
1420 NTAPI
1421 NtMakePermanentObject(IN HANDLE ObjectHandle)
1422 {
1423     PVOID ObjectBody;
1424     NTSTATUS Status;
1425     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1426     PAGED_CODE();
1427 
1428     /* Make sure that the caller has SeCreatePermanentPrivilege */
1429     if (!SeSinglePrivilegeCheck(SeCreatePermanentPrivilege, PreviousMode))
1430     {
1431         return STATUS_PRIVILEGE_NOT_HELD;
1432     }
1433 
1434     /* Reference the object */
1435     Status = ObReferenceObjectByHandle(ObjectHandle,
1436                                        0,
1437                                        NULL,
1438                                        PreviousMode,
1439                                        &ObjectBody,
1440                                        NULL);
1441     if (Status != STATUS_SUCCESS) return Status;
1442 
1443     /* Set it as permanent and dereference it */
1444     ObpSetPermanentObject(ObjectBody, TRUE);
1445     ObDereferenceObject(ObjectBody);
1446     return STATUS_SUCCESS;
1447 }
1448 
1449 /*++
1450 * @name NtQueryObject
1451 * @implemented NT4
1452 *
1453 *     The NtQueryObject routine <FILLMEIN>
1454 *
1455 * @param ObjectHandle
1456 *        <FILLMEIN>
1457 *
1458 * @param ObjectInformationClass
1459 *        <FILLMEIN>
1460 *
1461 * @param ObjectInformation
1462 *        <FILLMEIN>
1463 *
1464 * @param Length
1465 *        <FILLMEIN>
1466 *
1467 * @param ResultLength
1468 *        <FILLMEIN>
1469 *
1470 * @return STATUS_SUCCESS or appropriate error value.
1471 *
1472 * @remarks None.
1473 *
1474 *--*/
1475 NTSTATUS
1476 NTAPI
1477 NtQueryObject(IN HANDLE ObjectHandle,
1478               IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
1479               OUT PVOID ObjectInformation,
1480               IN ULONG Length,
1481               OUT PULONG ResultLength OPTIONAL)
1482 {
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;
1489     NTSTATUS Status;
1490     POBJECT_HEADER_QUOTA_INFO ObjectQuota;
1491     SECURITY_INFORMATION SecurityInformation;
1492     POBJECT_TYPE ObjectType;
1493     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1494     PAGED_CODE();
1495 
1496     /* Check if the caller is from user mode */
1497     if (PreviousMode != KernelMode)
1498     {
1499         /* Protect validation with SEH */
1500         _SEH2_TRY
1501         {
1502             /* Probe the input structure */
1503             ProbeForWrite(ObjectInformation, Length, sizeof(UCHAR));
1504 
1505             /* If we have a result length, probe it too */
1506             if (ResultLength) ProbeForWriteUlong(ResultLength);
1507         }
1508         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1509         {
1510             /* Return the exception code */
1511             _SEH2_YIELD(return _SEH2_GetExceptionCode());
1512         }
1513         _SEH2_END;
1514     }
1515 
1516     /*
1517      * Make sure this isn't a generic type query, since the caller doesn't
1518      * have to give a handle for it
1519      */
1520     if (ObjectInformationClass != ObjectTypesInformation)
1521     {
1522         /* Reference the object */
1523         Status = ObReferenceObjectByHandle(ObjectHandle,
1524                                            0,
1525                                            NULL,
1526                                            KeGetPreviousMode(),
1527                                            &Object,
1528                                            &HandleInfo);
1529         if (!NT_SUCCESS (Status)) return Status;
1530 
1531         /* Get the object header */
1532         ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
1533         ObjectType = ObjectHeader->Type;
1534     }
1535 
1536     _SEH2_TRY
1537     {
1538         /* Check the information class */
1539         switch (ObjectInformationClass)
1540         {
1541             /* Basic info */
1542             case ObjectBasicInformation:
1543 
1544                 /* Validate length */
1545                 InfoLength = sizeof(OBJECT_BASIC_INFORMATION);
1546                 if (Length != sizeof(OBJECT_BASIC_INFORMATION))
1547                 {
1548                     /* Fail */
1549                     Status = STATUS_INFO_LENGTH_MISMATCH;
1550                     break;
1551                 }
1552 
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;
1559 
1560                 /* Permanent/Exclusive Flags are NOT in Handle attributes! */
1561                 if (ObjectHeader->Flags & OB_FLAG_EXCLUSIVE)
1562                 {
1563                     /* Set the flag */
1564                     BasicInfo->Attributes |= OBJ_EXCLUSIVE;
1565                 }
1566                 if (ObjectHeader->Flags & OB_FLAG_PERMANENT)
1567                 {
1568                     /* Set the flag */
1569                     BasicInfo->Attributes |= OBJ_PERMANENT;
1570                 }
1571 
1572                 /* Copy quota information */
1573                 ObjectQuota = OBJECT_HEADER_TO_QUOTA_INFO(ObjectHeader);
1574                 if (ObjectQuota != NULL)
1575                 {
1576                     BasicInfo->PagedPoolCharge = ObjectQuota->PagedPoolCharge;
1577                     BasicInfo->NonPagedPoolCharge = ObjectQuota->NonPagedPoolCharge;
1578                 }
1579                 else
1580                 {
1581                     BasicInfo->PagedPoolCharge = 0;
1582                     BasicInfo->NonPagedPoolCharge = 0;
1583                 }
1584 
1585                 /* Copy name information */
1586                 BasicInfo->NameInfoSize = 0; /* FIXME*/
1587                 BasicInfo->TypeInfoSize = 0; /* FIXME*/
1588 
1589                 /* Check if this is a symlink */
1590                 if (ObjectHeader->Type == ObpSymbolicLinkObjectType)
1591                 {
1592                     /* Return the creation time */
1593                     BasicInfo->CreationTime.QuadPart =
1594                         ((POBJECT_SYMBOLIC_LINK)Object)->CreationTime.QuadPart;
1595                 }
1596                 else
1597                 {
1598                     /* Otherwise return 0 */
1599                     BasicInfo->CreationTime.QuadPart = (ULONGLONG)0;
1600                 }
1601 
1602                 /* Copy security information */
1603                 BasicInfo->SecurityDescriptorSize = 0;
1604                 if (BooleanFlagOn(HandleInfo.GrantedAccess, READ_CONTROL) &&
1605                     ObjectHeader->SecurityDescriptor != NULL)
1606                 {
1607                     SecurityInformation = OWNER_SECURITY_INFORMATION |
1608                                           GROUP_SECURITY_INFORMATION |
1609                                           DACL_SECURITY_INFORMATION |
1610                                           SACL_SECURITY_INFORMATION;
1611 
1612                     ObjectType->TypeInfo.SecurityProcedure(Object,
1613                                                            QuerySecurityDescriptor,
1614                                                            &SecurityInformation,
1615                                                            NULL,
1616                                                            &BasicInfo->SecurityDescriptorSize,
1617                                                            &ObjectHeader->SecurityDescriptor,
1618                                                            ObjectType->TypeInfo.PoolType,
1619                                                            &ObjectType->TypeInfo.GenericMapping);
1620                 }
1621 
1622                 /* Break out with success */
1623                 Status = STATUS_SUCCESS;
1624                 break;
1625 
1626             /* Name information */
1627             case ObjectNameInformation:
1628 
1629                 /* Call the helper and break out */
1630                 Status = ObQueryNameString(Object,
1631                                            (POBJECT_NAME_INFORMATION)
1632                                            ObjectInformation,
1633                                            Length,
1634                                            &InfoLength);
1635                 break;
1636 
1637             /* Information about this type */
1638             case ObjectTypeInformation:
1639 
1640                 /* Call the helper and break out */
1641                 Status = ObQueryTypeInfo(ObjectHeader->Type,
1642                                          (POBJECT_TYPE_INFORMATION)
1643                                          ObjectInformation,
1644                                          Length,
1645                                          &InfoLength);
1646                 break;
1647 
1648             /* Information about all types */
1649             case ObjectTypesInformation:
1650                 DPRINT1("NOT IMPLEMENTED!\n");
1651                 InfoLength = Length;
1652                 Status = STATUS_NOT_IMPLEMENTED;
1653                 break;
1654 
1655             /* Information about the handle flags */
1656             case ObjectHandleFlagInformation:
1657 
1658                 /* Validate length */
1659                 InfoLength = sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION);
1660                 if (Length != sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION))
1661                 {
1662                     Status = STATUS_INFO_LENGTH_MISMATCH;
1663                     break;
1664                 }
1665 
1666                 /* Get the structure */
1667                 HandleFlags = (POBJECT_HANDLE_ATTRIBUTE_INFORMATION)
1668                                ObjectInformation;
1669 
1670                 /* Set the flags */
1671                 HandleFlags->Inherit = HandleInfo.HandleAttributes & OBJ_INHERIT;
1672                 HandleFlags->ProtectFromClose = (HandleInfo.HandleAttributes &
1673                                                  OBJ_PROTECT_CLOSE) != 0;
1674 
1675                 /* Break out with success */
1676                 Status = STATUS_SUCCESS;
1677                 break;
1678 
1679             /* Anything else */
1680             default:
1681 
1682                 /* Fail it */
1683                 InfoLength = Length;
1684                 Status = STATUS_INVALID_INFO_CLASS;
1685                 break;
1686         }
1687 
1688         /* Check if the caller wanted the return length */
1689         if (ResultLength)
1690         {
1691             /* Write the length */
1692             *ResultLength = InfoLength;
1693         }
1694     }
1695     _SEH2_EXCEPT(ExSystemExceptionFilter())
1696     {
1697         /* Otherwise, get the exception code */
1698         Status = _SEH2_GetExceptionCode();
1699     }
1700     _SEH2_END;
1701 
1702     /* Dereference the object if we had referenced it */
1703     if (Object) ObDereferenceObject(Object);
1704 
1705     /* Return status */
1706     return Status;
1707 }
1708 
1709 /*++
1710 * @name NtSetInformationObject
1711 * @implemented NT4
1712 *
1713 *     The NtSetInformationObject routine <FILLMEIN>
1714 *
1715 * @param ObjectHandle
1716 *        <FILLMEIN>
1717 *
1718 * @param ObjectInformationClass
1719 *        <FILLMEIN>
1720 *
1721 * @param ObjectInformation
1722 *        <FILLMEIN>
1723 *
1724 * @param Length
1725 *        <FILLMEIN>
1726 *
1727 * @return STATUS_SUCCESS or appropriate error value.
1728 *
1729 * @remarks None.
1730 *
1731 *--*/
1732 NTSTATUS
1733 NTAPI
1734 NtSetInformationObject(IN HANDLE ObjectHandle,
1735                        IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
1736                        IN PVOID ObjectInformation,
1737                        IN ULONG Length)
1738 {
1739     NTSTATUS Status;
1740     OBP_SET_HANDLE_ATTRIBUTES_CONTEXT Context;
1741     PVOID ObjectTable;
1742     KAPC_STATE ApcState;
1743     POBJECT_DIRECTORY Directory;
1744     KPROCESSOR_MODE PreviousMode;
1745     BOOLEAN AttachedToProcess = FALSE;
1746     PAGED_CODE();
1747 
1748     /* Validate the information class */
1749     switch (ObjectInformationClass)
1750     {
1751         case ObjectHandleFlagInformation:
1752 
1753             /* Validate the length */
1754             if (Length != sizeof(OBJECT_HANDLE_ATTRIBUTE_INFORMATION))
1755             {
1756                 /* Invalid length */
1757                 return STATUS_INFO_LENGTH_MISMATCH;
1758             }
1759 
1760             /* Save the previous mode */
1761             Context.PreviousMode = ExGetPreviousMode();
1762 
1763             /* Check if we were called from user mode */
1764             if (Context.PreviousMode != KernelMode)
1765             {
1766                 /* Enter SEH */
1767                 _SEH2_TRY
1768                 {
1769                     /* Probe and capture the attribute buffer */
1770                     ProbeForRead(ObjectInformation,
1771                                  sizeof(OBJECT_HANDLE_ATTRIBUTE_INFORMATION),
1772                                  sizeof(BOOLEAN));
1773                     Context.Information = *(POBJECT_HANDLE_ATTRIBUTE_INFORMATION)
1774                                             ObjectInformation;
1775                 }
1776                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1777                 {
1778                     /* Return the exception code */
1779                     _SEH2_YIELD(return _SEH2_GetExceptionCode());
1780                 }
1781                 _SEH2_END;
1782             }
1783             else
1784             {
1785                 /* Just copy the buffer directly */
1786                 Context.Information = *(POBJECT_HANDLE_ATTRIBUTE_INFORMATION)
1787                                         ObjectInformation;
1788             }
1789 
1790             /* Check if this is a kernel handle */
1791             if (ObpIsKernelHandle(ObjectHandle, Context.PreviousMode))
1792             {
1793                 /* Get the actual handle */
1794                 ObjectHandle = ObKernelHandleToHandle(ObjectHandle);
1795                 ObjectTable = ObpKernelHandleTable;
1796 
1797                 /* Check if we're not in the system process */
1798                 if (PsGetCurrentProcess() != PsInitialSystemProcess)
1799                 {
1800                     /* Attach to it */
1801                     KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
1802                     AttachedToProcess = TRUE;
1803                 }
1804             }
1805             else
1806             {
1807                 /* Use the current table */
1808                 ObjectTable = PsGetCurrentProcess()->ObjectTable;
1809             }
1810 
1811             /* Change the handle attributes */
1812             if (!ExChangeHandle(ObjectTable,
1813                                 ObjectHandle,
1814                                 ObpSetHandleAttributes,
1815                                 (ULONG_PTR)&Context))
1816             {
1817                 /* Some failure */
1818                 Status = STATUS_ACCESS_DENIED;
1819             }
1820             else
1821             {
1822                 /* We are done */
1823                 Status = STATUS_SUCCESS;
1824             }
1825 
1826             /* De-attach if we were attached, and return status */
1827             if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1828             break;
1829 
1830         case ObjectSessionInformation:
1831 
1832             /* Only a system process can do this */
1833             PreviousMode = ExGetPreviousMode();
1834             if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
1835             {
1836                 /* Fail */
1837                 DPRINT1("Privilege not held\n");
1838                 Status = STATUS_PRIVILEGE_NOT_HELD;
1839             }
1840             else
1841             {
1842                 /* Get the object directory */
1843                 Status = ObReferenceObjectByHandle(ObjectHandle,
1844                                                    0,
1845                                                    ObpDirectoryObjectType,
1846                                                    PreviousMode,
1847                                                    (PVOID*)&Directory,
1848                                                    NULL);
1849                 if (NT_SUCCESS(Status))
1850                 {
1851                     /* Setup a lookup context */
1852                     OBP_LOOKUP_CONTEXT LookupContext;
1853                     ObpInitializeLookupContext(&LookupContext);
1854 
1855                     /* Set the directory session ID */
1856                     ObpAcquireDirectoryLockExclusive(Directory, &LookupContext);
1857                     Directory->SessionId = PsGetCurrentProcessSessionId();
1858                     ObpReleaseDirectoryLock(Directory, &LookupContext);
1859 
1860                     /* We're done, release the context and dereference the directory */
1861                     ObpReleaseLookupContext(&LookupContext);
1862                     ObDereferenceObject(Directory);
1863                 }
1864             }
1865             break;
1866 
1867         default:
1868             /* Unsupported class */
1869             Status = STATUS_INVALID_INFO_CLASS;
1870             break;
1871     }
1872 
1873     return Status;
1874 }
1875 
1876 /* EOF */
1877