xref: /reactos/ntoskrnl/ob/oblife.c (revision c3483339)
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             DPRINT("FIXME: Should return quotas: %lx %lx\n", PagedPoolCharge, NonPagedPoolCharge);
114 #if 0
115             PsReturnSharedPoolQuota(ObjectHeader->QuotaBlockCharged,
116                                     PagedPoolCharge,
117                                     NonPagedPoolCharge);
118 #endif
119 
120         }
121     }
122 
123     /* Check if a handle database was active */
124     if ((HandleInfo) && !(Header->Flags & OB_FLAG_SINGLE_PROCESS))
125     {
126         /* Free it */
127         ExFreePool(HandleInfo->HandleCountDatabase);
128         HandleInfo->HandleCountDatabase = NULL;
129     }
130 
131     /* Check if we have a name */
132     if ((NameInfo) && (NameInfo->Name.Buffer))
133     {
134         /* Free it */
135         ExFreePool(NameInfo->Name.Buffer);
136         NameInfo->Name.Buffer = NULL;
137     }
138 
139     /* Catch invalid access */
140     Header->Type = (POBJECT_TYPE)(ULONG_PTR)0xBAADB0B0BAADB0B0ULL;
141 
142     /* Free the object using the same allocation tag */
143     ExFreePoolWithTag(HeaderLocation, ObjectType->Key);
144 }
145 
146 VOID
147 NTAPI
148 ObpDeleteObject(IN PVOID Object,
149                 IN BOOLEAN CalledFromWorkerThread)
150 {
151     POBJECT_HEADER Header;
152     POBJECT_TYPE ObjectType;
153     POBJECT_HEADER_NAME_INFO NameInfo;
154     POBJECT_HEADER_CREATOR_INFO CreatorInfo;
155     KIRQL CalloutIrql;
156     PAGED_CODE();
157 
158     /* Get the header and type */
159     Header = OBJECT_TO_OBJECT_HEADER(Object);
160     ObjectType = Header->Type;
161 
162     /* Get creator and name information */
163     NameInfo = OBJECT_HEADER_TO_NAME_INFO(Header);
164     CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(Header);
165 
166     /* Check if the object is on a type list */
167     if ((CreatorInfo) && !(IsListEmpty(&CreatorInfo->TypeList)))
168     {
169         /* Lock the object type */
170         ObpEnterObjectTypeMutex(ObjectType);
171 
172         /* Remove the object from the type list */
173         RemoveEntryList(&CreatorInfo->TypeList);
174 
175         /* Release the lock */
176         ObpLeaveObjectTypeMutex(ObjectType);
177     }
178 
179     /* Check if we have a name */
180     if ((NameInfo) && (NameInfo->Name.Buffer))
181     {
182         /* Free it */
183         ExFreePool(NameInfo->Name.Buffer);
184         RtlInitEmptyUnicodeString(&NameInfo->Name, NULL, 0);
185     }
186 
187     /* Check if we have a security descriptor */
188     if (Header->SecurityDescriptor)
189     {
190         /* Call the security procedure to delete it */
191         ObpCalloutStart(&CalloutIrql);
192         ObjectType->TypeInfo.SecurityProcedure(Object,
193                                                DeleteSecurityDescriptor,
194                                                0,
195                                                NULL,
196                                                NULL,
197                                                &Header->SecurityDescriptor,
198                                                0,
199                                                NULL);
200         ObpCalloutEnd(CalloutIrql, "Security", ObjectType, Object);
201     }
202 
203     /* Check if we have a delete procedure */
204     if (ObjectType->TypeInfo.DeleteProcedure)
205     {
206         /* Save whether we were deleted from worker thread or not */
207         if (!CalledFromWorkerThread) Header->Flags |= OB_FLAG_DEFER_DELETE;
208 
209         /* Call it */
210         ObpCalloutStart(&CalloutIrql);
211         ObjectType->TypeInfo.DeleteProcedure(Object);
212         ObpCalloutEnd(CalloutIrql, "Delete", ObjectType, Object);
213     }
214 
215     /* Now de-allocate all object members */
216     ObpDeallocateObject(Object);
217 }
218 
219 VOID
220 NTAPI
221 ObpReapObject(IN PVOID Parameter)
222 {
223     POBJECT_HEADER ReapObject, NextObject;
224 
225     /* Start reaping */
226     do
227     {
228         /* Get the reap object */
229         ReapObject = InterlockedExchangePointer(&ObpReaperList, (PVOID)1);
230 
231         /* Start deletion loop */
232         do
233         {
234             /* Get the next object */
235             NextObject = ReapObject->NextToFree;
236 
237             /* Delete the object */
238             ObpDeleteObject(&ReapObject->Body, TRUE);
239 
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));
245 }
246 
247 /*++
248 * @name ObpSetPermanentObject
249 *
250 *     The ObpSetPermanentObject routine makes an sets or clears the permanent
251 *     flag of an object, thus making it either permanent or temporary.
252 *
253 * @param ObjectBody
254 *        Pointer to the object to make permanent or temporary.
255 *
256 * @param Permanent
257 *        Flag specifying which operation to perform.
258 *
259 * @return None.
260 *
261 * @remarks If the object is being made temporary, then it will be checked
262 *          as a candidate for immediate removal from the namespace.
263 *
264 *--*/
265 VOID
266 FASTCALL
267 ObpSetPermanentObject(IN PVOID ObjectBody,
268                       IN BOOLEAN Permanent)
269 {
270     POBJECT_HEADER ObjectHeader;
271 
272     /* Get the header */
273     ObjectHeader = OBJECT_TO_OBJECT_HEADER(ObjectBody);
274 
275     /* Acquire object lock */
276     ObpAcquireObjectLock(ObjectHeader);
277 
278     /* Check what we're doing to it */
279     if (Permanent)
280     {
281         /* Set it to permanent */
282         ObjectHeader->Flags |= OB_FLAG_PERMANENT;
283 
284         /* Release the lock */
285         ObpReleaseObjectLock(ObjectHeader);
286     }
287     else
288     {
289         /* Remove the flag */
290         ObjectHeader->Flags &= ~OB_FLAG_PERMANENT;
291 
292         /* Release the lock */
293         ObpReleaseObjectLock(ObjectHeader);
294 
295         /* Check if we should delete the object now */
296         ObpDeleteNameCheck(ObjectBody);
297     }
298 }
299 
300 PWCHAR
301 NTAPI
302 ObpAllocateObjectNameBuffer(IN ULONG Length,
303                             IN BOOLEAN UseLookaside,
304                             IN OUT PUNICODE_STRING ObjectName)
305 {
306     ULONG MaximumLength;
307     PVOID Buffer;
308 
309     /* Set the maximum length to the length plus the terminator */
310     MaximumLength = Length + sizeof(UNICODE_NULL);
311 
312     /* Check if we should use the lookaside buffer */
313     if (!(UseLookaside) || (MaximumLength > OBP_NAME_LOOKASIDE_MAX_SIZE))
314     {
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)
318          * here.
319          *
320          * People do call this with UseLookasideList FALSE so the distinction
321          * is critical.
322          */
323         if (MaximumLength <= OBP_NAME_LOOKASIDE_MAX_SIZE)
324         {
325             MaximumLength = OBP_NAME_LOOKASIDE_MAX_SIZE + sizeof(UNICODE_NULL);
326         }
327         Buffer = ExAllocatePoolWithTag(PagedPool,
328                                        MaximumLength,
329                                        OB_NAME_TAG);
330     }
331     else
332     {
333         /* Allocate from the lookaside */
334         MaximumLength = OBP_NAME_LOOKASIDE_MAX_SIZE;
335         Buffer = ObpAllocateObjectCreateInfoBuffer(LookasideNameBufferList);
336     }
337 
338     /* Setup the string */
339     ObjectName->MaximumLength = (USHORT)MaximumLength;
340     ObjectName->Length = (USHORT)Length;
341     ObjectName->Buffer = Buffer;
342     return Buffer;
343 }
344 
345 VOID
346 NTAPI
347 ObpFreeObjectNameBuffer(IN PUNICODE_STRING Name)
348 {
349     PVOID Buffer = Name->Buffer;
350 
351     /* We know this is a pool-allocation if the size doesn't match */
352     if (Name->MaximumLength != OBP_NAME_LOOKASIDE_MAX_SIZE)
353     {
354         /*
355          * Free it from the pool.
356          *
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!
365          */
366         ExFreePool(Buffer);
367     }
368     else
369     {
370         /* Otherwise, free from the lookaside */
371         ObpFreeCapturedAttributes(Buffer, LookasideNameBufferList);
372     }
373 }
374 
375 NTSTATUS
376 NTAPI
377 ObpCaptureObjectName(IN OUT PUNICODE_STRING CapturedName,
378                      IN PUNICODE_STRING ObjectName,
379                      IN KPROCESSOR_MODE AccessMode,
380                      IN BOOLEAN UseLookaside)
381 {
382     NTSTATUS Status = STATUS_SUCCESS;
383     ULONG StringLength;
384     PWCHAR _SEH2_VOLATILE StringBuffer = NULL;
385     UNICODE_STRING LocalName;
386     PAGED_CODE();
387 
388     /* Initialize the Input String */
389     RtlInitEmptyUnicodeString(CapturedName, NULL, 0);
390 
391     /* Protect everything */
392     _SEH2_TRY
393     {
394         /* Check if we came from user mode */
395         if (AccessMode != KernelMode)
396         {
397             /* First Probe the String */
398             LocalName = ProbeForReadUnicodeString(ObjectName);
399             ProbeForRead(LocalName.Buffer, LocalName.Length, sizeof(WCHAR));
400         }
401         else
402         {
403             /* No probing needed */
404             LocalName = *ObjectName;
405         }
406 
407         /* Make sure there really is a string */
408         StringLength = LocalName.Length;
409         if (StringLength)
410         {
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)))
415             {
416                 /* PS: Please keep the checks above expanded for clarity */
417                 Status = STATUS_OBJECT_NAME_INVALID;
418             }
419             else
420             {
421                 /* Allocate the string buffer */
422                 StringBuffer = ObpAllocateObjectNameBuffer(StringLength,
423                                                            UseLookaside,
424                                                            CapturedName);
425                 if (!StringBuffer)
426                 {
427                     /* Set failure code */
428                     Status = STATUS_INSUFFICIENT_RESOURCES;
429                 }
430                 else
431                 {
432                     /* Copy the name */
433                     RtlCopyMemory(StringBuffer, LocalName.Buffer, StringLength);
434                     StringBuffer[StringLength / sizeof(WCHAR)] = UNICODE_NULL;
435                 }
436             }
437         }
438     }
439     _SEH2_EXCEPT(ExSystemExceptionFilter())
440     {
441         /* Handle exception and free the string buffer */
442         Status = _SEH2_GetExceptionCode();
443         if (StringBuffer)
444         {
445             ObpFreeObjectNameBuffer(CapturedName);
446         }
447     }
448     _SEH2_END;
449 
450     /* Return */
451     return Status;
452 }
453 
454 NTSTATUS
455 NTAPI
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)
462 {
463     ULONG SdCharge, QuotaInfoSize;
464     NTSTATUS Status = STATUS_SUCCESS;
465     PSECURITY_DESCRIPTOR SecurityDescriptor;
466     PSECURITY_QUALITY_OF_SERVICE SecurityQos;
467     PUNICODE_STRING LocalObjectName = NULL;
468     PAGED_CODE();
469 
470     /* Zero out the Capture Data */
471     RtlZeroMemory(ObjectCreateInfo, sizeof(OBJECT_CREATE_INFORMATION));
472 
473     /* SEH everything here for protection */
474     _SEH2_TRY
475     {
476         /* Check if we got attributes */
477         if (ObjectAttributes)
478         {
479             /* Check if we're in user mode */
480             if (AccessMode != KernelMode)
481             {
482                 /* Probe the attributes */
483                 ProbeForRead(ObjectAttributes,
484                              sizeof(OBJECT_ATTRIBUTES),
485                              sizeof(ULONG));
486             }
487 
488             /* Validate the Size and Attributes */
489             if ((ObjectAttributes->Length != sizeof(OBJECT_ATTRIBUTES)) ||
490                 (ObjectAttributes->Attributes & ~OBJ_VALID_KERNEL_ATTRIBUTES))
491             {
492                 /* Invalid combination, fail */
493                 _SEH2_YIELD(return STATUS_INVALID_PARAMETER);
494             }
495 
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;
503 
504             /* Check if we have a security descriptor */
505             if (SecurityDescriptor)
506             {
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,
510                                                      AccessMode,
511                                                      NonPagedPool,
512                                                      TRUE,
513                                                      &ObjectCreateInfo->
514                                                      SecurityDescriptor);
515                 if (!NT_SUCCESS(Status))
516                 {
517                     /* Capture failed, quit */
518                     ObjectCreateInfo->SecurityDescriptor = NULL;
519                     _SEH2_YIELD(return Status);
520                 }
521 
522                 /*
523                  * By default, assume a SD size of 1024 and allow twice its
524                  * size.
525                  * If SD size happen to be bigger than that, then allow it
526                  */
527                 SdCharge = 2048;
528                 SeComputeQuotaInformationSize(ObjectCreateInfo->SecurityDescriptor,
529                                               &QuotaInfoSize);
530                 if ((2 * QuotaInfoSize) > 2048)
531                 {
532                     SdCharge = 2 * QuotaInfoSize;
533                 }
534 
535                 /* Save the probe mode and security descriptor size */
536                 ObjectCreateInfo->SecurityDescriptorCharge = SdCharge;
537                 ObjectCreateInfo->ProbeMode = AccessMode;
538             }
539 
540             /* Check if we have QoS */
541             if (SecurityQos)
542             {
543                 /* Check if we came from user mode */
544                 if (AccessMode != KernelMode)
545                 {
546                     /* Validate the QoS */
547                     ProbeForRead(SecurityQos,
548                                  sizeof(SECURITY_QUALITY_OF_SERVICE),
549                                  sizeof(ULONG));
550                 }
551 
552                 /* Save Info */
553                 ObjectCreateInfo->SecurityQualityOfService = *SecurityQos;
554                 ObjectCreateInfo->SecurityQos =
555                     &ObjectCreateInfo->SecurityQualityOfService;
556             }
557         }
558         else
559         {
560             /* We don't have a name */
561             LocalObjectName = NULL;
562         }
563     }
564     _SEH2_EXCEPT(ExSystemExceptionFilter())
565     {
566         /* Cleanup and return the exception code */
567         ObpReleaseObjectCreateInformation(ObjectCreateInfo);
568         _SEH2_YIELD(return _SEH2_GetExceptionCode());
569     }
570     _SEH2_END;
571 
572     /* Now check if the Object Attributes had an Object Name */
573     if (LocalObjectName)
574     {
575         Status = ObpCaptureObjectName(ObjectName,
576                                       LocalObjectName,
577                                       AccessMode,
578                                       AllocateFromLookaside);
579     }
580     else
581     {
582         /* Clear the string */
583         RtlInitEmptyUnicodeString(ObjectName, NULL, 0);
584 
585         /* It cannot have specified a Root Directory */
586         if (ObjectCreateInfo->RootDirectory)
587         {
588             Status = STATUS_OBJECT_NAME_INVALID;
589         }
590     }
591 
592     /* Cleanup if we failed */
593     if (!NT_SUCCESS(Status))
594     {
595         ObpReleaseObjectCreateInformation(ObjectCreateInfo);
596     }
597 
598     /* Return status to caller */
599     return Status;
600 }
601 
602 VOID
603 NTAPI
604 ObFreeObjectCreateInfoBuffer(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo)
605 {
606     /* Call the macro. We use this function to isolate Ob internals from Io */
607     ObpFreeCapturedAttributes(ObjectCreateInfo, LookasideCreateInfoList);
608 }
609 
610 NTSTATUS
611 NTAPI
612 ObpAllocateObject(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo,
613                   IN PUNICODE_STRING ObjectName,
614                   IN POBJECT_TYPE ObjectType,
615                   IN ULONG ObjectSize,
616                   IN KPROCESSOR_MODE PreviousMode,
617                   IN POBJECT_HEADER *ObjectHeader)
618 {
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;
625     POOL_TYPE PoolType;
626     ULONG FinalSize;
627     ULONG Tag;
628     PAGED_CODE();
629 
630     /* Accounting */
631     ObpObjectsCreated++;
632 
633     /* Check if we don't have an Object Type yet */
634     if (!ObjectType)
635     {
636         /* Use default tag and non-paged pool */
637         PoolType = NonPagedPool;
638         Tag = 'TjbO';
639     }
640     else
641     {
642         /* Use the pool and tag given */
643         PoolType = ObjectType->TypeInfo.PoolType;
644         Tag = ObjectType->Key;
645     }
646 
647     /* Check if we have no create information (ie: we're an object type) */
648     if (!ObjectCreateInfo)
649     {
650         /* Use defaults */
651         QuotaSize = HandleSize = 0;
652         NameSize = sizeof(OBJECT_HEADER_NAME_INFO);
653         CreatorSize = sizeof(OBJECT_HEADER_CREATOR_INFO);
654     }
655     else
656     {
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))
665         {
666             /* Set quota size */
667             QuotaSize = sizeof(OBJECT_HEADER_QUOTA_INFO);
668             ObpObjectsWithPoolQuota++;
669         }
670         else
671         {
672             /* No Quota */
673             QuotaSize = 0;
674         }
675 
676         /* Check if we have a handle database */
677         if (ObjectType->TypeInfo.MaintainHandleCount)
678         {
679             /* Set handle database size */
680             HandleSize = sizeof(OBJECT_HEADER_HANDLE_INFO);
681             ObpObjectsWithHandleDB++;
682         }
683         else
684         {
685             /* None */
686             HandleSize = 0;
687         }
688 
689         /* Check if the Object has a name */
690         if (ObjectName->Buffer)
691         {
692             /* Set name size */
693             NameSize = sizeof(OBJECT_HEADER_NAME_INFO);
694             ObpObjectsWithName++;
695         }
696         else
697         {
698             /* No name */
699             NameSize = 0;
700         }
701 
702         /* Check if the Object maintains type lists */
703         if (ObjectType->TypeInfo.MaintainTypeList)
704         {
705             /* Set owner/creator size */
706             CreatorSize = sizeof(OBJECT_HEADER_CREATOR_INFO);
707             ObpObjectsWithCreatorInfo++;
708         }
709         else
710         {
711             /* No info */
712             CreatorSize = 0;
713         }
714     }
715 
716     /* Set final header size */
717     FinalSize = QuotaSize +
718                 HandleSize +
719                 NameSize +
720                 CreatorSize +
721                 FIELD_OFFSET(OBJECT_HEADER, Body);
722 
723     /* Allocate memory for the Object and Header */
724     Header = ExAllocatePoolWithTag(PoolType, FinalSize + ObjectSize, Tag);
725     if (!Header) return STATUS_INSUFFICIENT_RESOURCES;
726 
727     /* Check if we have a quota header */
728     if (QuotaSize)
729     {
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);
737     }
738 
739     /* Check if we have a handle database header */
740     if (HandleSize)
741     {
742         /* Initialize Handle Info */
743         HandleInfo = (POBJECT_HEADER_HANDLE_INFO)Header;
744         HandleInfo->SingleEntry.HandleCount = 0;
745         Header = (POBJECT_HEADER)(HandleInfo + 1);
746     }
747 
748     /* Check if we have a name header */
749     if (NameSize)
750     {
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;
756 
757         /* Check if this is a call with the special protection flag */
758         if ((PreviousMode == KernelMode) &&
759             (ObjectCreateInfo) &&
760             (ObjectCreateInfo->Attributes & OBJ_KERNEL_EXCLUSIVE))
761         {
762             /* Set flag which will make the object protected from user-mode */
763             NameInfo->QueryReferences |= OB_FLAG_KERNEL_EXCLUSIVE;
764         }
765 
766         /* Set the header pointer */
767         Header = (POBJECT_HEADER)(NameInfo + 1);
768     }
769 
770     /* Check if we have a creator header */
771     if (CreatorSize)
772     {
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);
779     }
780 
781     /* Check for quota information */
782     if (QuotaSize)
783     {
784         /* Set the offset */
785         Header->QuotaInfoOffset = (UCHAR)(QuotaSize +
786                                           HandleSize +
787                                           NameSize +
788                                           CreatorSize);
789     }
790     else
791     {
792         /* No offset */
793         Header->QuotaInfoOffset = 0;
794     }
795 
796     /* Check for handle information */
797     if (HandleSize)
798     {
799         /* Set the offset */
800         Header->HandleInfoOffset = (UCHAR)(HandleSize +
801                                            NameSize +
802                                            CreatorSize);
803     }
804     else
805     {
806         /* No offset */
807         Header->HandleInfoOffset = 0;
808     }
809 
810     /* Check for name information */
811     if (NameSize)
812     {
813         /* Set the offset */
814         Header->NameInfoOffset = (UCHAR)(NameSize + CreatorSize);
815     }
816     else
817     {
818         /* No Name */
819         Header->NameInfoOffset = 0;
820     }
821 
822     /* Set the new object flag */
823     Header->Flags = OB_FLAG_CREATE_INFO;
824 
825     /* Remember if we have creator info */
826     if (CreatorSize) Header->Flags |= OB_FLAG_CREATOR_INFO;
827 
828     /* Remember if we have handle info */
829     if (HandleSize) Header->Flags |= OB_FLAG_SINGLE_PROCESS;
830 
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;
837 
838     /* Check if this is a permanent object */
839     if ((ObjectCreateInfo) && (ObjectCreateInfo->Attributes & OBJ_PERMANENT))
840     {
841         /* Set the needed flag so we can check */
842         Header->Flags |= OB_FLAG_PERMANENT;
843     }
844 
845     /* Check if this is an exclusive object */
846     if ((ObjectCreateInfo) && (ObjectCreateInfo->Attributes & OBJ_EXCLUSIVE))
847     {
848         /* Set the needed flag so we can check */
849         Header->Flags |= OB_FLAG_EXCLUSIVE;
850     }
851 
852     /* Set kernel-mode flag */
853     if (PreviousMode == KernelMode) Header->Flags |= OB_FLAG_KERNEL_MODE;
854 
855     /* Check if we have a type */
856     if (ObjectType)
857     {
858         /* Increase the number of objects of this type */
859         InterlockedIncrement((PLONG)&ObjectType->TotalNumberOfObjects);
860 
861         /* Update the high water */
862         ObjectType->HighWaterNumberOfObjects = max(ObjectType->
863                                                    TotalNumberOfObjects,
864                                                    ObjectType->
865                                                    HighWaterNumberOfObjects);
866     }
867 
868     /* Return Header */
869     *ObjectHeader = Header;
870     return STATUS_SUCCESS;
871 }
872 
873 NTSTATUS
874 NTAPI
875 ObQueryTypeInfo(IN POBJECT_TYPE ObjectType,
876                 OUT POBJECT_TYPE_INFORMATION ObjectTypeInfo,
877                 IN ULONG Length,
878                 OUT PULONG ReturnLength)
879 {
880     NTSTATUS Status = STATUS_SUCCESS;
881     PWSTR InfoBuffer;
882 
883     /* Enter SEH */
884     _SEH2_TRY
885     {
886         /* Set return length aligned to 4-byte boundary */
887         *ReturnLength += sizeof(*ObjectTypeInfo) +
888                          ALIGN_UP(ObjectType->Name.MaximumLength, ULONG);
889 
890         /* Check if thats too much though. */
891         if (Length < *ReturnLength)
892         {
893             _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH);
894         }
895 
896         /* Build the data */
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;
921 
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;
927 
928         /* Copy it */
929         RtlCopyMemory(InfoBuffer,
930                       ObjectType->Name.Buffer,
931                       ObjectType->Name.Length);
932 
933         /* Null-terminate it */
934         (InfoBuffer)[ObjectType->Name.Length / sizeof(WCHAR)] = UNICODE_NULL;
935     }
936     _SEH2_EXCEPT(ExSystemExceptionFilter())
937     {
938         /* Otherwise, get the exception code */
939         Status = _SEH2_GetExceptionCode();
940     }
941     _SEH2_END;
942 
943     /* Return status to caller */
944     return Status;
945 }
946 
947 
948 /* PUBLIC FUNCTIONS **********************************************************/
949 
950 NTSTATUS
951 NTAPI
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,
957                IN ULONG ObjectSize,
958                IN ULONG PagedPoolCharge OPTIONAL,
959                IN ULONG NonPagedPoolCharge OPTIONAL,
960                OUT PVOID *Object)
961 {
962     NTSTATUS Status;
963     POBJECT_CREATE_INFORMATION ObjectCreateInfo;
964     UNICODE_STRING ObjectName;
965     POBJECT_HEADER Header;
966 
967     /* Allocate a capture buffer */
968     ObjectCreateInfo = ObpAllocateObjectCreateInfoBuffer(LookasideCreateInfoList);
969     if (!ObjectCreateInfo) return STATUS_INSUFFICIENT_RESOURCES;
970 
971     /* Capture all the info */
972     Status = ObpCaptureObjectCreateInformation(ObjectAttributes,
973                                                ProbeMode,
974                                                AccessMode,
975                                                FALSE,
976                                                ObjectCreateInfo,
977                                                &ObjectName);
978     if (NT_SUCCESS(Status))
979     {
980         /* Validate attributes */
981         if (Type->TypeInfo.InvalidAttributes & ObjectCreateInfo->Attributes)
982         {
983             /* Fail */
984             Status = STATUS_INVALID_PARAMETER;
985         }
986         else
987         {
988             /* Check if we have a paged charge */
989             if (!PagedPoolCharge)
990             {
991                 /* Save it */
992                 PagedPoolCharge = Type->TypeInfo.DefaultPagedPoolCharge;
993             }
994 
995             /* Check for nonpaged charge */
996             if (!NonPagedPoolCharge)
997             {
998                 /* Save it */
999                 NonPagedPoolCharge = Type->TypeInfo.DefaultNonPagedPoolCharge;
1000             }
1001 
1002             /* Write the pool charges */
1003             ObjectCreateInfo->PagedPoolCharge = PagedPoolCharge;
1004             ObjectCreateInfo->NonPagedPoolCharge = NonPagedPoolCharge;
1005 
1006             /* Allocate the Object */
1007             Status = ObpAllocateObject(ObjectCreateInfo,
1008                                        &ObjectName,
1009                                        Type,
1010                                        ObjectSize,
1011                                        AccessMode,
1012                                        &Header);
1013             if (NT_SUCCESS(Status))
1014             {
1015                 /* Return the Object */
1016                 *Object = &Header->Body;
1017 
1018                 /* Check if this is a permanent object */
1019                 if (Header->Flags & OB_FLAG_PERMANENT)
1020                 {
1021                     /* Do the privilege check */
1022                     if (!SeSinglePrivilegeCheck(SeCreatePermanentPrivilege,
1023                                                 ProbeMode))
1024                     {
1025                         /* Fail */
1026                         ObpDeallocateObject(*Object);
1027                         Status = STATUS_PRIVILEGE_NOT_HELD;
1028                     }
1029                 }
1030 
1031                 /* Return status */
1032                 return Status;
1033             }
1034         }
1035 
1036         /* Release the Capture Info, we don't need it */
1037         ObpFreeObjectCreateInformation(ObjectCreateInfo);
1038         if (ObjectName.Buffer) ObpFreeObjectNameBuffer(&ObjectName);
1039     }
1040 
1041     /* We failed, so release the Buffer */
1042     ObpFreeCapturedAttributes(ObjectCreateInfo, LookasideCreateInfoList);
1043     return Status;
1044 }
1045 
1046 NTSTATUS
1047 NTAPI
1048 ObCreateObjectType(IN PUNICODE_STRING TypeName,
1049                    IN POBJECT_TYPE_INITIALIZER ObjectTypeInitializer,
1050                    IN PVOID Reserved,
1051                    OUT POBJECT_TYPE *ObjectType)
1052 {
1053     POBJECT_HEADER Header;
1054     POBJECT_TYPE LocalObjectType;
1055     ULONG HeaderSize;
1056     NTSTATUS Status;
1057     OBP_LOOKUP_CONTEXT Context;
1058     PWCHAR p;
1059     ULONG i;
1060     UNICODE_STRING ObjectName;
1061     ANSI_STRING AnsiName;
1062     POBJECT_HEADER_CREATOR_INFO CreatorInfo;
1063 
1064     /* Verify parameters */
1065     if (!(TypeName) ||
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)))
1076     {
1077         /* Fail */
1078         return STATUS_INVALID_PARAMETER;
1079     }
1080 
1081     /* Make sure the name doesn't have a separator */
1082     p = TypeName->Buffer;
1083     i = TypeName->Length / sizeof(WCHAR);
1084     while (i--)
1085     {
1086         /* Check for one and fail */
1087         if (*p++ == OBJ_NAME_PATH_SEPARATOR) return STATUS_OBJECT_NAME_INVALID;
1088     }
1089 
1090     /* Setup a lookup context */
1091     ObpInitializeLookupContext(&Context);
1092 
1093     /* Check if we've already created the directory of types */
1094     if (ObpTypeDirectoryObject)
1095     {
1096         /* Acquire the directory lock */
1097         ObpAcquireDirectoryLockExclusive(ObpTypeDirectoryObject, &Context);
1098 
1099         /* Do the lookup */
1100         if (ObpLookupEntryDirectory(ObpTypeDirectoryObject,
1101                                     TypeName,
1102                                     OBJ_CASE_INSENSITIVE,
1103                                     FALSE,
1104                                     &Context))
1105         {
1106             /* We have already created it, so fail */
1107             ObpReleaseLookupContext(&Context);
1108             return STATUS_OBJECT_NAME_COLLISION;
1109         }
1110     }
1111 
1112     /* Now make a copy of the object name */
1113     ObjectName.Buffer = ExAllocatePoolWithTag(PagedPool,
1114                                               TypeName->MaximumLength,
1115                                               OB_NAME_TAG);
1116     if (!ObjectName.Buffer)
1117     {
1118         /* Out of memory, fail */
1119         ObpReleaseLookupContext(&Context);
1120         return STATUS_INSUFFICIENT_RESOURCES;
1121     }
1122 
1123     /* Set the length and copy the name */
1124     ObjectName.MaximumLength = TypeName->MaximumLength;
1125     RtlCopyUnicodeString(&ObjectName, TypeName);
1126 
1127     /* Allocate the Object */
1128     Status = ObpAllocateObject(NULL,
1129                                &ObjectName,
1130                                ObpTypeObjectType,
1131                                sizeof(OBJECT_TYPE),
1132                                KernelMode,
1133                                &Header);
1134     if (!NT_SUCCESS(Status))
1135     {
1136         /* Free the name and fail */
1137         ObpReleaseLookupContext(&Context);
1138         ExFreePool(ObjectName.Buffer);
1139         return Status;
1140     }
1141 
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;
1146 
1147     /* Clear accounting data */
1148     LocalObjectType->TotalNumberOfObjects =
1149     LocalObjectType->TotalNumberOfHandles =
1150     LocalObjectType->HighWaterNumberOfObjects =
1151     LocalObjectType->HighWaterNumberOfHandles = 0;
1152 
1153     /* Check if this is the first Object Type */
1154     if (!ObpTypeObjectType)
1155     {
1156         /* It is, so set this as the type object */
1157         ObpTypeObjectType = LocalObjectType;
1158         Header->Type = ObpTypeObjectType;
1159 
1160         /* Set the hard-coded key and object count */
1161         LocalObjectType->TotalNumberOfObjects = 1;
1162         LocalObjectType->Key = 'TjbO';
1163     }
1164     else
1165     {
1166         /* Convert the tag to ASCII */
1167         Status = RtlUnicodeStringToAnsiString(&AnsiName, TypeName, TRUE);
1168         if (NT_SUCCESS(Status))
1169         {
1170             /* For every missing character, use a space */
1171             for (i = 3; i >= AnsiName.Length; i--) AnsiName.Buffer[i] = ' ';
1172 
1173             /* Set the key and free the converted name */
1174             LocalObjectType->Key = *(PULONG)AnsiName.Buffer;
1175             RtlFreeAnsiString(&AnsiName);
1176         }
1177         else
1178         {
1179             /* Just copy the characters */
1180             LocalObjectType->Key = *(PULONG)TypeName->Buffer;
1181         }
1182     }
1183 
1184     /* Set up the type information */
1185     LocalObjectType->TypeInfo = *ObjectTypeInitializer;
1186     LocalObjectType->TypeInfo.PoolType = ObjectTypeInitializer->PoolType;
1187 
1188     /* Check if we have to maintain a type list */
1189     if (NtGlobalFlag & FLG_MAINTAIN_OBJECT_TYPELIST)
1190     {
1191         /* Enable support */
1192         LocalObjectType->TypeInfo.MaintainTypeList = TRUE;
1193     }
1194 
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);
1200 
1201     /* Check the pool type */
1202     if (ObjectTypeInitializer->PoolType == NonPagedPool)
1203     {
1204         /* Update the NonPaged Pool charge */
1205         LocalObjectType->TypeInfo.DefaultNonPagedPoolCharge += HeaderSize;
1206     }
1207     else
1208     {
1209         /* Update the Paged Pool charge */
1210         LocalObjectType->TypeInfo.DefaultPagedPoolCharge += HeaderSize;
1211     }
1212 
1213     /* All objects types need a security procedure */
1214     if (!ObjectTypeInitializer->SecurityProcedure)
1215     {
1216         LocalObjectType->TypeInfo.SecurityProcedure = SeDefaultObjectMethod;
1217     }
1218 
1219     /* Select the Wait Object */
1220     if (LocalObjectType->TypeInfo.UseDefaultObject)
1221     {
1222         /* Add the SYNCHRONIZE access mask since it's waitable */
1223         LocalObjectType->TypeInfo.ValidAccessMask |= SYNCHRONIZE;
1224 
1225         /* Use the "Default Object", a simple event */
1226         LocalObjectType->DefaultObject = &ObpDefaultObject;
1227     }
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")))
1230     {
1231         /* Wait on the File Object's event directly */
1232         LocalObjectType->DefaultObject = UlongToPtr(FIELD_OFFSET(FILE_OBJECT,
1233                                                                  Event));
1234     }
1235     else if ((TypeName->Length == 24) && !(wcscmp(TypeName->Buffer, L"WaitablePort")))
1236     {
1237         /* Wait on the LPC Port's object directly */
1238         LocalObjectType->DefaultObject = UlongToPtr(FIELD_OFFSET(LPCP_PORT_OBJECT,
1239                                                                  WaitEvent));
1240     }
1241     else
1242     {
1243         /* No default Object */
1244         LocalObjectType->DefaultObject = NULL;
1245     }
1246 
1247     /* Initialize Object Type components */
1248     ExInitializeResourceLite(&LocalObjectType->Mutex);
1249     for (i = 0; i < 4; i++)
1250     {
1251         /* Initialize the object locks */
1252         ExInitializeResourceLite(&LocalObjectType->ObjectLocks[i]);
1253     }
1254     InitializeListHead(&LocalObjectType->TypeList);
1255 
1256     /* Lock the object type */
1257     ObpEnterObjectTypeMutex(ObpTypeObjectType);
1258 
1259     /* Get creator info and insert it into the type list */
1260     CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(Header);
1261     if (CreatorInfo)
1262     {
1263         InsertTailList(&ObpTypeObjectType->TypeList,
1264                        &CreatorInfo->TypeList);
1265 
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;
1269     }
1270 
1271     /* Set the index and the entry into the object type array */
1272     LocalObjectType->Index = ObpTypeObjectType->TotalNumberOfObjects;
1273 
1274     ASSERT(LocalObjectType->Index != 0);
1275 
1276     if (LocalObjectType->Index < RTL_NUMBER_OF(ObpObjectTypes))
1277     {
1278         /* It fits, insert it */
1279         ObpObjectTypes[LocalObjectType->Index - 1] = LocalObjectType;
1280     }
1281 
1282     /* Release the object type */
1283     ObpLeaveObjectTypeMutex(ObpTypeObjectType);
1284 
1285     /* Check if we're actually creating the directory object itself */
1286     if (!(ObpTypeDirectoryObject) ||
1287         (ObpInsertEntryDirectory(ObpTypeDirectoryObject, &Context, Header)))
1288     {
1289         /* Check if the type directory exists */
1290         if (ObpTypeDirectoryObject)
1291         {
1292             /* Reference it */
1293             ObReferenceObject(ObpTypeDirectoryObject);
1294         }
1295 
1296         /* Cleanup the lookup context */
1297         ObpReleaseLookupContext(&Context);
1298 
1299         /* Return the object type and success */
1300         *ObjectType = LocalObjectType;
1301         return STATUS_SUCCESS;
1302     }
1303 
1304     /* If we got here, then we failed */
1305     ObpReleaseLookupContext(&Context);
1306     return STATUS_INSUFFICIENT_RESOURCES;
1307 }
1308 
1309 VOID
1310 NTAPI
1311 ObDeleteCapturedInsertInfo(IN PVOID Object)
1312 {
1313     POBJECT_HEADER ObjectHeader;
1314     PAGED_CODE();
1315 
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))
1320     {
1321         /* Free the create info */
1322         ObpFreeObjectCreateInformation(ObjectHeader->ObjectCreateInfo);
1323         ObjectHeader->ObjectCreateInfo = NULL;
1324     }
1325 }
1326 
1327 VOID
1328 NTAPI
1329 ObpDeleteObjectType(IN PVOID Object)
1330 {
1331     ULONG i;
1332     POBJECT_TYPE ObjectType = (PVOID)Object;
1333 
1334     /* Loop our locks */
1335     for (i = 0; i < 4; i++)
1336     {
1337         /* Delete each one */
1338         ExDeleteResourceLite(&ObjectType->ObjectLocks[i]);
1339     }
1340 
1341     /* Delete our main mutex */
1342     ExDeleteResourceLite(&ObjectType->Mutex);
1343 }
1344 
1345 /*++
1346 * @name ObMakeTemporaryObject
1347 * @implemented NT4
1348 *
1349 *     The ObMakeTemporaryObject routine <FILLMEIN>
1350 *
1351 * @param ObjectBody
1352 *        <FILLMEIN>
1353 *
1354 * @return None.
1355 *
1356 * @remarks None.
1357 *
1358 *--*/
1359 VOID
1360 NTAPI
1361 ObMakeTemporaryObject(IN PVOID ObjectBody)
1362 {
1363     PAGED_CODE();
1364 
1365     /* Call the internal API */
1366     ObpSetPermanentObject(ObjectBody, FALSE);
1367 }
1368 
1369 /*++
1370 * @name NtMakeTemporaryObject
1371 * @implemented NT4
1372 *
1373 *     The NtMakeTemporaryObject routine <FILLMEIN>
1374 *
1375 * @param ObjectHandle
1376 *        <FILLMEIN>
1377 *
1378 * @return STATUS_SUCCESS or appropriate error value.
1379 *
1380 * @remarks None.
1381 *
1382 *--*/
1383 NTSTATUS
1384 NTAPI
1385 NtMakeTemporaryObject(IN HANDLE ObjectHandle)
1386 {
1387     PVOID ObjectBody;
1388     NTSTATUS Status;
1389     PAGED_CODE();
1390 
1391     /* Reference the object for DELETE access */
1392     Status = ObReferenceObjectByHandle(ObjectHandle,
1393                                        DELETE,
1394                                        NULL,
1395                                        KeGetPreviousMode(),
1396                                        &ObjectBody,
1397                                        NULL);
1398     if (Status != STATUS_SUCCESS) return Status;
1399 
1400     /* Set it as temporary and dereference it */
1401     ObpSetPermanentObject(ObjectBody, FALSE);
1402     ObDereferenceObject(ObjectBody);
1403     return STATUS_SUCCESS;
1404 }
1405 
1406 /*++
1407 * @name NtMakePermanentObject
1408 * @implemented NT4
1409 *
1410 *     The NtMakePermanentObject routine <FILLMEIN>
1411 *
1412 * @param ObjectHandle
1413 *        <FILLMEIN>
1414 *
1415 * @return STATUS_SUCCESS or appropriate error value.
1416 *
1417 * @remarks None.
1418 *
1419 *--*/
1420 NTSTATUS
1421 NTAPI
1422 NtMakePermanentObject(IN HANDLE ObjectHandle)
1423 {
1424     PVOID ObjectBody;
1425     NTSTATUS Status;
1426     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1427     PAGED_CODE();
1428 
1429     /* Make sure that the caller has SeCreatePermanentPrivilege */
1430     Status = SeSinglePrivilegeCheck(SeCreatePermanentPrivilege,
1431                                     PreviousMode);
1432     if (!NT_SUCCESS(Status)) return STATUS_PRIVILEGE_NOT_HELD;
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                     /* FIXME: Missng locks */
1852                     /* Set its session ID */
1853                     Directory->SessionId = PsGetCurrentProcessSessionId();
1854                     ObDereferenceObject(Directory);
1855                 }
1856             }
1857             break;
1858 
1859         default:
1860             /* Unsupported class */
1861             Status = STATUS_INVALID_INFO_CLASS;
1862             break;
1863     }
1864 
1865     return Status;
1866 }
1867 
1868 /* EOF */
1869