xref: /reactos/ntoskrnl/ob/oblife.c (revision 2196a06f)
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 = TAG_OBJECT_TYPE;
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         /* Lock the lookup context */
1097         ObpAcquireLookupContextLock(&Context, ObpTypeDirectoryObject);
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 = TAG_OBJECT_TYPE;
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     if (!SeSinglePrivilegeCheck(SeCreatePermanentPrivilege, PreviousMode))
1431     {
1432         return STATUS_PRIVILEGE_NOT_HELD;
1433     }
1434 
1435     /* Reference the object */
1436     Status = ObReferenceObjectByHandle(ObjectHandle,
1437                                        0,
1438                                        NULL,
1439                                        PreviousMode,
1440                                        &ObjectBody,
1441                                        NULL);
1442     if (Status != STATUS_SUCCESS) return Status;
1443 
1444     /* Set it as permanent and dereference it */
1445     ObpSetPermanentObject(ObjectBody, TRUE);
1446     ObDereferenceObject(ObjectBody);
1447     return STATUS_SUCCESS;
1448 }
1449 
1450 /*++
1451 * @name NtQueryObject
1452 * @implemented NT4
1453 *
1454 *     The NtQueryObject routine <FILLMEIN>
1455 *
1456 * @param ObjectHandle
1457 *        <FILLMEIN>
1458 *
1459 * @param ObjectInformationClass
1460 *        <FILLMEIN>
1461 *
1462 * @param ObjectInformation
1463 *        <FILLMEIN>
1464 *
1465 * @param Length
1466 *        <FILLMEIN>
1467 *
1468 * @param ResultLength
1469 *        <FILLMEIN>
1470 *
1471 * @return STATUS_SUCCESS or appropriate error value.
1472 *
1473 * @remarks None.
1474 *
1475 *--*/
1476 NTSTATUS
1477 NTAPI
1478 NtQueryObject(IN HANDLE ObjectHandle,
1479               IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
1480               OUT PVOID ObjectInformation,
1481               IN ULONG Length,
1482               OUT PULONG ResultLength OPTIONAL)
1483 {
1484     OBJECT_HANDLE_INFORMATION HandleInfo;
1485     POBJECT_HEADER ObjectHeader = NULL;
1486     POBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleFlags;
1487     POBJECT_BASIC_INFORMATION BasicInfo;
1488     ULONG InfoLength = 0;
1489     PVOID Object = NULL;
1490     NTSTATUS Status;
1491     POBJECT_HEADER_QUOTA_INFO ObjectQuota;
1492     SECURITY_INFORMATION SecurityInformation;
1493     POBJECT_TYPE ObjectType;
1494     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1495     PAGED_CODE();
1496 
1497     /* Check if the caller is from user mode */
1498     if (PreviousMode != KernelMode)
1499     {
1500         /* Protect validation with SEH */
1501         _SEH2_TRY
1502         {
1503             /* Probe the input structure */
1504             ProbeForWrite(ObjectInformation, Length, sizeof(UCHAR));
1505 
1506             /* If we have a result length, probe it too */
1507             if (ResultLength) ProbeForWriteUlong(ResultLength);
1508         }
1509         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1510         {
1511             /* Return the exception code */
1512             _SEH2_YIELD(return _SEH2_GetExceptionCode());
1513         }
1514         _SEH2_END;
1515     }
1516 
1517     /*
1518      * Make sure this isn't a generic type query, since the caller doesn't
1519      * have to give a handle for it
1520      */
1521     if (ObjectInformationClass != ObjectTypesInformation)
1522     {
1523         /* Reference the object */
1524         Status = ObReferenceObjectByHandle(ObjectHandle,
1525                                            0,
1526                                            NULL,
1527                                            KeGetPreviousMode(),
1528                                            &Object,
1529                                            &HandleInfo);
1530         if (!NT_SUCCESS (Status)) return Status;
1531 
1532         /* Get the object header */
1533         ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
1534         ObjectType = ObjectHeader->Type;
1535     }
1536 
1537     _SEH2_TRY
1538     {
1539         /* Check the information class */
1540         switch (ObjectInformationClass)
1541         {
1542             /* Basic info */
1543             case ObjectBasicInformation:
1544 
1545                 /* Validate length */
1546                 InfoLength = sizeof(OBJECT_BASIC_INFORMATION);
1547                 if (Length != sizeof(OBJECT_BASIC_INFORMATION))
1548                 {
1549                     /* Fail */
1550                     Status = STATUS_INFO_LENGTH_MISMATCH;
1551                     break;
1552                 }
1553 
1554                 /* Fill out the basic information */
1555                 BasicInfo = (POBJECT_BASIC_INFORMATION)ObjectInformation;
1556                 BasicInfo->Attributes = HandleInfo.HandleAttributes;
1557                 BasicInfo->GrantedAccess = HandleInfo.GrantedAccess;
1558                 BasicInfo->HandleCount = ObjectHeader->HandleCount;
1559                 BasicInfo->PointerCount = ObjectHeader->PointerCount;
1560 
1561                 /* Permanent/Exclusive Flags are NOT in Handle attributes! */
1562                 if (ObjectHeader->Flags & OB_FLAG_EXCLUSIVE)
1563                 {
1564                     /* Set the flag */
1565                     BasicInfo->Attributes |= OBJ_EXCLUSIVE;
1566                 }
1567                 if (ObjectHeader->Flags & OB_FLAG_PERMANENT)
1568                 {
1569                     /* Set the flag */
1570                     BasicInfo->Attributes |= OBJ_PERMANENT;
1571                 }
1572 
1573                 /* Copy quota information */
1574                 ObjectQuota = OBJECT_HEADER_TO_QUOTA_INFO(ObjectHeader);
1575                 if (ObjectQuota != NULL)
1576                 {
1577                     BasicInfo->PagedPoolCharge = ObjectQuota->PagedPoolCharge;
1578                     BasicInfo->NonPagedPoolCharge = ObjectQuota->NonPagedPoolCharge;
1579                 }
1580                 else
1581                 {
1582                     BasicInfo->PagedPoolCharge = 0;
1583                     BasicInfo->NonPagedPoolCharge = 0;
1584                 }
1585 
1586                 /* Copy name information */
1587                 BasicInfo->NameInfoSize = 0; /* FIXME*/
1588                 BasicInfo->TypeInfoSize = 0; /* FIXME*/
1589 
1590                 /* Check if this is a symlink */
1591                 if (ObjectHeader->Type == ObpSymbolicLinkObjectType)
1592                 {
1593                     /* Return the creation time */
1594                     BasicInfo->CreationTime.QuadPart =
1595                         ((POBJECT_SYMBOLIC_LINK)Object)->CreationTime.QuadPart;
1596                 }
1597                 else
1598                 {
1599                     /* Otherwise return 0 */
1600                     BasicInfo->CreationTime.QuadPart = (ULONGLONG)0;
1601                 }
1602 
1603                 /* Copy security information */
1604                 BasicInfo->SecurityDescriptorSize = 0;
1605                 if (BooleanFlagOn(HandleInfo.GrantedAccess, READ_CONTROL) &&
1606                     ObjectHeader->SecurityDescriptor != NULL)
1607                 {
1608                     SecurityInformation = OWNER_SECURITY_INFORMATION |
1609                                           GROUP_SECURITY_INFORMATION |
1610                                           DACL_SECURITY_INFORMATION |
1611                                           SACL_SECURITY_INFORMATION;
1612 
1613                     ObjectType->TypeInfo.SecurityProcedure(Object,
1614                                                            QuerySecurityDescriptor,
1615                                                            &SecurityInformation,
1616                                                            NULL,
1617                                                            &BasicInfo->SecurityDescriptorSize,
1618                                                            &ObjectHeader->SecurityDescriptor,
1619                                                            ObjectType->TypeInfo.PoolType,
1620                                                            &ObjectType->TypeInfo.GenericMapping);
1621                 }
1622 
1623                 /* Break out with success */
1624                 Status = STATUS_SUCCESS;
1625                 break;
1626 
1627             /* Name information */
1628             case ObjectNameInformation:
1629 
1630                 /* Call the helper and break out */
1631                 Status = ObQueryNameString(Object,
1632                                            (POBJECT_NAME_INFORMATION)
1633                                            ObjectInformation,
1634                                            Length,
1635                                            &InfoLength);
1636                 break;
1637 
1638             /* Information about this type */
1639             case ObjectTypeInformation:
1640 
1641                 /* Call the helper and break out */
1642                 Status = ObQueryTypeInfo(ObjectHeader->Type,
1643                                          (POBJECT_TYPE_INFORMATION)
1644                                          ObjectInformation,
1645                                          Length,
1646                                          &InfoLength);
1647                 break;
1648 
1649             /* Information about all types */
1650             case ObjectTypesInformation:
1651                 DPRINT1("NOT IMPLEMENTED!\n");
1652                 InfoLength = Length;
1653                 Status = STATUS_NOT_IMPLEMENTED;
1654                 break;
1655 
1656             /* Information about the handle flags */
1657             case ObjectHandleFlagInformation:
1658 
1659                 /* Validate length */
1660                 InfoLength = sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION);
1661                 if (Length != sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION))
1662                 {
1663                     Status = STATUS_INFO_LENGTH_MISMATCH;
1664                     break;
1665                 }
1666 
1667                 /* Get the structure */
1668                 HandleFlags = (POBJECT_HANDLE_ATTRIBUTE_INFORMATION)
1669                                ObjectInformation;
1670 
1671                 /* Set the flags */
1672                 HandleFlags->Inherit = HandleInfo.HandleAttributes & OBJ_INHERIT;
1673                 HandleFlags->ProtectFromClose = (HandleInfo.HandleAttributes &
1674                                                  OBJ_PROTECT_CLOSE) != 0;
1675 
1676                 /* Break out with success */
1677                 Status = STATUS_SUCCESS;
1678                 break;
1679 
1680             /* Anything else */
1681             default:
1682 
1683                 /* Fail it */
1684                 InfoLength = Length;
1685                 Status = STATUS_INVALID_INFO_CLASS;
1686                 break;
1687         }
1688 
1689         /* Check if the caller wanted the return length */
1690         if (ResultLength)
1691         {
1692             /* Write the length */
1693             *ResultLength = InfoLength;
1694         }
1695     }
1696     _SEH2_EXCEPT(ExSystemExceptionFilter())
1697     {
1698         /* Otherwise, get the exception code */
1699         Status = _SEH2_GetExceptionCode();
1700     }
1701     _SEH2_END;
1702 
1703     /* Dereference the object if we had referenced it */
1704     if (Object) ObDereferenceObject(Object);
1705 
1706     /* Return status */
1707     return Status;
1708 }
1709 
1710 /*++
1711 * @name NtSetInformationObject
1712 * @implemented NT4
1713 *
1714 *     The NtSetInformationObject routine <FILLMEIN>
1715 *
1716 * @param ObjectHandle
1717 *        <FILLMEIN>
1718 *
1719 * @param ObjectInformationClass
1720 *        <FILLMEIN>
1721 *
1722 * @param ObjectInformation
1723 *        <FILLMEIN>
1724 *
1725 * @param Length
1726 *        <FILLMEIN>
1727 *
1728 * @return STATUS_SUCCESS or appropriate error value.
1729 *
1730 * @remarks None.
1731 *
1732 *--*/
1733 NTSTATUS
1734 NTAPI
1735 NtSetInformationObject(IN HANDLE ObjectHandle,
1736                        IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
1737                        IN PVOID ObjectInformation,
1738                        IN ULONG Length)
1739 {
1740     NTSTATUS Status;
1741     OBP_SET_HANDLE_ATTRIBUTES_CONTEXT Context;
1742     PVOID ObjectTable;
1743     KAPC_STATE ApcState;
1744     POBJECT_DIRECTORY Directory;
1745     KPROCESSOR_MODE PreviousMode;
1746     BOOLEAN AttachedToProcess = FALSE;
1747     PAGED_CODE();
1748 
1749     /* Validate the information class */
1750     switch (ObjectInformationClass)
1751     {
1752         case ObjectHandleFlagInformation:
1753 
1754             /* Validate the length */
1755             if (Length != sizeof(OBJECT_HANDLE_ATTRIBUTE_INFORMATION))
1756             {
1757                 /* Invalid length */
1758                 return STATUS_INFO_LENGTH_MISMATCH;
1759             }
1760 
1761             /* Save the previous mode */
1762             Context.PreviousMode = ExGetPreviousMode();
1763 
1764             /* Check if we were called from user mode */
1765             if (Context.PreviousMode != KernelMode)
1766             {
1767                 /* Enter SEH */
1768                 _SEH2_TRY
1769                 {
1770                     /* Probe and capture the attribute buffer */
1771                     ProbeForRead(ObjectInformation,
1772                                  sizeof(OBJECT_HANDLE_ATTRIBUTE_INFORMATION),
1773                                  sizeof(BOOLEAN));
1774                     Context.Information = *(POBJECT_HANDLE_ATTRIBUTE_INFORMATION)
1775                                             ObjectInformation;
1776                 }
1777                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1778                 {
1779                     /* Return the exception code */
1780                     _SEH2_YIELD(return _SEH2_GetExceptionCode());
1781                 }
1782                 _SEH2_END;
1783             }
1784             else
1785             {
1786                 /* Just copy the buffer directly */
1787                 Context.Information = *(POBJECT_HANDLE_ATTRIBUTE_INFORMATION)
1788                                         ObjectInformation;
1789             }
1790 
1791             /* Check if this is a kernel handle */
1792             if (ObpIsKernelHandle(ObjectHandle, Context.PreviousMode))
1793             {
1794                 /* Get the actual handle */
1795                 ObjectHandle = ObKernelHandleToHandle(ObjectHandle);
1796                 ObjectTable = ObpKernelHandleTable;
1797 
1798                 /* Check if we're not in the system process */
1799                 if (PsGetCurrentProcess() != PsInitialSystemProcess)
1800                 {
1801                     /* Attach to it */
1802                     KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
1803                     AttachedToProcess = TRUE;
1804                 }
1805             }
1806             else
1807             {
1808                 /* Use the current table */
1809                 ObjectTable = PsGetCurrentProcess()->ObjectTable;
1810             }
1811 
1812             /* Change the handle attributes */
1813             if (!ExChangeHandle(ObjectTable,
1814                                 ObjectHandle,
1815                                 ObpSetHandleAttributes,
1816                                 (ULONG_PTR)&Context))
1817             {
1818                 /* Some failure */
1819                 Status = STATUS_ACCESS_DENIED;
1820             }
1821             else
1822             {
1823                 /* We are done */
1824                 Status = STATUS_SUCCESS;
1825             }
1826 
1827             /* De-attach if we were attached, and return status */
1828             if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1829             break;
1830 
1831         case ObjectSessionInformation:
1832 
1833             /* Only a system process can do this */
1834             PreviousMode = ExGetPreviousMode();
1835             if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
1836             {
1837                 /* Fail */
1838                 DPRINT1("Privilege not held\n");
1839                 Status = STATUS_PRIVILEGE_NOT_HELD;
1840             }
1841             else
1842             {
1843                 /* Get the object directory */
1844                 Status = ObReferenceObjectByHandle(ObjectHandle,
1845                                                    0,
1846                                                    ObpDirectoryObjectType,
1847                                                    PreviousMode,
1848                                                    (PVOID*)&Directory,
1849                                                    NULL);
1850                 if (NT_SUCCESS(Status))
1851                 {
1852                     /* Setup a lookup context */
1853                     OBP_LOOKUP_CONTEXT LookupContext;
1854                     ObpInitializeLookupContext(&LookupContext);
1855 
1856                     /* Set the directory session ID */
1857                     ObpAcquireDirectoryLockExclusive(Directory, &LookupContext);
1858                     Directory->SessionId = PsGetCurrentProcessSessionId();
1859                     ObpReleaseDirectoryLock(Directory, &LookupContext);
1860 
1861                     /* We're done, release the context and dereference the directory */
1862                     ObpReleaseLookupContext(&LookupContext);
1863                     ObDereferenceObject(Directory);
1864                 }
1865             }
1866             break;
1867 
1868         default:
1869             /* Unsupported class */
1870             Status = STATUS_INVALID_INFO_CLASS;
1871             break;
1872     }
1873 
1874     return Status;
1875 }
1876 
1877 /* EOF */
1878