xref: /reactos/ntoskrnl/ob/oblife.c (revision 19b18ce2)
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     NTSTATUS Status = STATUS_SUCCESS;
464     PSECURITY_DESCRIPTOR SecurityDescriptor;
465     PSECURITY_QUALITY_OF_SERVICE SecurityQos;
466     PUNICODE_STRING LocalObjectName = NULL;
467     PAGED_CODE();
468 
469     /* Zero out the Capture Data */
470     RtlZeroMemory(ObjectCreateInfo, sizeof(OBJECT_CREATE_INFORMATION));
471 
472     /* SEH everything here for protection */
473     _SEH2_TRY
474     {
475         /* Check if we got attributes */
476         if (ObjectAttributes)
477         {
478             /* Check if we're in user mode */
479             if (AccessMode != KernelMode)
480             {
481                 /* Probe the attributes */
482                 ProbeForRead(ObjectAttributes,
483                              sizeof(OBJECT_ATTRIBUTES),
484                              sizeof(ULONG));
485             }
486 
487             /* Validate the Size and Attributes */
488             if ((ObjectAttributes->Length != sizeof(OBJECT_ATTRIBUTES)) ||
489                 (ObjectAttributes->Attributes & ~OBJ_VALID_KERNEL_ATTRIBUTES))
490             {
491                 /* Invalid combination, fail */
492                 _SEH2_YIELD(return STATUS_INVALID_PARAMETER);
493             }
494 
495             /* Set some Create Info and do not allow user-mode kernel handles */
496             ObjectCreateInfo->RootDirectory = ObjectAttributes->RootDirectory;
497             ObjectCreateInfo->Attributes = ObjectAttributes->Attributes & OBJ_VALID_KERNEL_ATTRIBUTES;
498             if (CreatorMode != KernelMode) ObjectCreateInfo->Attributes &= ~OBJ_KERNEL_HANDLE;
499             LocalObjectName = ObjectAttributes->ObjectName;
500             SecurityDescriptor = ObjectAttributes->SecurityDescriptor;
501             SecurityQos = ObjectAttributes->SecurityQualityOfService;
502 
503             /* Check if we have a security descriptor */
504             if (SecurityDescriptor)
505             {
506                 /* Capture it. Note: This has an implicit memory barrier due
507                    to the function call, so cleanup is safe here.) */
508                 Status = SeCaptureSecurityDescriptor(SecurityDescriptor,
509                                                      AccessMode,
510                                                      NonPagedPool,
511                                                      TRUE,
512                                                      &ObjectCreateInfo->
513                                                      SecurityDescriptor);
514                 if (!NT_SUCCESS(Status))
515                 {
516                     /* Capture failed, quit */
517                     ObjectCreateInfo->SecurityDescriptor = NULL;
518                     _SEH2_YIELD(return Status);
519                 }
520 
521                 /* Save the probe mode and security descriptor size */
522                 ObjectCreateInfo->SecurityDescriptorCharge = 2048; /* FIXME */
523                 ObjectCreateInfo->ProbeMode = AccessMode;
524             }
525 
526             /* Check if we have QoS */
527             if (SecurityQos)
528             {
529                 /* Check if we came from user mode */
530                 if (AccessMode != KernelMode)
531                 {
532                     /* Validate the QoS */
533                     ProbeForRead(SecurityQos,
534                                  sizeof(SECURITY_QUALITY_OF_SERVICE),
535                                  sizeof(ULONG));
536                 }
537 
538                 /* Save Info */
539                 ObjectCreateInfo->SecurityQualityOfService = *SecurityQos;
540                 ObjectCreateInfo->SecurityQos =
541                     &ObjectCreateInfo->SecurityQualityOfService;
542             }
543         }
544         else
545         {
546             /* We don't have a name */
547             LocalObjectName = NULL;
548         }
549     }
550     _SEH2_EXCEPT(ExSystemExceptionFilter())
551     {
552         /* Cleanup and return the exception code */
553         ObpReleaseObjectCreateInformation(ObjectCreateInfo);
554         _SEH2_YIELD(return _SEH2_GetExceptionCode());
555     }
556     _SEH2_END;
557 
558     /* Now check if the Object Attributes had an Object Name */
559     if (LocalObjectName)
560     {
561         Status = ObpCaptureObjectName(ObjectName,
562                                       LocalObjectName,
563                                       AccessMode,
564                                       AllocateFromLookaside);
565     }
566     else
567     {
568         /* Clear the string */
569         RtlInitEmptyUnicodeString(ObjectName, NULL, 0);
570 
571         /* It cannot have specified a Root Directory */
572         if (ObjectCreateInfo->RootDirectory)
573         {
574             Status = STATUS_OBJECT_NAME_INVALID;
575         }
576     }
577 
578     /* Cleanup if we failed */
579     if (!NT_SUCCESS(Status))
580     {
581         ObpReleaseObjectCreateInformation(ObjectCreateInfo);
582     }
583 
584     /* Return status to caller */
585     return Status;
586 }
587 
588 VOID
589 NTAPI
590 ObFreeObjectCreateInfoBuffer(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo)
591 {
592     /* Call the macro. We use this function to isolate Ob internals from Io */
593     ObpFreeCapturedAttributes(ObjectCreateInfo, LookasideCreateInfoList);
594 }
595 
596 NTSTATUS
597 NTAPI
598 ObpAllocateObject(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo,
599                   IN PUNICODE_STRING ObjectName,
600                   IN POBJECT_TYPE ObjectType,
601                   IN ULONG ObjectSize,
602                   IN KPROCESSOR_MODE PreviousMode,
603                   IN POBJECT_HEADER *ObjectHeader)
604 {
605     POBJECT_HEADER Header;
606     ULONG QuotaSize, HandleSize, NameSize, CreatorSize;
607     POBJECT_HEADER_HANDLE_INFO HandleInfo;
608     POBJECT_HEADER_NAME_INFO NameInfo;
609     POBJECT_HEADER_CREATOR_INFO CreatorInfo;
610     POBJECT_HEADER_QUOTA_INFO QuotaInfo;
611     POOL_TYPE PoolType;
612     ULONG FinalSize;
613     ULONG Tag;
614     PAGED_CODE();
615 
616     /* Accounting */
617     ObpObjectsCreated++;
618 
619     /* Check if we don't have an Object Type yet */
620     if (!ObjectType)
621     {
622         /* Use default tag and non-paged pool */
623         PoolType = NonPagedPool;
624         Tag = 'TjbO';
625     }
626     else
627     {
628         /* Use the pool and tag given */
629         PoolType = ObjectType->TypeInfo.PoolType;
630         Tag = ObjectType->Key;
631     }
632 
633     /* Check if we have no create information (ie: we're an object type) */
634     if (!ObjectCreateInfo)
635     {
636         /* Use defaults */
637         QuotaSize = HandleSize = 0;
638         NameSize = sizeof(OBJECT_HEADER_NAME_INFO);
639         CreatorSize = sizeof(OBJECT_HEADER_CREATOR_INFO);
640     }
641     else
642     {
643         /* Check if we have quota */
644         if ((((ObjectCreateInfo->PagedPoolCharge !=
645                ObjectType->TypeInfo.DefaultPagedPoolCharge) ||
646               (ObjectCreateInfo->NonPagedPoolCharge !=
647                ObjectType->TypeInfo.DefaultNonPagedPoolCharge) ||
648               (ObjectCreateInfo->SecurityDescriptorCharge > 2048)) &&
649              (PsGetCurrentProcess() != PsInitialSystemProcess)) ||
650             (ObjectCreateInfo->Attributes & OBJ_EXCLUSIVE))
651         {
652             /* Set quota size */
653             QuotaSize = sizeof(OBJECT_HEADER_QUOTA_INFO);
654             ObpObjectsWithPoolQuota++;
655         }
656         else
657         {
658             /* No Quota */
659             QuotaSize = 0;
660         }
661 
662         /* Check if we have a handle database */
663         if (ObjectType->TypeInfo.MaintainHandleCount)
664         {
665             /* Set handle database size */
666             HandleSize = sizeof(OBJECT_HEADER_HANDLE_INFO);
667             ObpObjectsWithHandleDB++;
668         }
669         else
670         {
671             /* None */
672             HandleSize = 0;
673         }
674 
675         /* Check if the Object has a name */
676         if (ObjectName->Buffer)
677         {
678             /* Set name size */
679             NameSize = sizeof(OBJECT_HEADER_NAME_INFO);
680             ObpObjectsWithName++;
681         }
682         else
683         {
684             /* No name */
685             NameSize = 0;
686         }
687 
688         /* Check if the Object maintains type lists */
689         if (ObjectType->TypeInfo.MaintainTypeList)
690         {
691             /* Set owner/creator size */
692             CreatorSize = sizeof(OBJECT_HEADER_CREATOR_INFO);
693             ObpObjectsWithCreatorInfo++;
694         }
695         else
696         {
697             /* No info */
698             CreatorSize = 0;
699         }
700     }
701 
702     /* Set final header size */
703     FinalSize = QuotaSize +
704                 HandleSize +
705                 NameSize +
706                 CreatorSize +
707                 FIELD_OFFSET(OBJECT_HEADER, Body);
708 
709     /* Allocate memory for the Object and Header */
710     Header = ExAllocatePoolWithTag(PoolType, FinalSize + ObjectSize, Tag);
711     if (!Header) return STATUS_INSUFFICIENT_RESOURCES;
712 
713     /* Check if we have a quota header */
714     if (QuotaSize)
715     {
716         /* Initialize quota info */
717         QuotaInfo = (POBJECT_HEADER_QUOTA_INFO)Header;
718         QuotaInfo->PagedPoolCharge = ObjectCreateInfo->PagedPoolCharge;
719         QuotaInfo->NonPagedPoolCharge = ObjectCreateInfo->NonPagedPoolCharge;
720         QuotaInfo->SecurityDescriptorCharge = ObjectCreateInfo->SecurityDescriptorCharge;
721         QuotaInfo->ExclusiveProcess = NULL;
722         Header = (POBJECT_HEADER)(QuotaInfo + 1);
723     }
724 
725     /* Check if we have a handle database header */
726     if (HandleSize)
727     {
728         /* Initialize Handle Info */
729         HandleInfo = (POBJECT_HEADER_HANDLE_INFO)Header;
730         HandleInfo->SingleEntry.HandleCount = 0;
731         Header = (POBJECT_HEADER)(HandleInfo + 1);
732     }
733 
734     /* Check if we have a name header */
735     if (NameSize)
736     {
737         /* Initialize the Object Name Info */
738         NameInfo = (POBJECT_HEADER_NAME_INFO)Header;
739         NameInfo->Name = *ObjectName;
740         NameInfo->Directory = NULL;
741         NameInfo->QueryReferences = 1;
742 
743         /* Check if this is a call with the special protection flag */
744         if ((PreviousMode == KernelMode) &&
745             (ObjectCreateInfo) &&
746             (ObjectCreateInfo->Attributes & OBJ_KERNEL_EXCLUSIVE))
747         {
748             /* Set flag which will make the object protected from user-mode */
749             NameInfo->QueryReferences |= OB_FLAG_KERNEL_EXCLUSIVE;
750         }
751 
752         /* Set the header pointer */
753         Header = (POBJECT_HEADER)(NameInfo + 1);
754     }
755 
756     /* Check if we have a creator header */
757     if (CreatorSize)
758     {
759         /* Initialize Creator Info */
760         CreatorInfo = (POBJECT_HEADER_CREATOR_INFO)Header;
761         CreatorInfo->CreatorBackTraceIndex = 0;
762         CreatorInfo->CreatorUniqueProcess = PsGetCurrentProcessId();
763         InitializeListHead(&CreatorInfo->TypeList);
764         Header = (POBJECT_HEADER)(CreatorInfo + 1);
765     }
766 
767     /* Check for quota information */
768     if (QuotaSize)
769     {
770         /* Set the offset */
771         Header->QuotaInfoOffset = (UCHAR)(QuotaSize +
772                                           HandleSize +
773                                           NameSize +
774                                           CreatorSize);
775     }
776     else
777     {
778         /* No offset */
779         Header->QuotaInfoOffset = 0;
780     }
781 
782     /* Check for handle information */
783     if (HandleSize)
784     {
785         /* Set the offset */
786         Header->HandleInfoOffset = (UCHAR)(HandleSize +
787                                            NameSize +
788                                            CreatorSize);
789     }
790     else
791     {
792         /* No offset */
793         Header->HandleInfoOffset = 0;
794     }
795 
796     /* Check for name information */
797     if (NameSize)
798     {
799         /* Set the offset */
800         Header->NameInfoOffset = (UCHAR)(NameSize + CreatorSize);
801     }
802     else
803     {
804         /* No Name */
805         Header->NameInfoOffset = 0;
806     }
807 
808     /* Set the new object flag */
809     Header->Flags = OB_FLAG_CREATE_INFO;
810 
811     /* Remember if we have creator info */
812     if (CreatorSize) Header->Flags |= OB_FLAG_CREATOR_INFO;
813 
814     /* Remember if we have handle info */
815     if (HandleSize) Header->Flags |= OB_FLAG_SINGLE_PROCESS;
816 
817     /* Initialize the object header */
818     Header->PointerCount = 1;
819     Header->HandleCount = 0;
820     Header->Type = ObjectType;
821     Header->ObjectCreateInfo = ObjectCreateInfo;
822     Header->SecurityDescriptor = NULL;
823 
824     /* Check if this is a permanent object */
825     if ((ObjectCreateInfo) && (ObjectCreateInfo->Attributes & OBJ_PERMANENT))
826     {
827         /* Set the needed flag so we can check */
828         Header->Flags |= OB_FLAG_PERMANENT;
829     }
830 
831     /* Check if this is an exclusive object */
832     if ((ObjectCreateInfo) && (ObjectCreateInfo->Attributes & OBJ_EXCLUSIVE))
833     {
834         /* Set the needed flag so we can check */
835         Header->Flags |= OB_FLAG_EXCLUSIVE;
836     }
837 
838     /* Set kernel-mode flag */
839     if (PreviousMode == KernelMode) Header->Flags |= OB_FLAG_KERNEL_MODE;
840 
841     /* Check if we have a type */
842     if (ObjectType)
843     {
844         /* Increase the number of objects of this type */
845         InterlockedIncrement((PLONG)&ObjectType->TotalNumberOfObjects);
846 
847         /* Update the high water */
848         ObjectType->HighWaterNumberOfObjects = max(ObjectType->
849                                                    TotalNumberOfObjects,
850                                                    ObjectType->
851                                                    HighWaterNumberOfObjects);
852     }
853 
854     /* Return Header */
855     *ObjectHeader = Header;
856     return STATUS_SUCCESS;
857 }
858 
859 NTSTATUS
860 NTAPI
861 ObQueryTypeInfo(IN POBJECT_TYPE ObjectType,
862                 OUT POBJECT_TYPE_INFORMATION ObjectTypeInfo,
863                 IN ULONG Length,
864                 OUT PULONG ReturnLength)
865 {
866     NTSTATUS Status = STATUS_SUCCESS;
867     PWSTR InfoBuffer;
868 
869     /* Enter SEH */
870     _SEH2_TRY
871     {
872         /* Set return length aligned to 4-byte boundary */
873         *ReturnLength += sizeof(*ObjectTypeInfo) +
874                          ALIGN_UP(ObjectType->Name.MaximumLength, ULONG);
875 
876         /* Check if thats too much though. */
877         if (Length < *ReturnLength)
878         {
879             _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH);
880         }
881 
882         /* Build the data */
883         ObjectTypeInfo->TotalNumberOfHandles =
884             ObjectType->TotalNumberOfHandles;
885         ObjectTypeInfo->TotalNumberOfObjects =
886             ObjectType->TotalNumberOfObjects;
887         ObjectTypeInfo->HighWaterNumberOfHandles =
888             ObjectType->HighWaterNumberOfHandles;
889         ObjectTypeInfo->HighWaterNumberOfObjects =
890             ObjectType->HighWaterNumberOfObjects;
891         ObjectTypeInfo->PoolType =
892             ObjectType->TypeInfo.PoolType;
893         ObjectTypeInfo->DefaultNonPagedPoolCharge =
894             ObjectType->TypeInfo.DefaultNonPagedPoolCharge;
895         ObjectTypeInfo->DefaultPagedPoolCharge =
896             ObjectType->TypeInfo.DefaultPagedPoolCharge;
897         ObjectTypeInfo->ValidAccessMask =
898             ObjectType->TypeInfo.ValidAccessMask;
899         ObjectTypeInfo->SecurityRequired =
900             ObjectType->TypeInfo.SecurityRequired;
901         ObjectTypeInfo->InvalidAttributes =
902             ObjectType->TypeInfo.InvalidAttributes;
903         ObjectTypeInfo->GenericMapping =
904             ObjectType->TypeInfo.GenericMapping;
905         ObjectTypeInfo->MaintainHandleCount =
906             ObjectType->TypeInfo.MaintainHandleCount;
907 
908         /* Setup the name buffer */
909         InfoBuffer = (PWSTR)(ObjectTypeInfo + 1);
910         ObjectTypeInfo->TypeName.Buffer = InfoBuffer;
911         ObjectTypeInfo->TypeName.MaximumLength = ObjectType->Name.MaximumLength;
912         ObjectTypeInfo->TypeName.Length = ObjectType->Name.Length;
913 
914         /* Copy it */
915         RtlCopyMemory(InfoBuffer,
916                       ObjectType->Name.Buffer,
917                       ObjectType->Name.Length);
918 
919         /* Null-terminate it */
920         (InfoBuffer)[ObjectType->Name.Length / sizeof(WCHAR)] = UNICODE_NULL;
921     }
922     _SEH2_EXCEPT(ExSystemExceptionFilter())
923     {
924         /* Otherwise, get the exception code */
925         Status = _SEH2_GetExceptionCode();
926     }
927     _SEH2_END;
928 
929     /* Return status to caller */
930     return Status;
931 }
932 
933 
934 /* PUBLIC FUNCTIONS **********************************************************/
935 
936 NTSTATUS
937 NTAPI
938 ObCreateObject(IN KPROCESSOR_MODE ProbeMode OPTIONAL,
939                IN POBJECT_TYPE Type,
940                IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
941                IN KPROCESSOR_MODE AccessMode,
942                IN OUT PVOID ParseContext OPTIONAL,
943                IN ULONG ObjectSize,
944                IN ULONG PagedPoolCharge OPTIONAL,
945                IN ULONG NonPagedPoolCharge OPTIONAL,
946                OUT PVOID *Object)
947 {
948     NTSTATUS Status;
949     POBJECT_CREATE_INFORMATION ObjectCreateInfo;
950     UNICODE_STRING ObjectName;
951     POBJECT_HEADER Header;
952 
953     /* Allocate a capture buffer */
954     ObjectCreateInfo = ObpAllocateObjectCreateInfoBuffer(LookasideCreateInfoList);
955     if (!ObjectCreateInfo) return STATUS_INSUFFICIENT_RESOURCES;
956 
957     /* Capture all the info */
958     Status = ObpCaptureObjectCreateInformation(ObjectAttributes,
959                                                ProbeMode,
960                                                AccessMode,
961                                                FALSE,
962                                                ObjectCreateInfo,
963                                                &ObjectName);
964     if (NT_SUCCESS(Status))
965     {
966         /* Validate attributes */
967         if (Type->TypeInfo.InvalidAttributes & ObjectCreateInfo->Attributes)
968         {
969             /* Fail */
970             Status = STATUS_INVALID_PARAMETER;
971         }
972         else
973         {
974             /* Check if we have a paged charge */
975             if (!PagedPoolCharge)
976             {
977                 /* Save it */
978                 PagedPoolCharge = Type->TypeInfo.DefaultPagedPoolCharge;
979             }
980 
981             /* Check for nonpaged charge */
982             if (!NonPagedPoolCharge)
983             {
984                 /* Save it */
985                 NonPagedPoolCharge = Type->TypeInfo.DefaultNonPagedPoolCharge;
986             }
987 
988             /* Write the pool charges */
989             ObjectCreateInfo->PagedPoolCharge = PagedPoolCharge;
990             ObjectCreateInfo->NonPagedPoolCharge = NonPagedPoolCharge;
991 
992             /* Allocate the Object */
993             Status = ObpAllocateObject(ObjectCreateInfo,
994                                        &ObjectName,
995                                        Type,
996                                        ObjectSize,
997                                        AccessMode,
998                                        &Header);
999             if (NT_SUCCESS(Status))
1000             {
1001                 /* Return the Object */
1002                 *Object = &Header->Body;
1003 
1004                 /* Check if this is a permanent object */
1005                 if (Header->Flags & OB_FLAG_PERMANENT)
1006                 {
1007                     /* Do the privilege check */
1008                     if (!SeSinglePrivilegeCheck(SeCreatePermanentPrivilege,
1009                                                 ProbeMode))
1010                     {
1011                         /* Fail */
1012                         ObpDeallocateObject(*Object);
1013                         Status = STATUS_PRIVILEGE_NOT_HELD;
1014                     }
1015                 }
1016 
1017                 /* Return status */
1018                 return Status;
1019             }
1020         }
1021 
1022         /* Release the Capture Info, we don't need it */
1023         ObpFreeObjectCreateInformation(ObjectCreateInfo);
1024         if (ObjectName.Buffer) ObpFreeObjectNameBuffer(&ObjectName);
1025     }
1026 
1027     /* We failed, so release the Buffer */
1028     ObpFreeCapturedAttributes(ObjectCreateInfo, LookasideCreateInfoList);
1029     return Status;
1030 }
1031 
1032 NTSTATUS
1033 NTAPI
1034 ObCreateObjectType(IN PUNICODE_STRING TypeName,
1035                    IN POBJECT_TYPE_INITIALIZER ObjectTypeInitializer,
1036                    IN PVOID Reserved,
1037                    OUT POBJECT_TYPE *ObjectType)
1038 {
1039     POBJECT_HEADER Header;
1040     POBJECT_TYPE LocalObjectType;
1041     ULONG HeaderSize;
1042     NTSTATUS Status;
1043     OBP_LOOKUP_CONTEXT Context;
1044     PWCHAR p;
1045     ULONG i;
1046     UNICODE_STRING ObjectName;
1047     ANSI_STRING AnsiName;
1048     POBJECT_HEADER_CREATOR_INFO CreatorInfo;
1049 
1050     /* Verify parameters */
1051     if (!(TypeName) ||
1052         !(TypeName->Length) ||
1053         (TypeName->Length % sizeof(WCHAR)) ||
1054         !(ObjectTypeInitializer) ||
1055         (ObjectTypeInitializer->Length != sizeof(*ObjectTypeInitializer)) ||
1056         (ObjectTypeInitializer->InvalidAttributes & ~OBJ_VALID_KERNEL_ATTRIBUTES) ||
1057         (ObjectTypeInitializer->MaintainHandleCount &&
1058          (!(ObjectTypeInitializer->OpenProcedure) &&
1059           !ObjectTypeInitializer->CloseProcedure)) ||
1060         ((!ObjectTypeInitializer->UseDefaultObject) &&
1061          (ObjectTypeInitializer->PoolType != NonPagedPool)))
1062     {
1063         /* Fail */
1064         return STATUS_INVALID_PARAMETER;
1065     }
1066 
1067     /* Make sure the name doesn't have a separator */
1068     p = TypeName->Buffer;
1069     i = TypeName->Length / sizeof(WCHAR);
1070     while (i--)
1071     {
1072         /* Check for one and fail */
1073         if (*p++ == OBJ_NAME_PATH_SEPARATOR) return STATUS_OBJECT_NAME_INVALID;
1074     }
1075 
1076     /* Setup a lookup context */
1077     ObpInitializeLookupContext(&Context);
1078 
1079     /* Check if we've already created the directory of types */
1080     if (ObpTypeDirectoryObject)
1081     {
1082         /* Acquire the directory lock */
1083         ObpAcquireDirectoryLockExclusive(ObpTypeDirectoryObject, &Context);
1084 
1085         /* Do the lookup */
1086         if (ObpLookupEntryDirectory(ObpTypeDirectoryObject,
1087                                     TypeName,
1088                                     OBJ_CASE_INSENSITIVE,
1089                                     FALSE,
1090                                     &Context))
1091         {
1092             /* We have already created it, so fail */
1093             ObpReleaseLookupContext(&Context);
1094             return STATUS_OBJECT_NAME_COLLISION;
1095         }
1096     }
1097 
1098     /* Now make a copy of the object name */
1099     ObjectName.Buffer = ExAllocatePoolWithTag(PagedPool,
1100                                               TypeName->MaximumLength,
1101                                               OB_NAME_TAG);
1102     if (!ObjectName.Buffer)
1103     {
1104         /* Out of memory, fail */
1105         ObpReleaseLookupContext(&Context);
1106         return STATUS_INSUFFICIENT_RESOURCES;
1107     }
1108 
1109     /* Set the length and copy the name */
1110     ObjectName.MaximumLength = TypeName->MaximumLength;
1111     RtlCopyUnicodeString(&ObjectName, TypeName);
1112 
1113     /* Allocate the Object */
1114     Status = ObpAllocateObject(NULL,
1115                                &ObjectName,
1116                                ObpTypeObjectType,
1117                                sizeof(OBJECT_TYPE),
1118                                KernelMode,
1119                                &Header);
1120     if (!NT_SUCCESS(Status))
1121     {
1122         /* Free the name and fail */
1123         ObpReleaseLookupContext(&Context);
1124         ExFreePool(ObjectName.Buffer);
1125         return Status;
1126     }
1127 
1128     /* Setup the flags and name */
1129     LocalObjectType = (POBJECT_TYPE)&Header->Body;
1130     LocalObjectType->Name = ObjectName;
1131     Header->Flags |= OB_FLAG_KERNEL_MODE | OB_FLAG_PERMANENT;
1132 
1133     /* Clear accounting data */
1134     LocalObjectType->TotalNumberOfObjects =
1135     LocalObjectType->TotalNumberOfHandles =
1136     LocalObjectType->HighWaterNumberOfObjects =
1137     LocalObjectType->HighWaterNumberOfHandles = 0;
1138 
1139     /* Check if this is the first Object Type */
1140     if (!ObpTypeObjectType)
1141     {
1142         /* It is, so set this as the type object */
1143         ObpTypeObjectType = LocalObjectType;
1144         Header->Type = ObpTypeObjectType;
1145 
1146         /* Set the hard-coded key and object count */
1147         LocalObjectType->TotalNumberOfObjects = 1;
1148         LocalObjectType->Key = 'TjbO';
1149     }
1150     else
1151     {
1152         /* Convert the tag to ASCII */
1153         Status = RtlUnicodeStringToAnsiString(&AnsiName, TypeName, TRUE);
1154         if (NT_SUCCESS(Status))
1155         {
1156             /* For every missing character, use a space */
1157             for (i = 3; i >= AnsiName.Length; i--) AnsiName.Buffer[i] = ' ';
1158 
1159             /* Set the key and free the converted name */
1160             LocalObjectType->Key = *(PULONG)AnsiName.Buffer;
1161             RtlFreeAnsiString(&AnsiName);
1162         }
1163         else
1164         {
1165             /* Just copy the characters */
1166             LocalObjectType->Key = *(PULONG)TypeName->Buffer;
1167         }
1168     }
1169 
1170     /* Set up the type information */
1171     LocalObjectType->TypeInfo = *ObjectTypeInitializer;
1172     LocalObjectType->TypeInfo.PoolType = ObjectTypeInitializer->PoolType;
1173 
1174     /* Check if we have to maintain a type list */
1175     if (NtGlobalFlag & FLG_MAINTAIN_OBJECT_TYPELIST)
1176     {
1177         /* Enable support */
1178         LocalObjectType->TypeInfo.MaintainTypeList = TRUE;
1179     }
1180 
1181     /* Calculate how much space our header'll take up */
1182     HeaderSize = sizeof(OBJECT_HEADER) +
1183                  sizeof(OBJECT_HEADER_NAME_INFO) +
1184                  (ObjectTypeInitializer->MaintainHandleCount ?
1185                   sizeof(OBJECT_HEADER_HANDLE_INFO) : 0);
1186 
1187     /* Check the pool type */
1188     if (ObjectTypeInitializer->PoolType == NonPagedPool)
1189     {
1190         /* Update the NonPaged Pool charge */
1191         LocalObjectType->TypeInfo.DefaultNonPagedPoolCharge += HeaderSize;
1192     }
1193     else
1194     {
1195         /* Update the Paged Pool charge */
1196         LocalObjectType->TypeInfo.DefaultPagedPoolCharge += HeaderSize;
1197     }
1198 
1199     /* All objects types need a security procedure */
1200     if (!ObjectTypeInitializer->SecurityProcedure)
1201     {
1202         LocalObjectType->TypeInfo.SecurityProcedure = SeDefaultObjectMethod;
1203     }
1204 
1205     /* Select the Wait Object */
1206     if (LocalObjectType->TypeInfo.UseDefaultObject)
1207     {
1208         /* Add the SYNCHRONIZE access mask since it's waitable */
1209         LocalObjectType->TypeInfo.ValidAccessMask |= SYNCHRONIZE;
1210 
1211         /* Use the "Default Object", a simple event */
1212         LocalObjectType->DefaultObject = &ObpDefaultObject;
1213     }
1214     /* The File Object gets an optimized hack so it can be waited on */
1215     else if ((TypeName->Length == 8) && !(wcscmp(TypeName->Buffer, L"File")))
1216     {
1217         /* Wait on the File Object's event directly */
1218         LocalObjectType->DefaultObject = UlongToPtr(FIELD_OFFSET(FILE_OBJECT,
1219                                                                  Event));
1220     }
1221     else if ((TypeName->Length == 24) && !(wcscmp(TypeName->Buffer, L"WaitablePort")))
1222     {
1223         /* Wait on the LPC Port's object directly */
1224         LocalObjectType->DefaultObject = UlongToPtr(FIELD_OFFSET(LPCP_PORT_OBJECT,
1225                                                                  WaitEvent));
1226     }
1227     else
1228     {
1229         /* No default Object */
1230         LocalObjectType->DefaultObject = NULL;
1231     }
1232 
1233     /* Initialize Object Type components */
1234     ExInitializeResourceLite(&LocalObjectType->Mutex);
1235     for (i = 0; i < 4; i++)
1236     {
1237         /* Initialize the object locks */
1238         ExInitializeResourceLite(&LocalObjectType->ObjectLocks[i]);
1239     }
1240     InitializeListHead(&LocalObjectType->TypeList);
1241 
1242     /* Lock the object type */
1243     ObpEnterObjectTypeMutex(ObpTypeObjectType);
1244 
1245     /* Get creator info and insert it into the type list */
1246     CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(Header);
1247     if (CreatorInfo)
1248     {
1249         InsertTailList(&ObpTypeObjectType->TypeList,
1250                        &CreatorInfo->TypeList);
1251 
1252         /* CORE-8423: Avoid inserting this a second time if someone creates a
1253          * handle to the object type (bug in Windows 2003) */
1254         Header->Flags &= ~OB_FLAG_CREATE_INFO;
1255     }
1256 
1257     /* Set the index and the entry into the object type array */
1258     LocalObjectType->Index = ObpTypeObjectType->TotalNumberOfObjects;
1259 
1260     ASSERT(LocalObjectType->Index != 0);
1261 
1262     if (LocalObjectType->Index < RTL_NUMBER_OF(ObpObjectTypes))
1263     {
1264         /* It fits, insert it */
1265         ObpObjectTypes[LocalObjectType->Index - 1] = LocalObjectType;
1266     }
1267 
1268     /* Release the object type */
1269     ObpLeaveObjectTypeMutex(ObpTypeObjectType);
1270 
1271     /* Check if we're actually creating the directory object itself */
1272     if (!(ObpTypeDirectoryObject) ||
1273         (ObpInsertEntryDirectory(ObpTypeDirectoryObject, &Context, Header)))
1274     {
1275         /* Check if the type directory exists */
1276         if (ObpTypeDirectoryObject)
1277         {
1278             /* Reference it */
1279             ObReferenceObject(ObpTypeDirectoryObject);
1280         }
1281 
1282         /* Cleanup the lookup context */
1283         ObpReleaseLookupContext(&Context);
1284 
1285         /* Return the object type and success */
1286         *ObjectType = LocalObjectType;
1287         return STATUS_SUCCESS;
1288     }
1289 
1290     /* If we got here, then we failed */
1291     ObpReleaseLookupContext(&Context);
1292     return STATUS_INSUFFICIENT_RESOURCES;
1293 }
1294 
1295 VOID
1296 NTAPI
1297 ObDeleteCapturedInsertInfo(IN PVOID Object)
1298 {
1299     POBJECT_HEADER ObjectHeader;
1300     PAGED_CODE();
1301 
1302     /* Check if there is anything to free */
1303     ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
1304     if ((ObjectHeader->Flags & OB_FLAG_CREATE_INFO) &&
1305         (ObjectHeader->ObjectCreateInfo != NULL))
1306     {
1307         /* Free the create info */
1308         ObpFreeObjectCreateInformation(ObjectHeader->ObjectCreateInfo);
1309         ObjectHeader->ObjectCreateInfo = NULL;
1310     }
1311 }
1312 
1313 VOID
1314 NTAPI
1315 ObpDeleteObjectType(IN PVOID Object)
1316 {
1317     ULONG i;
1318     POBJECT_TYPE ObjectType = (PVOID)Object;
1319 
1320     /* Loop our locks */
1321     for (i = 0; i < 4; i++)
1322     {
1323         /* Delete each one */
1324         ExDeleteResourceLite(&ObjectType->ObjectLocks[i]);
1325     }
1326 
1327     /* Delete our main mutex */
1328     ExDeleteResourceLite(&ObjectType->Mutex);
1329 }
1330 
1331 /*++
1332 * @name ObMakeTemporaryObject
1333 * @implemented NT4
1334 *
1335 *     The ObMakeTemporaryObject routine <FILLMEIN>
1336 *
1337 * @param ObjectBody
1338 *        <FILLMEIN>
1339 *
1340 * @return None.
1341 *
1342 * @remarks None.
1343 *
1344 *--*/
1345 VOID
1346 NTAPI
1347 ObMakeTemporaryObject(IN PVOID ObjectBody)
1348 {
1349     PAGED_CODE();
1350 
1351     /* Call the internal API */
1352     ObpSetPermanentObject(ObjectBody, FALSE);
1353 }
1354 
1355 /*++
1356 * @name NtMakeTemporaryObject
1357 * @implemented NT4
1358 *
1359 *     The NtMakeTemporaryObject routine <FILLMEIN>
1360 *
1361 * @param ObjectHandle
1362 *        <FILLMEIN>
1363 *
1364 * @return STATUS_SUCCESS or appropriate error value.
1365 *
1366 * @remarks None.
1367 *
1368 *--*/
1369 NTSTATUS
1370 NTAPI
1371 NtMakeTemporaryObject(IN HANDLE ObjectHandle)
1372 {
1373     PVOID ObjectBody;
1374     NTSTATUS Status;
1375     PAGED_CODE();
1376 
1377     /* Reference the object for DELETE access */
1378     Status = ObReferenceObjectByHandle(ObjectHandle,
1379                                        DELETE,
1380                                        NULL,
1381                                        KeGetPreviousMode(),
1382                                        &ObjectBody,
1383                                        NULL);
1384     if (Status != STATUS_SUCCESS) return Status;
1385 
1386     /* Set it as temporary and dereference it */
1387     ObpSetPermanentObject(ObjectBody, FALSE);
1388     ObDereferenceObject(ObjectBody);
1389     return STATUS_SUCCESS;
1390 }
1391 
1392 /*++
1393 * @name NtMakePermanentObject
1394 * @implemented NT4
1395 *
1396 *     The NtMakePermanentObject routine <FILLMEIN>
1397 *
1398 * @param ObjectHandle
1399 *        <FILLMEIN>
1400 *
1401 * @return STATUS_SUCCESS or appropriate error value.
1402 *
1403 * @remarks None.
1404 *
1405 *--*/
1406 NTSTATUS
1407 NTAPI
1408 NtMakePermanentObject(IN HANDLE ObjectHandle)
1409 {
1410     PVOID ObjectBody;
1411     NTSTATUS Status;
1412     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1413     PAGED_CODE();
1414 
1415     /* Make sure that the caller has SeCreatePermanentPrivilege */
1416     Status = SeSinglePrivilegeCheck(SeCreatePermanentPrivilege,
1417                                     PreviousMode);
1418     if (!NT_SUCCESS(Status)) return STATUS_PRIVILEGE_NOT_HELD;
1419 
1420     /* Reference the object */
1421     Status = ObReferenceObjectByHandle(ObjectHandle,
1422                                        0,
1423                                        NULL,
1424                                        PreviousMode,
1425                                        &ObjectBody,
1426                                        NULL);
1427     if (Status != STATUS_SUCCESS) return Status;
1428 
1429     /* Set it as permanent and dereference it */
1430     ObpSetPermanentObject(ObjectBody, TRUE);
1431     ObDereferenceObject(ObjectBody);
1432     return STATUS_SUCCESS;
1433 }
1434 
1435 /*++
1436 * @name NtQueryObject
1437 * @implemented NT4
1438 *
1439 *     The NtQueryObject routine <FILLMEIN>
1440 *
1441 * @param ObjectHandle
1442 *        <FILLMEIN>
1443 *
1444 * @param ObjectInformationClass
1445 *        <FILLMEIN>
1446 *
1447 * @param ObjectInformation
1448 *        <FILLMEIN>
1449 *
1450 * @param Length
1451 *        <FILLMEIN>
1452 *
1453 * @param ResultLength
1454 *        <FILLMEIN>
1455 *
1456 * @return STATUS_SUCCESS or appropriate error value.
1457 *
1458 * @remarks None.
1459 *
1460 *--*/
1461 NTSTATUS
1462 NTAPI
1463 NtQueryObject(IN HANDLE ObjectHandle,
1464               IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
1465               OUT PVOID ObjectInformation,
1466               IN ULONG Length,
1467               OUT PULONG ResultLength OPTIONAL)
1468 {
1469     OBJECT_HANDLE_INFORMATION HandleInfo;
1470     POBJECT_HEADER ObjectHeader = NULL;
1471     POBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleFlags;
1472     POBJECT_BASIC_INFORMATION BasicInfo;
1473     ULONG InfoLength = 0;
1474     PVOID Object = NULL;
1475     NTSTATUS Status;
1476     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1477     PAGED_CODE();
1478 
1479     /* Check if the caller is from user mode */
1480     if (PreviousMode != KernelMode)
1481     {
1482         /* Protect validation with SEH */
1483         _SEH2_TRY
1484         {
1485             /* Probe the input structure */
1486             ProbeForWrite(ObjectInformation, Length, sizeof(UCHAR));
1487 
1488             /* If we have a result length, probe it too */
1489             if (ResultLength) ProbeForWriteUlong(ResultLength);
1490         }
1491         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1492         {
1493             /* Return the exception code */
1494             _SEH2_YIELD(return _SEH2_GetExceptionCode());
1495         }
1496         _SEH2_END;
1497     }
1498 
1499     /*
1500      * Make sure this isn't a generic type query, since the caller doesn't
1501      * have to give a handle for it
1502      */
1503     if (ObjectInformationClass != ObjectTypesInformation)
1504     {
1505         /* Reference the object */
1506         Status = ObReferenceObjectByHandle(ObjectHandle,
1507                                            0,
1508                                            NULL,
1509                                            KeGetPreviousMode(),
1510                                            &Object,
1511                                            &HandleInfo);
1512         if (!NT_SUCCESS (Status)) return Status;
1513 
1514         /* Get the object header */
1515         ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
1516     }
1517 
1518     _SEH2_TRY
1519     {
1520         /* Check the information class */
1521         switch (ObjectInformationClass)
1522         {
1523             /* Basic info */
1524             case ObjectBasicInformation:
1525 
1526                 /* Validate length */
1527                 InfoLength = sizeof(OBJECT_BASIC_INFORMATION);
1528                 if (Length != sizeof(OBJECT_BASIC_INFORMATION))
1529                 {
1530                     /* Fail */
1531                     Status = STATUS_INFO_LENGTH_MISMATCH;
1532                     break;
1533                 }
1534 
1535                 /* Fill out the basic information */
1536                 BasicInfo = (POBJECT_BASIC_INFORMATION)ObjectInformation;
1537                 BasicInfo->Attributes = HandleInfo.HandleAttributes;
1538                 BasicInfo->GrantedAccess = HandleInfo.GrantedAccess;
1539                 BasicInfo->HandleCount = ObjectHeader->HandleCount;
1540                 BasicInfo->PointerCount = ObjectHeader->PointerCount;
1541 
1542                 /* Permanent/Exclusive Flags are NOT in Handle attributes! */
1543                 if (ObjectHeader->Flags & OB_FLAG_EXCLUSIVE)
1544                 {
1545                     /* Set the flag */
1546                     BasicInfo->Attributes |= OBJ_EXCLUSIVE;
1547                 }
1548                 if (ObjectHeader->Flags & OB_FLAG_PERMANENT)
1549                 {
1550                     /* Set the flag */
1551                     BasicInfo->Attributes |= OBJ_PERMANENT;
1552                 }
1553 
1554                 /* Copy quota information */
1555                 BasicInfo->PagedPoolCharge = 0; /* FIXME*/
1556                 BasicInfo->NonPagedPoolCharge = 0; /* FIXME*/
1557 
1558                 /* Copy name information */
1559                 BasicInfo->NameInfoSize = 0; /* FIXME*/
1560                 BasicInfo->TypeInfoSize = 0; /* FIXME*/
1561 
1562                 /* Copy security information */
1563                 BasicInfo->SecurityDescriptorSize = 0; /* FIXME*/
1564 
1565                 /* Check if this is a symlink */
1566                 if (ObjectHeader->Type == ObSymbolicLinkType)
1567                 {
1568                     /* Return the creation time */
1569                     BasicInfo->CreationTime.QuadPart =
1570                         ((POBJECT_SYMBOLIC_LINK)Object)->CreationTime.QuadPart;
1571                 }
1572                 else
1573                 {
1574                     /* Otherwise return 0 */
1575                     BasicInfo->CreationTime.QuadPart = (ULONGLONG)0;
1576                 }
1577 
1578                 /* Break out with success */
1579                 Status = STATUS_SUCCESS;
1580                 break;
1581 
1582             /* Name information */
1583             case ObjectNameInformation:
1584 
1585                 /* Call the helper and break out */
1586                 Status = ObQueryNameString(Object,
1587                                            (POBJECT_NAME_INFORMATION)
1588                                            ObjectInformation,
1589                                            Length,
1590                                            &InfoLength);
1591                 break;
1592 
1593             /* Information about this type */
1594             case ObjectTypeInformation:
1595 
1596                 /* Call the helper and break out */
1597                 Status = ObQueryTypeInfo(ObjectHeader->Type,
1598                                          (POBJECT_TYPE_INFORMATION)
1599                                          ObjectInformation,
1600                                          Length,
1601                                          &InfoLength);
1602                 break;
1603 
1604             /* Information about all types */
1605             case ObjectTypesInformation:
1606                 DPRINT1("NOT IMPLEMENTED!\n");
1607                 InfoLength = Length;
1608                 Status = STATUS_NOT_IMPLEMENTED;
1609                 break;
1610 
1611             /* Information about the handle flags */
1612             case ObjectHandleFlagInformation:
1613 
1614                 /* Validate length */
1615                 InfoLength = sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION);
1616                 if (Length != sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION))
1617                 {
1618                     Status = STATUS_INFO_LENGTH_MISMATCH;
1619                     break;
1620                 }
1621 
1622                 /* Get the structure */
1623                 HandleFlags = (POBJECT_HANDLE_ATTRIBUTE_INFORMATION)
1624                                ObjectInformation;
1625 
1626                 /* Set the flags */
1627                 HandleFlags->Inherit = HandleInfo.HandleAttributes & OBJ_INHERIT;
1628                 HandleFlags->ProtectFromClose = (HandleInfo.HandleAttributes &
1629                                                  OBJ_PROTECT_CLOSE) != 0;
1630 
1631                 /* Break out with success */
1632                 Status = STATUS_SUCCESS;
1633                 break;
1634 
1635             /* Anything else */
1636             default:
1637 
1638                 /* Fail it */
1639                 InfoLength = Length;
1640                 Status = STATUS_INVALID_INFO_CLASS;
1641                 break;
1642         }
1643 
1644         /* Check if the caller wanted the return length */
1645         if (ResultLength)
1646         {
1647             /* Write the length */
1648             *ResultLength = InfoLength;
1649         }
1650     }
1651     _SEH2_EXCEPT(ExSystemExceptionFilter())
1652     {
1653         /* Otherwise, get the exception code */
1654         Status = _SEH2_GetExceptionCode();
1655     }
1656     _SEH2_END;
1657 
1658     /* Dereference the object if we had referenced it */
1659     if (Object) ObDereferenceObject(Object);
1660 
1661     /* Return status */
1662     return Status;
1663 }
1664 
1665 /*++
1666 * @name NtSetInformationObject
1667 * @implemented NT4
1668 *
1669 *     The NtSetInformationObject routine <FILLMEIN>
1670 *
1671 * @param ObjectHandle
1672 *        <FILLMEIN>
1673 *
1674 * @param ObjectInformationClass
1675 *        <FILLMEIN>
1676 *
1677 * @param ObjectInformation
1678 *        <FILLMEIN>
1679 *
1680 * @param Length
1681 *        <FILLMEIN>
1682 *
1683 * @return STATUS_SUCCESS or appropriate error value.
1684 *
1685 * @remarks None.
1686 *
1687 *--*/
1688 NTSTATUS
1689 NTAPI
1690 NtSetInformationObject(IN HANDLE ObjectHandle,
1691                        IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
1692                        IN PVOID ObjectInformation,
1693                        IN ULONG Length)
1694 {
1695     NTSTATUS Status;
1696     OBP_SET_HANDLE_ATTRIBUTES_CONTEXT Context;
1697     PVOID ObjectTable;
1698     KAPC_STATE ApcState;
1699     POBJECT_DIRECTORY Directory;
1700     KPROCESSOR_MODE PreviousMode;
1701     BOOLEAN AttachedToProcess = FALSE;
1702     PAGED_CODE();
1703 
1704     /* Validate the information class */
1705     switch (ObjectInformationClass)
1706     {
1707         case ObjectHandleFlagInformation:
1708 
1709             /* Validate the length */
1710             if (Length != sizeof(OBJECT_HANDLE_ATTRIBUTE_INFORMATION))
1711             {
1712                 /* Invalid length */
1713                 return STATUS_INFO_LENGTH_MISMATCH;
1714             }
1715 
1716             /* Save the previous mode */
1717             Context.PreviousMode = ExGetPreviousMode();
1718 
1719             /* Check if we were called from user mode */
1720             if (Context.PreviousMode != KernelMode)
1721             {
1722                 /* Enter SEH */
1723                 _SEH2_TRY
1724                 {
1725                     /* Probe and capture the attribute buffer */
1726                     ProbeForRead(ObjectInformation,
1727                                  sizeof(OBJECT_HANDLE_ATTRIBUTE_INFORMATION),
1728                                  sizeof(BOOLEAN));
1729                     Context.Information = *(POBJECT_HANDLE_ATTRIBUTE_INFORMATION)
1730                                             ObjectInformation;
1731                 }
1732                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1733                 {
1734                     /* Return the exception code */
1735                     _SEH2_YIELD(return _SEH2_GetExceptionCode());
1736                 }
1737                 _SEH2_END;
1738             }
1739             else
1740             {
1741                 /* Just copy the buffer directly */
1742                 Context.Information = *(POBJECT_HANDLE_ATTRIBUTE_INFORMATION)
1743                                         ObjectInformation;
1744             }
1745 
1746             /* Check if this is a kernel handle */
1747             if (ObpIsKernelHandle(ObjectHandle, Context.PreviousMode))
1748             {
1749                 /* Get the actual handle */
1750                 ObjectHandle = ObKernelHandleToHandle(ObjectHandle);
1751                 ObjectTable = ObpKernelHandleTable;
1752 
1753                 /* Check if we're not in the system process */
1754                 if (PsGetCurrentProcess() != PsInitialSystemProcess)
1755                 {
1756                     /* Attach to it */
1757                     KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
1758                     AttachedToProcess = TRUE;
1759                 }
1760             }
1761             else
1762             {
1763                 /* Use the current table */
1764                 ObjectTable = PsGetCurrentProcess()->ObjectTable;
1765             }
1766 
1767             /* Change the handle attributes */
1768             if (!ExChangeHandle(ObjectTable,
1769                                 ObjectHandle,
1770                                 ObpSetHandleAttributes,
1771                                 (ULONG_PTR)&Context))
1772             {
1773                 /* Some failure */
1774                 Status = STATUS_ACCESS_DENIED;
1775             }
1776             else
1777             {
1778                 /* We are done */
1779                 Status = STATUS_SUCCESS;
1780             }
1781 
1782             /* De-attach if we were attached, and return status */
1783             if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1784             break;
1785 
1786         case ObjectSessionInformation:
1787 
1788             /* Only a system process can do this */
1789             PreviousMode = ExGetPreviousMode();
1790             if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
1791             {
1792                 /* Fail */
1793                 DPRINT1("Privilege not held\n");
1794                 Status = STATUS_PRIVILEGE_NOT_HELD;
1795             }
1796             else
1797             {
1798                 /* Get the object directory */
1799                 Status = ObReferenceObjectByHandle(ObjectHandle,
1800                                                    0,
1801                                                    ObDirectoryType,
1802                                                    PreviousMode,
1803                                                    (PVOID*)&Directory,
1804                                                    NULL);
1805                 if (NT_SUCCESS(Status))
1806                 {
1807                     /* FIXME: Missng locks */
1808                     /* Set its session ID */
1809                     Directory->SessionId = PsGetCurrentProcessSessionId();
1810                     ObDereferenceObject(Directory);
1811                 }
1812             }
1813             break;
1814 
1815         default:
1816             /* Unsupported class */
1817             Status = STATUS_INVALID_INFO_CLASS;
1818             break;
1819     }
1820 
1821     return Status;
1822 }
1823 
1824 /* EOF */
1825