xref: /reactos/ntoskrnl/ob/obhandle.c (revision 279107d5)
1 /*
2  * PROJECT:         ReactOS Kernel
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            ntoskrnl/ob/obhandle.c
5  * PURPOSE:         Manages all functions related to the Object Manager handle
6  *                  implementation, including creating and destroying handles
7  *                  and/or handle tables, duplicating objects, and setting the
8  *                  permanent or temporary flags.
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 PHANDLE_TABLE ObpKernelHandleTable = NULL;
21 ULONG ObpAccessProtectCloseBit = MAXIMUM_ALLOWED;
22 
23 #define TAG_OB_HANDLE 'dHbO'
24 
25 /* PRIVATE FUNCTIONS *********************************************************/
26 
27 PHANDLE_TABLE
28 NTAPI
29 ObReferenceProcessHandleTable(IN PEPROCESS Process)
30 {
31     PHANDLE_TABLE HandleTable = NULL;
32 
33     /* Lock the process */
34     if (ExAcquireRundownProtection(&Process->RundownProtect))
35     {
36         /* Get the handle table */
37         HandleTable = Process->ObjectTable;
38         if (!HandleTable)
39         {
40             /* No table, release the lock */
41             ExReleaseRundownProtection(&Process->RundownProtect);
42         }
43     }
44 
45     /* Return the handle table */
46     return HandleTable;
47 }
48 
49 VOID
50 NTAPI
51 ObDereferenceProcessHandleTable(IN PEPROCESS Process)
52 {
53     /* Release the process lock */
54     ExReleaseRundownProtection(&Process->RundownProtect);
55 }
56 
57 ULONG
58 NTAPI
59 ObGetProcessHandleCount(IN PEPROCESS Process)
60 {
61     ULONG HandleCount;
62     PHANDLE_TABLE HandleTable;
63 
64     ASSERT(Process);
65 
66     /* Ensure the handle table doesn't go away while we use it */
67     HandleTable = ObReferenceProcessHandleTable(Process);
68 
69     if (HandleTable != NULL)
70     {
71         /* Count the number of handles the process has */
72         HandleCount = HandleTable->HandleCount;
73 
74         /* Let the handle table go */
75         ObDereferenceProcessHandleTable(Process);
76     }
77     else
78     {
79         /* No handle table, no handles */
80         HandleCount = 0;
81     }
82 
83     return HandleCount;
84 }
85 
86 NTSTATUS
87 NTAPI
88 ObpReferenceProcessObjectByHandle(IN HANDLE Handle,
89                                   IN PEPROCESS Process,
90                                   IN PHANDLE_TABLE HandleTable,
91                                   IN KPROCESSOR_MODE AccessMode,
92                                   OUT PVOID *Object,
93                                   OUT POBJECT_HANDLE_INFORMATION HandleInformation,
94                                   OUT PACCESS_MASK AuditMask)
95 {
96     PHANDLE_TABLE_ENTRY HandleEntry;
97     POBJECT_HEADER ObjectHeader;
98     ACCESS_MASK GrantedAccess;
99     ULONG Attributes;
100     PETHREAD Thread = PsGetCurrentThread();
101     NTSTATUS Status;
102 
103     /* Assume failure */
104     *Object = NULL;
105 
106     /* Check if this is a special handle */
107     if (HandleToLong(Handle) < 0)
108     {
109         /* Check if the caller wants the current process */
110         if (Handle == NtCurrentProcess())
111         {
112             /* Return handle info */
113             HandleInformation->HandleAttributes = 0;
114             HandleInformation->GrantedAccess = Process->GrantedAccess;
115 
116             /* No audit mask */
117             *AuditMask = 0;
118 
119             /* Reference ourselves */
120             ObjectHeader = OBJECT_TO_OBJECT_HEADER(Process);
121             InterlockedIncrementSizeT(&ObjectHeader->PointerCount);
122 
123             /* Return the pointer */
124             *Object = Process;
125             ASSERT(*Object != NULL);
126             return STATUS_SUCCESS;
127         }
128 
129         /* Check if the caller wants the current thread */
130         if (Handle == NtCurrentThread())
131         {
132             /* Return handle information */
133             HandleInformation->HandleAttributes = 0;
134             HandleInformation->GrantedAccess = Thread->GrantedAccess;
135 
136             /* Reference ourselves */
137             ObjectHeader = OBJECT_TO_OBJECT_HEADER(Thread);
138             InterlockedIncrementSizeT(&ObjectHeader->PointerCount);
139 
140             /* No audit mask */
141             *AuditMask = 0;
142 
143             /* Return the pointer */
144             *Object = Thread;
145             ASSERT(*Object != NULL);
146             return STATUS_SUCCESS;
147         }
148 
149         /* This is a kernel handle... do we have access? */
150         if (AccessMode == KernelMode)
151         {
152             /* Use the kernel handle table and get the actual handle value */
153             Handle = ObKernelHandleToHandle(Handle);
154             HandleTable = ObpKernelHandleTable;
155         }
156         else
157         {
158             /* This is an illegal attempt to access a kernel handle */
159             return STATUS_INVALID_HANDLE;
160         }
161     }
162 
163     /* Enter a critical region while we touch the handle table */
164     ASSERT(HandleTable != NULL);
165     KeEnterCriticalRegion();
166 
167     /* Get the handle entry */
168     HandleEntry = ExMapHandleToPointer(HandleTable, Handle);
169     if (HandleEntry)
170     {
171         /* Get the object header and validate the type*/
172         ObjectHeader = ObpGetHandleObject(HandleEntry);
173 
174         /* Get the granted access and validate it */
175         GrantedAccess = HandleEntry->GrantedAccess;
176 
177         /* Mask out the internal attributes */
178         Attributes = HandleEntry->ObAttributes & OBJ_HANDLE_ATTRIBUTES;
179 
180         /* Fill out the information */
181         HandleInformation->HandleAttributes = Attributes;
182         HandleInformation->GrantedAccess = GrantedAccess;
183 
184         /* No audit mask (FIXME!) */
185         *AuditMask = 0;
186 
187         /* Return the pointer */
188         *Object = &ObjectHeader->Body;
189 
190         /* Add a reference */
191         InterlockedIncrementSizeT(&ObjectHeader->PointerCount);
192 
193         /* Unlock the handle */
194         ExUnlockHandleTableEntry(HandleTable, HandleEntry);
195         KeLeaveCriticalRegion();
196 
197         /* Return success */
198         ASSERT(*Object != NULL);
199         return STATUS_SUCCESS;
200     }
201     else
202     {
203         /* Invalid handle */
204         Status = STATUS_INVALID_HANDLE;
205     }
206 
207     /* Return failure status */
208     KeLeaveCriticalRegion();
209     return Status;
210 }
211 
212 BOOLEAN
213 NTAPI
214 ObpEnumFindHandleProcedure(IN PHANDLE_TABLE_ENTRY HandleEntry,
215                            IN HANDLE Handle,
216                            IN PVOID Context)
217 {
218     POBJECT_HEADER ObjectHeader;
219     ACCESS_MASK GrantedAccess;
220     ULONG HandleAttributes;
221     POBP_FIND_HANDLE_DATA FindData = Context;
222 
223     /* Get the object header */
224     ObjectHeader = ObpGetHandleObject(HandleEntry);
225 
226     /* Make sure it's valid and matching */
227     if ((FindData->ObjectHeader) && (FindData->ObjectHeader != ObjectHeader))
228     {
229         /* No match, fail */
230         return FALSE;
231     }
232 
233     /* Now attempt to match the object type */
234     if ((FindData->ObjectType) && (FindData->ObjectType != ObjectHeader->Type))
235     {
236         /* No match, fail */
237         return FALSE;
238     }
239 
240     /* Check if we have extra information */
241     if (FindData->HandleInformation)
242     {
243         /* Get the granted access and attributes */
244         GrantedAccess = HandleEntry->GrantedAccess;
245         HandleAttributes = HandleEntry->ObAttributes & OBJ_HANDLE_ATTRIBUTES;
246 
247         /* Attempt to match them */
248         if ((FindData->HandleInformation->HandleAttributes != HandleAttributes) ||
249             (FindData->HandleInformation->GrantedAccess != GrantedAccess))
250         {
251             /* No match, fail */
252             return FALSE;
253         }
254     }
255 
256     /* We have a match */
257     return TRUE;
258 }
259 
260 POBJECT_HANDLE_COUNT_ENTRY
261 NTAPI
262 ObpInsertHandleCount(IN POBJECT_HEADER ObjectHeader)
263 {
264     POBJECT_HEADER_HANDLE_INFO HandleInfo;
265     POBJECT_HANDLE_COUNT_ENTRY FreeEntry;
266     POBJECT_HANDLE_COUNT_DATABASE HandleDatabase, OldHandleDatabase;
267     ULONG i;
268     ULONG Size, OldSize;
269     OBJECT_HANDLE_COUNT_DATABASE SingleDatabase;
270     PAGED_CODE();
271 
272     /* Get the handle info */
273     HandleInfo = OBJECT_HEADER_TO_HANDLE_INFO(ObjectHeader);
274     if (!HandleInfo) return NULL;
275 
276     /* Check if we only have one entry */
277     if (ObjectHeader->Flags & OB_FLAG_SINGLE_PROCESS)
278     {
279         /* Fill out the single entry */
280         SingleDatabase.CountEntries = 1;
281         SingleDatabase.HandleCountEntries[0] = HandleInfo->SingleEntry;
282 
283         /* Use this as the old size */
284         OldHandleDatabase = &SingleDatabase;
285         OldSize = sizeof(SingleDatabase);
286 
287         /* Now we'll have two entries, and an entire DB */
288         i = 2;
289         Size = sizeof(OBJECT_HANDLE_COUNT_DATABASE) +
290                ((i - 1) * sizeof(OBJECT_HANDLE_COUNT_ENTRY));
291     }
292     else
293     {
294         /* We already have a DB, get the information from it */
295         OldHandleDatabase = HandleInfo->HandleCountDatabase;
296         i = OldHandleDatabase->CountEntries;
297         OldSize = sizeof(OBJECT_HANDLE_COUNT_DATABASE) +
298                   ((i - 1) * sizeof(OBJECT_HANDLE_COUNT_ENTRY));
299 
300         /* Add 4 more entries */
301         i += 4;
302         Size = OldSize + (4 * sizeof(OBJECT_HANDLE_COUNT_ENTRY));
303     }
304 
305     /* Allocate the DB */
306     HandleDatabase = ExAllocatePoolWithTag(PagedPool, Size, TAG_OB_HANDLE);
307     if (!HandleDatabase) return NULL;
308 
309     /* Copy the old database */
310     RtlCopyMemory(HandleDatabase, OldHandleDatabase, OldSize);
311 
312     /* Check if we he had a single entry before */
313     if (ObjectHeader->Flags & OB_FLAG_SINGLE_PROCESS)
314     {
315         /* Now we have more */
316         ObjectHeader->Flags &= ~OB_FLAG_SINGLE_PROCESS;
317     }
318     else
319     {
320         /* Otherwise we had a DB, free it */
321         ExFreePoolWithTag(OldHandleDatabase, TAG_OB_HANDLE);
322     }
323 
324     /* Find the end of the copy and zero out the new data */
325     FreeEntry = (PVOID)((ULONG_PTR)HandleDatabase + OldSize);
326     RtlZeroMemory(FreeEntry, Size - OldSize);
327 
328     /* Set the new information and return the free entry */
329     HandleDatabase->CountEntries = i;
330     HandleInfo->HandleCountDatabase = HandleDatabase;
331     return FreeEntry;
332 }
333 
334 NTSTATUS
335 NTAPI
336 ObpIncrementHandleDataBase(IN POBJECT_HEADER ObjectHeader,
337                            IN PEPROCESS Process,
338                            IN OUT PULONG NewProcessHandleCount)
339 {
340     POBJECT_HEADER_HANDLE_INFO HandleInfo;
341     POBJECT_HANDLE_COUNT_ENTRY HandleEntry, FreeEntry = NULL;
342     POBJECT_HANDLE_COUNT_DATABASE HandleDatabase;
343     ULONG i;
344     PAGED_CODE();
345 
346     /* Get the handle info and check if we only have one entry */
347     HandleInfo = OBJECT_HEADER_TO_HANDLE_INFO(ObjectHeader);
348     if (ObjectHeader->Flags & OB_FLAG_SINGLE_PROCESS)
349     {
350         /* Check if the entry is free */
351         if (!HandleInfo->SingleEntry.HandleCount)
352         {
353             /* Add ours */
354             HandleInfo->SingleEntry.HandleCount = 1;
355             HandleInfo->SingleEntry.Process = Process;
356 
357             /* Return success and 1 handle */
358             *NewProcessHandleCount = 1;
359             return STATUS_SUCCESS;
360         }
361         else if (HandleInfo->SingleEntry.Process == Process)
362         {
363             /* Busy entry, but same process */
364             *NewProcessHandleCount = ++HandleInfo->SingleEntry.HandleCount;
365             return STATUS_SUCCESS;
366         }
367         else
368         {
369             /* Insert a new entry */
370             FreeEntry = ObpInsertHandleCount(ObjectHeader);
371             if (!FreeEntry) return STATUS_INSUFFICIENT_RESOURCES;
372             ASSERT(!FreeEntry->Process);
373             ASSERT(!FreeEntry->HandleCount);
374 
375             /* Fill it out */
376             FreeEntry->Process = Process;
377             FreeEntry->HandleCount = 1;
378 
379             /* Return success and 1 handle */
380             *NewProcessHandleCount = 1;
381             return STATUS_SUCCESS;
382         }
383     }
384 
385     /* We have a database instead */
386     HandleDatabase = HandleInfo->HandleCountDatabase;
387     if (HandleDatabase)
388     {
389         /* Get the entries and loop them */
390         i = HandleDatabase->CountEntries;
391         HandleEntry = &HandleDatabase->HandleCountEntries[0];
392         while (i)
393         {
394             /* Check if this is a match */
395             if (HandleEntry->Process == Process)
396             {
397                 /* Found it, get the process handle count */
398                 *NewProcessHandleCount = ++HandleEntry->HandleCount;
399                 return STATUS_SUCCESS;
400             }
401             else if (!HandleEntry->HandleCount)
402             {
403                 /* Found a free entry */
404                 FreeEntry = HandleEntry;
405             }
406 
407             /* Keep looping */
408             HandleEntry++;
409             i--;
410         }
411 
412         /* Check if we couldn't find a free entry */
413         if (!FreeEntry)
414         {
415             /* Allocate one */
416             FreeEntry = ObpInsertHandleCount(ObjectHeader);
417             if (!FreeEntry) return STATUS_INSUFFICIENT_RESOURCES;
418             ASSERT(!FreeEntry->Process);
419             ASSERT(!FreeEntry->HandleCount);
420         }
421 
422         /* Fill out the entry */
423         FreeEntry->Process = Process;
424         FreeEntry->HandleCount = 1;
425         *NewProcessHandleCount = 1;
426     }
427 
428     /* Return success if we got here */
429     return STATUS_SUCCESS;
430 }
431 
432 NTSTATUS
433 NTAPI
434 ObpChargeQuotaForObject(IN POBJECT_HEADER ObjectHeader,
435                         IN POBJECT_TYPE ObjectType,
436                         OUT PBOOLEAN NewObject)
437 {
438     POBJECT_HEADER_QUOTA_INFO ObjectQuota;
439     ULONG PagedPoolCharge, NonPagedPoolCharge;
440 
441     /* Get quota information */
442     ObjectQuota = OBJECT_HEADER_TO_QUOTA_INFO(ObjectHeader);
443     *NewObject = FALSE;
444 
445     /* Check if this is a new object */
446     if (ObjectHeader->Flags & OB_FLAG_CREATE_INFO)
447     {
448         /* Remove the flag */
449         ObjectHeader->Flags &= ~ OB_FLAG_CREATE_INFO;
450         if (ObjectQuota)
451         {
452             /* We have a quota, get the charges */
453             PagedPoolCharge = ObjectQuota->PagedPoolCharge;
454             NonPagedPoolCharge = ObjectQuota->NonPagedPoolCharge;
455         }
456         else
457         {
458             /* Get it from the object type */
459             PagedPoolCharge = ObjectType->TypeInfo.DefaultPagedPoolCharge;
460             NonPagedPoolCharge = ObjectType->TypeInfo.DefaultNonPagedPoolCharge;
461         }
462 
463         /* Charge the quota */
464         ObjectHeader->QuotaBlockCharged = (PVOID)1;
465         DPRINT("FIXME: Should charge: %lx %lx\n", PagedPoolCharge, NonPagedPoolCharge);
466 #if 0
467             PsChargeSharedPoolQuota(PsGetCurrentProcess(),
468                                     PagedPoolCharge,
469                                     NonPagedPoolCharge);
470 #endif
471 
472         /* Check if we don't have a quota block */
473         if (!ObjectHeader->QuotaBlockCharged) return STATUS_QUOTA_EXCEEDED;
474 
475         /* Now set the flag */
476         *NewObject = TRUE;
477     }
478 
479     /* Return success */
480     return STATUS_SUCCESS;
481 }
482 
483 NTSTATUS
484 NTAPI
485 ObpValidateAccessMask(IN PACCESS_STATE AccessState)
486 {
487     PISECURITY_DESCRIPTOR SecurityDescriptor;
488 
489     /* We're only interested if the object for this access state has an SD */
490     SecurityDescriptor = AccessState->SecurityDescriptor;
491     if (SecurityDescriptor)
492     {
493         /* Check if the SD has a system ACL but hasn't been granted access to get/set it */
494         if ((SecurityDescriptor->Control & SE_SACL_PRESENT) &&
495             !(AccessState->PreviouslyGrantedAccess & ACCESS_SYSTEM_SECURITY))
496         {
497             /* We're gonna need access */
498             AccessState->RemainingDesiredAccess |= ACCESS_SYSTEM_SECURITY;
499         }
500     }
501 
502     /* This can't fail */
503     return STATUS_SUCCESS;
504 }
505 
506 /*++
507 * @name ObpDecrementHandleCount
508 *
509 *     The ObpDecrementHandleCount routine <FILLMEIN>
510 *
511 * @param ObjectBody
512 *        <FILLMEIN>.
513 *
514 * @param Process
515 *        <FILLMEIN>.
516 *
517 * @param GrantedAccess
518 *        <FILLMEIN>.
519 *
520 * @return None.
521 *
522 * @remarks None.
523 *
524 *--*/
525 VOID
526 NTAPI
527 ObpDecrementHandleCount(IN PVOID ObjectBody,
528                         IN PEPROCESS Process,
529                         IN ACCESS_MASK GrantedAccess,
530                         IN POBJECT_TYPE ObjectType)
531 {
532     POBJECT_HEADER ObjectHeader;
533     LONG SystemHandleCount, ProcessHandleCount;
534     LONG NewCount;
535     KIRQL CalloutIrql;
536     POBJECT_HEADER_HANDLE_INFO HandleInfo;
537     POBJECT_HANDLE_COUNT_ENTRY HandleEntry;
538     POBJECT_HANDLE_COUNT_DATABASE HandleDatabase;
539     ULONG i;
540     PAGED_CODE();
541 
542     /* Get the object type and header */
543     ObjectHeader = OBJECT_TO_OBJECT_HEADER(ObjectBody);
544     OBTRACE(OB_HANDLE_DEBUG,
545             "%s - Decrementing count for: %p. HC PC %lx %lx\n",
546             __FUNCTION__,
547             ObjectBody,
548             ObjectHeader->HandleCount,
549             ObjectHeader->PointerCount);
550 
551     /* Lock the object */
552     ObpAcquireObjectLock(ObjectHeader);
553 
554     /* Set default counts */
555     SystemHandleCount = ObjectHeader->HandleCount;
556     ProcessHandleCount = 0;
557 
558     /* Decrement the handle count */
559     NewCount = InterlockedDecrementSizeT(&ObjectHeader->HandleCount);
560 
561     /* Check if we're out of handles and this was an exclusive object */
562     if (!(NewCount) && (ObjectHeader->Flags & OB_FLAG_EXCLUSIVE))
563     {
564         /* Clear the exclusive flag */
565         OBJECT_HEADER_TO_QUOTA_INFO(ObjectHeader)->ExclusiveProcess = NULL;
566     }
567 
568     /* Is the object type keeping track of handles? */
569     if (ObjectType->TypeInfo.MaintainHandleCount)
570     {
571         /* Get handle information */
572         HandleInfo = OBJECT_HEADER_TO_HANDLE_INFO(ObjectHeader);
573 
574         /* Check if there's only a single entry */
575         if (ObjectHeader->Flags & OB_FLAG_SINGLE_PROCESS)
576         {
577             /* It should be us */
578             ASSERT(HandleInfo->SingleEntry.Process == Process);
579             ASSERT(HandleInfo->SingleEntry.HandleCount > 0);
580 
581             /* Get the handle counts */
582             ProcessHandleCount = HandleInfo->SingleEntry.HandleCount--;
583             HandleEntry = &HandleInfo->SingleEntry;
584         }
585         else
586         {
587             /* Otherwise, get the database */
588             HandleDatabase = HandleInfo->HandleCountDatabase;
589             if (HandleDatabase)
590             {
591                 /* Get the entries and loop them */
592                 i = HandleDatabase->CountEntries;
593                 HandleEntry = &HandleDatabase->HandleCountEntries[0];
594                 while (i)
595                 {
596                     /* Check if this is a match */
597                     if ((HandleEntry->HandleCount) &&
598                         (HandleEntry->Process == Process))
599                     {
600                         /* Found it, get the process handle count */
601                         ProcessHandleCount = HandleEntry->HandleCount--;
602                         break;
603                     }
604 
605                     /* Keep looping */
606                     HandleEntry++;
607                     i--;
608                 }
609             }
610             else
611             {
612                 /* No database, so no entry */
613                 HandleEntry = NULL;
614             }
615         }
616 
617         /* Check if this is the last handle */
618         if (ProcessHandleCount == 1)
619         {
620             /* Then clear the entry */
621             HandleEntry->Process = NULL;
622             HandleEntry->HandleCount = 0;
623         }
624     }
625 
626     /* Release the lock */
627     ObpReleaseObjectLock(ObjectHeader);
628 
629     /* Check if we have a close procedure */
630     if (ObjectType->TypeInfo.CloseProcedure)
631     {
632         /* Call it */
633         ObpCalloutStart(&CalloutIrql);
634         ObjectType->TypeInfo.CloseProcedure(Process,
635                                             ObjectBody,
636                                             GrantedAccess,
637                                             ProcessHandleCount,
638                                             SystemHandleCount);
639         ObpCalloutEnd(CalloutIrql, "Close", ObjectType, ObjectBody);
640     }
641 
642     /* Check if we should delete the object */
643     ObpDeleteNameCheck(ObjectBody);
644 
645     /* Decrease the total number of handles for this type */
646     InterlockedDecrement((PLONG)&ObjectType->TotalNumberOfHandles);
647     OBTRACE(OB_HANDLE_DEBUG,
648             "%s - Decremented count for: %p. HC PC %lx %lx\n",
649             __FUNCTION__,
650             ObjectBody,
651             ObjectHeader->HandleCount,
652             ObjectHeader->PointerCount);
653 }
654 
655 /*++
656 * @name ObpCloseHandleTableEntry
657 *
658 *     The ObpCloseHandleTableEntry routine <FILLMEIN>
659 *
660 * @param HandleTable
661 *        <FILLMEIN>.
662 *
663 * @param HandleEntry
664 *        <FILLMEIN>.
665 *
666 * @param Handle
667 *        <FILLMEIN>.
668 *
669 * @param AccessMode
670 *        <FILLMEIN>.
671 *
672 * @param IgnoreHandleProtection
673 *        <FILLMEIN>.
674 *
675 * @return <FILLMEIN>.
676 *
677 * @remarks None.
678 *
679 *--*/
680 NTSTATUS
681 NTAPI
682 ObpCloseHandleTableEntry(IN PHANDLE_TABLE HandleTable,
683                          IN PHANDLE_TABLE_ENTRY HandleEntry,
684                          IN HANDLE Handle,
685                          IN KPROCESSOR_MODE AccessMode,
686                          IN BOOLEAN IgnoreHandleProtection)
687 {
688     PVOID Body;
689     POBJECT_TYPE ObjectType;
690     POBJECT_HEADER ObjectHeader;
691     ACCESS_MASK GrantedAccess;
692     KIRQL CalloutIrql;
693     PAGED_CODE();
694 
695     /* Get the object data */
696     ObjectHeader = ObpGetHandleObject(HandleEntry);
697     ObjectType = ObjectHeader->Type;
698     Body = &ObjectHeader->Body;
699     GrantedAccess = HandleEntry->GrantedAccess;
700     OBTRACE(OB_HANDLE_DEBUG,
701             "%s - Closing handle: %p for %p. HC PC %lx %lx\n",
702             __FUNCTION__,
703             Handle,
704             Body,
705             ObjectHeader->HandleCount,
706             ObjectHeader->PointerCount);
707 
708     /* Check if the object has an Okay To Close procedure */
709     if (ObjectType->TypeInfo.OkayToCloseProcedure)
710     {
711         /* Call it and check if it's not letting us close it */
712         ObpCalloutStart(&CalloutIrql);
713         if (!ObjectType->TypeInfo.OkayToCloseProcedure(PsGetCurrentProcess(),
714                                                        Body,
715                                                        Handle,
716                                                        AccessMode))
717         {
718             /* Fail */
719             ObpCalloutEnd(CalloutIrql, "NtClose", ObjectType, Body);
720             ExUnlockHandleTableEntry(HandleTable, HandleEntry);
721             return STATUS_HANDLE_NOT_CLOSABLE;
722         }
723 
724         /* Success, validate callout retrn */
725         ObpCalloutEnd(CalloutIrql, "NtClose", ObjectType, Body);
726     }
727 
728     /* The callback allowed us to close it, but does the handle itself? */
729     if ((HandleEntry->ObAttributes & OBJ_PROTECT_CLOSE) &&
730         !(IgnoreHandleProtection))
731     {
732         /* It doesn't, are we from user mode? */
733         if (AccessMode != KernelMode)
734         {
735             /* We are! Unlock the entry */
736             ExUnlockHandleTableEntry(HandleTable, HandleEntry);
737 
738             /* Make sure we have a debug port */
739             if (PsGetCurrentProcess()->DebugPort)
740             {
741                 /* Raise an exception */
742                 return KeRaiseUserException(STATUS_HANDLE_NOT_CLOSABLE);
743             }
744             else
745             {
746                 /* Return the error instead */
747                 return STATUS_HANDLE_NOT_CLOSABLE;
748             }
749         }
750         else
751         {
752             /* Otherwise, bugcheck the OS */
753             KeBugCheckEx(INVALID_KERNEL_HANDLE, (ULONG_PTR)Handle, 0, 0, 0);
754         }
755     }
756 
757     /* Destroy and unlock the handle entry */
758     ExDestroyHandle(HandleTable, Handle, HandleEntry);
759 
760     /* Now decrement the handle count */
761     ObpDecrementHandleCount(Body,
762                             PsGetCurrentProcess(),
763                             GrantedAccess,
764                             ObjectType);
765 
766     /* Dereference the object as well */
767     ObDereferenceObject(Body);
768 
769     /* Return to caller */
770     OBTRACE(OB_HANDLE_DEBUG,
771             "%s - Closed handle: %p for %p.\n",
772             __FUNCTION__,
773             Handle,
774             Body);
775     return STATUS_SUCCESS;
776 }
777 
778 /*++
779 * @name ObpIncrementHandleCount
780 *
781 *     The ObpIncrementHandleCount routine <FILLMEIN>
782 *
783 * @param Object
784 *        <FILLMEIN>.
785 *
786 * @param AccessState
787 *        <FILLMEIN>.
788 *
789 * @param AccessMode
790 *        <FILLMEIN>.
791 *
792 * @param HandleAttributes
793 *        <FILLMEIN>.
794 *
795 * @param Process
796 *        <FILLMEIN>.
797 *
798 * @param OpenReason
799 *        <FILLMEIN>.
800 *
801 * @return <FILLMEIN>.
802 *
803 * @remarks None.
804 *
805 *--*/
806 NTSTATUS
807 NTAPI
808 ObpIncrementHandleCount(IN PVOID Object,
809                         IN PACCESS_STATE AccessState OPTIONAL,
810                         IN KPROCESSOR_MODE AccessMode,
811                         IN ULONG HandleAttributes,
812                         IN PEPROCESS Process,
813                         IN OB_OPEN_REASON OpenReason)
814 {
815     POBJECT_HEADER ObjectHeader;
816     POBJECT_TYPE ObjectType;
817     ULONG ProcessHandleCount;
818     NTSTATUS Status;
819     PEPROCESS ExclusiveProcess;
820     BOOLEAN Exclusive = FALSE, NewObject;
821     POBJECT_HEADER_CREATOR_INFO CreatorInfo;
822     KIRQL CalloutIrql;
823     KPROCESSOR_MODE ProbeMode;
824     ULONG Total;
825     POBJECT_HEADER_NAME_INFO NameInfo;
826     PAGED_CODE();
827 
828     /* Get the object header and type */
829     ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
830     ObjectType = ObjectHeader->Type;
831     OBTRACE(OB_HANDLE_DEBUG,
832             "%s - Incrementing count for: %p. Reason: %lx. HC PC %lx %lx\n",
833             __FUNCTION__,
834             Object,
835             OpenReason,
836             ObjectHeader->HandleCount,
837             ObjectHeader->PointerCount);
838 
839     /* Check if caller is forcing user mode */
840     if (HandleAttributes & OBJ_FORCE_ACCESS_CHECK)
841     {
842         /* Force it */
843         ProbeMode = UserMode;
844     }
845     else
846     {
847         /* Keep original setting */
848         ProbeMode = AccessMode;
849     }
850 
851     /* Lock the object */
852     ObpAcquireObjectLock(ObjectHeader);
853 
854     /* Charge quota and remove the creator info flag */
855     Status = ObpChargeQuotaForObject(ObjectHeader, ObjectType, &NewObject);
856     if (!NT_SUCCESS(Status)) return Status;
857 
858     /* Check if the open is exclusive */
859     if (HandleAttributes & OBJ_EXCLUSIVE)
860     {
861         /* Check if the object allows this, or if the inherit flag was given */
862         if ((HandleAttributes & OBJ_INHERIT) ||
863             !(ObjectHeader->Flags & OB_FLAG_EXCLUSIVE))
864         {
865             /* Incorrect attempt */
866             Status = STATUS_INVALID_PARAMETER;
867             goto Quickie;
868         }
869 
870         /* Check if we have access to it */
871         ExclusiveProcess = OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader);
872         if ((!(ExclusiveProcess) && (ObjectHeader->HandleCount)) ||
873             ((ExclusiveProcess) && (ExclusiveProcess != PsGetCurrentProcess())))
874         {
875             /* This isn't the right process */
876             Status = STATUS_ACCESS_DENIED;
877             goto Quickie;
878         }
879 
880         /* Now you got exclusive access */
881         Exclusive = TRUE;
882     }
883     else if ((ObjectHeader->Flags & OB_FLAG_EXCLUSIVE) &&
884              (OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader)))
885     {
886         /* Caller didn't want exclusive access, but the object is exclusive */
887         Status = STATUS_ACCESS_DENIED;
888         goto Quickie;
889     }
890 
891     /* Check for exclusive kernel object */
892     NameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
893     if ((NameInfo) && (NameInfo->QueryReferences & OB_FLAG_KERNEL_EXCLUSIVE) &&
894         (ProbeMode != KernelMode))
895     {
896         /* Caller is not kernel, but the object is kernel exclusive */
897         Status = STATUS_ACCESS_DENIED;
898         goto Quickie;
899     }
900 
901     /*
902      * Check if this is an object that went from 0 handles back to existence,
903      * but doesn't have an open procedure, only a close procedure. This means
904      * that it will never realize that the object is back alive, so we must
905      * fail the request.
906      */
907     if (!(ObjectHeader->HandleCount) &&
908         !(NewObject) &&
909         (ObjectType->TypeInfo.MaintainHandleCount) &&
910         !(ObjectType->TypeInfo.OpenProcedure) &&
911         (ObjectType->TypeInfo.CloseProcedure))
912     {
913         /* Fail */
914         Status = STATUS_UNSUCCESSFUL;
915         goto Quickie;
916     }
917 
918     /* Check if we're opening an existing handle */
919     if ((OpenReason == ObOpenHandle) ||
920         ((OpenReason == ObDuplicateHandle) && (AccessState)))
921     {
922         /* Validate the caller's access to this object */
923         if (!ObCheckObjectAccess(Object,
924                                  AccessState,
925                                  TRUE,
926                                  ProbeMode,
927                                  &Status))
928         {
929             /* Access was denied, so fail */
930             goto Quickie;
931         }
932     }
933     else if (OpenReason == ObCreateHandle)
934     {
935         /* Convert MAXIMUM_ALLOWED to GENERIC_ALL */
936         if (AccessState->RemainingDesiredAccess & MAXIMUM_ALLOWED)
937         {
938             /* Mask out MAXIMUM_ALLOWED and stick GENERIC_ALL instead */
939             AccessState->RemainingDesiredAccess &= ~MAXIMUM_ALLOWED;
940             AccessState->RemainingDesiredAccess |= GENERIC_ALL;
941         }
942 
943         /* Check if we have to map the GENERIC mask */
944         if (AccessState->RemainingDesiredAccess & GENERIC_ACCESS)
945         {
946             /* Map it to the correct access masks */
947             RtlMapGenericMask(&AccessState->RemainingDesiredAccess,
948                               &ObjectType->TypeInfo.GenericMapping);
949         }
950 
951         /* Check if the caller is trying to access system security */
952         if (AccessState->RemainingDesiredAccess & ACCESS_SYSTEM_SECURITY)
953         {
954             /* FIXME: TODO */
955             DPRINT1("ACCESS_SYSTEM_SECURITY not validated!\n");
956         }
957     }
958 
959     /* Check if this is an exclusive handle */
960     if (Exclusive)
961     {
962         /* Save the owner process */
963         OBJECT_HEADER_TO_QUOTA_INFO(ObjectHeader)->ExclusiveProcess = Process;
964     }
965 
966     /* Increase the handle count */
967     InterlockedIncrementSizeT(&ObjectHeader->HandleCount);
968     ProcessHandleCount = 0;
969 
970     /* Check if we have a handle database */
971     if (ObjectType->TypeInfo.MaintainHandleCount)
972     {
973         /* Increment the handle database */
974         Status = ObpIncrementHandleDataBase(ObjectHeader,
975                                             Process,
976                                             &ProcessHandleCount);
977         if (!NT_SUCCESS(Status))
978         {
979             /* FIXME: This should never happen for now */
980             DPRINT1("Unhandled case\n");
981             ASSERT(FALSE);
982             goto Quickie;
983         }
984     }
985 
986     /* Release the lock */
987     ObpReleaseObjectLock(ObjectHeader);
988 
989     /* Check if we have an open procedure */
990     Status = STATUS_SUCCESS;
991     if (ObjectType->TypeInfo.OpenProcedure)
992     {
993         /* Call it */
994         ObpCalloutStart(&CalloutIrql);
995         Status = ObjectType->TypeInfo.OpenProcedure(OpenReason,
996                                                     Process,
997                                                     Object,
998                                                     AccessState ?
999                                                     AccessState->
1000                                                     PreviouslyGrantedAccess :
1001                                                     0,
1002                                                     ProcessHandleCount);
1003         ObpCalloutEnd(CalloutIrql, "Open", ObjectType, Object);
1004 
1005         /* Check if the open procedure failed */
1006         if (!NT_SUCCESS(Status))
1007         {
1008             /* FIXME: This should never happen for now */
1009             DPRINT1("Unhandled case\n");
1010             ASSERT(FALSE);
1011             return Status;
1012         }
1013     }
1014 
1015     /* Check if this is a create operation */
1016     if (OpenReason == ObCreateHandle)
1017     {
1018         /* Check if we have creator info */
1019         CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(ObjectHeader);
1020         if (CreatorInfo)
1021         {
1022             /* We do, acquire the lock */
1023             ObpEnterObjectTypeMutex(ObjectType);
1024 
1025             /* Insert us on the list */
1026             InsertTailList(&ObjectType->TypeList, &CreatorInfo->TypeList);
1027 
1028             /* Release the lock */
1029             ObpLeaveObjectTypeMutex(ObjectType);
1030         }
1031     }
1032 
1033     /* Increase total number of handles */
1034     Total = InterlockedIncrement((PLONG)&ObjectType->TotalNumberOfHandles);
1035     if (Total > ObjectType->HighWaterNumberOfHandles)
1036     {
1037         /* Fixup count */
1038         ObjectType->HighWaterNumberOfHandles = Total;
1039     }
1040 
1041     /* Trace call and return */
1042     OBTRACE(OB_HANDLE_DEBUG,
1043             "%s - Incremented count for: %p. Reason: %lx HC PC %lx %lx\n",
1044             __FUNCTION__,
1045             Object,
1046             OpenReason,
1047             ObjectHeader->HandleCount,
1048             ObjectHeader->PointerCount);
1049     return Status;
1050 
1051 Quickie:
1052     /* Release lock and return */
1053     ObpReleaseObjectLock(ObjectHeader);
1054     return Status;
1055 }
1056 
1057 /*++
1058 * @name ObpIncrementUnnamedHandleCount
1059 *
1060 *     The ObpIncrementUnnamedHandleCount routine <FILLMEIN>
1061 *
1062 * @param Object
1063 *        <FILLMEIN>.
1064 *
1065 * @param AccessState
1066 *        <FILLMEIN>.
1067 *
1068 * @param AccessMode
1069 *        <FILLMEIN>.
1070 *
1071 * @param HandleAttributes
1072 *        <FILLMEIN>.
1073 *
1074 * @param Process
1075 *        <FILLMEIN>.
1076 *
1077 * @param OpenReason
1078 *        <FILLMEIN>.
1079 *
1080 * @return <FILLMEIN>.
1081 *
1082 * @remarks None.
1083 *
1084 *--*/
1085 NTSTATUS
1086 NTAPI
1087 ObpIncrementUnnamedHandleCount(IN PVOID Object,
1088                                IN PACCESS_MASK DesiredAccess,
1089                                IN KPROCESSOR_MODE AccessMode,
1090                                IN ULONG HandleAttributes,
1091                                IN PEPROCESS Process)
1092 {
1093     POBJECT_HEADER ObjectHeader;
1094     POBJECT_TYPE ObjectType;
1095     ULONG ProcessHandleCount;
1096     NTSTATUS Status;
1097     PEPROCESS ExclusiveProcess;
1098     BOOLEAN Exclusive = FALSE, NewObject;
1099     POBJECT_HEADER_CREATOR_INFO CreatorInfo;
1100     KIRQL CalloutIrql;
1101     ULONG Total;
1102 
1103     /* Get the object header and type */
1104     ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
1105     ObjectType = ObjectHeader->Type;
1106     OBTRACE(OB_HANDLE_DEBUG,
1107             "%s - Incrementing count for: %p. UNNAMED. HC PC %lx %lx\n",
1108             __FUNCTION__,
1109             Object,
1110             ObjectHeader->HandleCount,
1111             ObjectHeader->PointerCount);
1112 
1113     /* Lock the object */
1114     ObpAcquireObjectLock(ObjectHeader);
1115 
1116     /* Charge quota and remove the creator info flag */
1117     Status = ObpChargeQuotaForObject(ObjectHeader, ObjectType, &NewObject);
1118     if (!NT_SUCCESS(Status)) return Status;
1119 
1120     /* Check if the open is exclusive */
1121     if (HandleAttributes & OBJ_EXCLUSIVE)
1122     {
1123         /* Check if the object allows this, or if the inherit flag was given */
1124         if ((HandleAttributes & OBJ_INHERIT) ||
1125             !(ObjectHeader->Flags & OB_FLAG_EXCLUSIVE))
1126         {
1127             /* Incorrect attempt */
1128             Status = STATUS_INVALID_PARAMETER;
1129             goto Quickie;
1130         }
1131 
1132         /* Check if we have access to it */
1133         ExclusiveProcess = OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader);
1134         if ((!(ExclusiveProcess) && (ObjectHeader->HandleCount)) ||
1135             ((ExclusiveProcess) && (ExclusiveProcess != PsGetCurrentProcess())))
1136         {
1137             /* This isn't the right process */
1138             Status = STATUS_ACCESS_DENIED;
1139             goto Quickie;
1140         }
1141 
1142         /* Now you got exclusive access */
1143         Exclusive = TRUE;
1144     }
1145     else if ((ObjectHeader->Flags & OB_FLAG_EXCLUSIVE) &&
1146              (OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader)))
1147     {
1148         /* Caller didn't want exclusive access, but the object is exclusive */
1149         Status = STATUS_ACCESS_DENIED;
1150         goto Quickie;
1151     }
1152 
1153     /*
1154      * Check if this is an object that went from 0 handles back to existence,
1155      * but doesn't have an open procedure, only a close procedure. This means
1156      * that it will never realize that the object is back alive, so we must
1157      * fail the request.
1158      */
1159     if (!(ObjectHeader->HandleCount) &&
1160         !(NewObject) &&
1161         (ObjectType->TypeInfo.MaintainHandleCount) &&
1162         !(ObjectType->TypeInfo.OpenProcedure) &&
1163         (ObjectType->TypeInfo.CloseProcedure))
1164     {
1165         /* Fail */
1166         Status = STATUS_UNSUCCESSFUL;
1167         goto Quickie;
1168     }
1169 
1170     /* Convert MAXIMUM_ALLOWED to GENERIC_ALL */
1171     if (*DesiredAccess & MAXIMUM_ALLOWED)
1172     {
1173         /* Mask out MAXIMUM_ALLOWED and stick GENERIC_ALL instead */
1174         *DesiredAccess &= ~MAXIMUM_ALLOWED;
1175         *DesiredAccess |= GENERIC_ALL;
1176     }
1177 
1178     /* Check if we have to map the GENERIC mask */
1179     if (*DesiredAccess & GENERIC_ACCESS)
1180     {
1181         /* Map it to the correct access masks */
1182         RtlMapGenericMask(DesiredAccess,
1183                           &ObjectType->TypeInfo.GenericMapping);
1184     }
1185 
1186     /* Check if this is an exclusive handle */
1187     if (Exclusive)
1188     {
1189         /* Save the owner process */
1190         OBJECT_HEADER_TO_QUOTA_INFO(ObjectHeader)->ExclusiveProcess = Process;
1191     }
1192 
1193     /* Increase the handle count */
1194     InterlockedIncrementSizeT(&ObjectHeader->HandleCount);
1195     ProcessHandleCount = 0;
1196 
1197     /* Check if we have a handle database */
1198     if (ObjectType->TypeInfo.MaintainHandleCount)
1199     {
1200         /* Increment the handle database */
1201         Status = ObpIncrementHandleDataBase(ObjectHeader,
1202                                             Process,
1203                                             &ProcessHandleCount);
1204         if (!NT_SUCCESS(Status))
1205         {
1206             /* FIXME: This should never happen for now */
1207             DPRINT1("Unhandled case\n");
1208             ASSERT(FALSE);
1209             goto Quickie;
1210         }
1211     }
1212 
1213     /* Release the lock */
1214     ObpReleaseObjectLock(ObjectHeader);
1215 
1216     /* Check if we have an open procedure */
1217     Status = STATUS_SUCCESS;
1218     if (ObjectType->TypeInfo.OpenProcedure)
1219     {
1220         /* Call it */
1221         ObpCalloutStart(&CalloutIrql);
1222         Status = ObjectType->TypeInfo.OpenProcedure(ObCreateHandle,
1223                                                     Process,
1224                                                     Object,
1225                                                     *DesiredAccess,
1226                                                     ProcessHandleCount);
1227         ObpCalloutEnd(CalloutIrql, "Open", ObjectType, Object);
1228 
1229         /* Check if the open procedure failed */
1230         if (!NT_SUCCESS(Status))
1231         {
1232             /* FIXME: This should never happen for now */
1233             DPRINT1("Unhandled case\n");
1234             ASSERT(FALSE);
1235             return Status;
1236         }
1237     }
1238 
1239     /* Check if we have creator info */
1240     CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(ObjectHeader);
1241     if (CreatorInfo)
1242     {
1243         /* We do, acquire the lock */
1244         ObpEnterObjectTypeMutex(ObjectType);
1245 
1246         /* Insert us on the list */
1247         InsertTailList(&ObjectType->TypeList, &CreatorInfo->TypeList);
1248 
1249         /* Release the lock */
1250         ObpLeaveObjectTypeMutex(ObjectType);
1251     }
1252 
1253     /* Increase total number of handles */
1254     Total = InterlockedIncrement((PLONG)&ObjectType->TotalNumberOfHandles);
1255     if (Total > ObjectType->HighWaterNumberOfHandles)
1256     {
1257         /* Fixup count */
1258         ObjectType->HighWaterNumberOfHandles = Total;
1259     }
1260 
1261     /* Trace call and return */
1262     OBTRACE(OB_HANDLE_DEBUG,
1263             "%s - Incremented count for: %p. UNNAMED HC PC %lx %lx\n",
1264             __FUNCTION__,
1265             Object,
1266             ObjectHeader->HandleCount,
1267             ObjectHeader->PointerCount);
1268     return Status;
1269 
1270 Quickie:
1271     /* Release lock and return */
1272     ObpReleaseObjectLock(ObjectHeader);
1273     return Status;
1274 }
1275 
1276 /*++
1277 * @name ObpCreateUnnamedHandle
1278 *
1279 *     The ObpCreateUnnamedHandle routine <FILLMEIN>
1280 *
1281 * @param Object
1282 *        <FILLMEIN>.
1283 *
1284 * @param DesiredAccess
1285 *        <FILLMEIN>.
1286 *
1287 * @param AdditionalReferences
1288 *        <FILLMEIN>.
1289 *
1290 * @param HandleAttributes
1291 *        <FILLMEIN>.
1292 *
1293 * @param AccessMode
1294 *        <FILLMEIN>.
1295 *
1296 * @param ReturnedObject
1297 *        <FILLMEIN>.
1298 *
1299 * @param ReturnedHandle
1300 *        <FILLMEIN>.
1301 *
1302 * @return <FILLMEIN>.
1303 *
1304 * @remarks None.
1305 *
1306 *--*/
1307 NTSTATUS
1308 NTAPI
1309 ObpCreateUnnamedHandle(IN PVOID Object,
1310                        IN ACCESS_MASK DesiredAccess,
1311                        IN ULONG AdditionalReferences,
1312                        IN ULONG HandleAttributes,
1313                        IN KPROCESSOR_MODE AccessMode,
1314                        OUT PVOID *ReturnedObject,
1315                        OUT PHANDLE ReturnedHandle)
1316 {
1317     HANDLE_TABLE_ENTRY NewEntry;
1318     POBJECT_HEADER ObjectHeader;
1319     HANDLE Handle;
1320     KAPC_STATE ApcState;
1321     BOOLEAN AttachedToProcess = FALSE, KernelHandle = FALSE;
1322     PVOID HandleTable;
1323     NTSTATUS Status;
1324     ACCESS_MASK GrantedAccess;
1325     POBJECT_TYPE ObjectType;
1326     PAGED_CODE();
1327 
1328     /* Get the object header and type */
1329     ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
1330     ObjectType = ObjectHeader->Type;
1331     OBTRACE(OB_HANDLE_DEBUG,
1332             "%s - Creating handle for: %p. UNNAMED. HC PC %lx %lx\n",
1333             __FUNCTION__,
1334             Object,
1335             ObjectHeader->HandleCount,
1336             ObjectHeader->PointerCount);
1337 
1338     /* Save the object header */
1339     NewEntry.Object = ObjectHeader;
1340 
1341     /* Mask out the internal attributes */
1342     NewEntry.ObAttributes |= HandleAttributes & OBJ_HANDLE_ATTRIBUTES;
1343 
1344     /* Check if this is a kernel handle */
1345     if (HandleAttributes & OBJ_KERNEL_HANDLE)
1346     {
1347         /* Set the handle table */
1348         HandleTable = ObpKernelHandleTable;
1349         KernelHandle = TRUE;
1350 
1351         /* Check if we're not in the system process */
1352         if (PsGetCurrentProcess() != PsInitialSystemProcess)
1353         {
1354             /* Attach to the system process */
1355             KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
1356             AttachedToProcess = TRUE;
1357         }
1358     }
1359     else
1360     {
1361         /* Get the current handle table */
1362         HandleTable = PsGetCurrentProcess()->ObjectTable;
1363     }
1364 
1365     /* Increment the handle count */
1366     Status = ObpIncrementUnnamedHandleCount(Object,
1367                                             &DesiredAccess,
1368                                             AccessMode,
1369                                             HandleAttributes,
1370                                             PsGetCurrentProcess());
1371     if (!NT_SUCCESS(Status))
1372     {
1373         /*
1374          * We failed (meaning security failure, according to NT Internals)
1375          * detach and return
1376          */
1377         if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1378         return Status;
1379     }
1380 
1381     /* Remove what's not in the valid access mask */
1382     GrantedAccess = DesiredAccess & (ObjectType->TypeInfo.ValidAccessMask |
1383                                      ACCESS_SYSTEM_SECURITY);
1384 
1385     /* Handle extra references */
1386     if (AdditionalReferences)
1387     {
1388         /* Add them to the header */
1389         InterlockedExchangeAddSizeT(&ObjectHeader->PointerCount,
1390                                     AdditionalReferences);
1391     }
1392 
1393     /* Save the access mask */
1394     NewEntry.GrantedAccess = GrantedAccess;
1395 
1396     /*
1397      * Create the actual handle. We'll need to do this *after* calling
1398      * ObpIncrementHandleCount to make sure that Object Security is valid
1399      * (specified in Gl00my documentation on Ob)
1400      */
1401     OBTRACE(OB_HANDLE_DEBUG,
1402             "%s - Handle Properties: [%p-%lx-%lx]\n",
1403             __FUNCTION__,
1404             NewEntry.Object, NewEntry.ObAttributes & 3, NewEntry.GrantedAccess);
1405     Handle = ExCreateHandle(HandleTable, &NewEntry);
1406 
1407     /* Make sure we got a handle */
1408     if (Handle)
1409     {
1410         /* Check if this was a kernel handle */
1411         if (KernelHandle) Handle = ObMarkHandleAsKernelHandle(Handle);
1412 
1413         /* Return handle and object */
1414         *ReturnedHandle = Handle;
1415 
1416         /* Return the new object only if caller wanted it biased */
1417         if ((AdditionalReferences) && (ReturnedObject))
1418         {
1419             /* Return it */
1420             *ReturnedObject = Object;
1421         }
1422 
1423         /* Detach if needed */
1424         if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1425 
1426         /* Trace and return */
1427         OBTRACE(OB_HANDLE_DEBUG,
1428                 "%s - Returning Handle: %p HC PC %lx %lx\n",
1429                 __FUNCTION__,
1430                 Handle,
1431                 ObjectHeader->HandleCount,
1432                 ObjectHeader->PointerCount);
1433         return STATUS_SUCCESS;
1434     }
1435 
1436     /* Handle extra references */
1437     if (AdditionalReferences)
1438     {
1439         /* Dereference it as many times as required */
1440         InterlockedExchangeAddSizeT(&ObjectHeader->PointerCount,
1441                                     -(LONG)AdditionalReferences);
1442     }
1443 
1444     /* Decrement the handle count and detach */
1445     ObpDecrementHandleCount(&ObjectHeader->Body,
1446                             PsGetCurrentProcess(),
1447                             GrantedAccess,
1448                             ObjectType);
1449 
1450     /* Detach and fail */
1451     if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1452     return STATUS_INSUFFICIENT_RESOURCES;
1453 }
1454 
1455 /*++
1456 * @name ObpCreateHandle
1457 *
1458 *     The ObpCreateHandle routine <FILLMEIN>
1459 *
1460 * @param OpenReason
1461 *        <FILLMEIN>.
1462 *
1463 * @param Object
1464 *        <FILLMEIN>.
1465 *
1466 * @param Type
1467 *        <FILLMEIN>.
1468 *
1469 * @param AccessState
1470 *        <FILLMEIN>.
1471 *
1472 * @param AdditionalReferences
1473 *        <FILLMEIN>.
1474 *
1475 * @param HandleAttributes
1476 *        <FILLMEIN>.
1477 *
1478 * @param AccessMode
1479 *        <FILLMEIN>.
1480 *
1481 * @param ReturnedObject
1482 *        <FILLMEIN>.
1483 *
1484 * @param ReturnedHandle
1485 *        <FILLMEIN>.
1486 *
1487 * @return <FILLMEIN>.
1488 *
1489 * @remarks Cleans up the Lookup Context on return.
1490 *
1491 *--*/
1492 NTSTATUS
1493 NTAPI
1494 ObpCreateHandle(IN OB_OPEN_REASON OpenReason,
1495                 IN PVOID Object,
1496                 IN POBJECT_TYPE Type OPTIONAL,
1497                 IN PACCESS_STATE AccessState,
1498                 IN ULONG AdditionalReferences,
1499                 IN ULONG HandleAttributes,
1500                 IN POBP_LOOKUP_CONTEXT Context,
1501                 IN KPROCESSOR_MODE AccessMode,
1502                 OUT PVOID *ReturnedObject,
1503                 OUT PHANDLE ReturnedHandle)
1504 {
1505     HANDLE_TABLE_ENTRY NewEntry;
1506     POBJECT_HEADER ObjectHeader;
1507     HANDLE Handle;
1508     KAPC_STATE ApcState;
1509     BOOLEAN AttachedToProcess = FALSE, KernelHandle = FALSE;
1510     POBJECT_TYPE ObjectType;
1511     PVOID HandleTable;
1512     NTSTATUS Status;
1513     ACCESS_MASK DesiredAccess, GrantedAccess;
1514     PAUX_ACCESS_DATA AuxData;
1515     PAGED_CODE();
1516 
1517     /* Get the object header and type */
1518     ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
1519     ObjectType = ObjectHeader->Type;
1520     OBTRACE(OB_HANDLE_DEBUG,
1521             "%s - Creating handle for: %p. Reason: %lx. HC PC %lx %lx\n",
1522             __FUNCTION__,
1523             Object,
1524             OpenReason,
1525             ObjectHeader->HandleCount,
1526             ObjectHeader->PointerCount);
1527 
1528     /* Check if the types match */
1529     if ((Type) && (ObjectType != Type))
1530     {
1531         /* They don't, cleanup */
1532         if (Context) ObpReleaseLookupContext(Context);
1533         return STATUS_OBJECT_TYPE_MISMATCH;
1534     }
1535 
1536     /* Save the object header */
1537     NewEntry.Object = ObjectHeader;
1538 
1539     /* Check if this is a kernel handle */
1540     if (HandleAttributes & OBJ_KERNEL_HANDLE)
1541     {
1542         /* Set the handle table */
1543         HandleTable = ObpKernelHandleTable;
1544         KernelHandle = TRUE;
1545 
1546         /* Check if we're not in the system process */
1547         if (PsGetCurrentProcess() != PsInitialSystemProcess)
1548         {
1549             /* Attach to the system process */
1550             KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
1551             AttachedToProcess = TRUE;
1552         }
1553     }
1554     else
1555     {
1556         /* Get the current handle table */
1557         HandleTable = PsGetCurrentProcess()->ObjectTable;
1558     }
1559 
1560     /* Increment the handle count */
1561     Status = ObpIncrementHandleCount(Object,
1562                                      AccessState,
1563                                      AccessMode,
1564                                      HandleAttributes,
1565                                      PsGetCurrentProcess(),
1566                                      OpenReason);
1567     if (!NT_SUCCESS(Status))
1568     {
1569         /*
1570          * We failed (meaning security failure, according to NT Internals)
1571          * detach and return
1572          */
1573         if (Context) ObpReleaseLookupContext(Context);
1574         if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1575         return Status;
1576     }
1577 
1578     /* Check if we are doing audits on close */
1579     if (AccessState->GenerateOnClose)
1580     {
1581         /* Force the attribute on */
1582         HandleAttributes |= OBJ_AUDIT_OBJECT_CLOSE;
1583     }
1584 
1585     /* Mask out the internal attributes */
1586     NewEntry.ObAttributes |= (HandleAttributes & OBJ_HANDLE_ATTRIBUTES);
1587 
1588     /* Get the original desired access */
1589     DesiredAccess = AccessState->RemainingDesiredAccess |
1590                     AccessState->PreviouslyGrantedAccess;
1591 
1592     /* Remove what's not in the valid access mask */
1593     GrantedAccess = DesiredAccess & (ObjectType->TypeInfo.ValidAccessMask |
1594                                      ACCESS_SYSTEM_SECURITY);
1595 
1596     /* Update the value in the access state */
1597     AccessState->PreviouslyGrantedAccess = GrantedAccess;
1598 
1599     /* Get the auxiliary data */
1600     AuxData = AccessState->AuxData;
1601 
1602     /* Handle extra references */
1603     if (AdditionalReferences)
1604     {
1605         /* Add them to the header */
1606         InterlockedExchangeAddSizeT(&ObjectHeader->PointerCount,
1607                                     AdditionalReferences);
1608     }
1609 
1610     /* Now we can release the object */
1611     if (Context) ObpReleaseLookupContext(Context);
1612 
1613     /* Save the access mask */
1614     NewEntry.GrantedAccess = GrantedAccess;
1615 
1616     /*
1617      * Create the actual handle. We'll need to do this *after* calling
1618      * ObpIncrementHandleCount to make sure that Object Security is valid
1619      * (specified in Gl00my documentation on Ob)
1620      */
1621     OBTRACE(OB_HANDLE_DEBUG,
1622             "%s - Handle Properties: [%p-%lx-%lx]\n",
1623             __FUNCTION__,
1624             NewEntry.Object, NewEntry.ObAttributes & 3, NewEntry.GrantedAccess);
1625     Handle = ExCreateHandle(HandleTable, &NewEntry);
1626 
1627     /* Make sure we got a handle */
1628     if (Handle)
1629     {
1630         /* Check if this was a kernel handle */
1631         if (KernelHandle) Handle = ObMarkHandleAsKernelHandle(Handle);
1632 
1633         /* Return it */
1634         *ReturnedHandle = Handle;
1635 
1636         /* Check if we need to generate on audit */
1637         if (AccessState->GenerateAudit)
1638         {
1639             /* Audit the handle creation */
1640             //SeAuditHandleCreation(AccessState, Handle);
1641         }
1642 
1643         /* Check if this was a create */
1644         if (OpenReason == ObCreateHandle)
1645         {
1646             /* Check if we need to audit the privileges */
1647             if ((AuxData->PrivilegeSet) &&
1648                 (AuxData->PrivilegeSet->PrivilegeCount))
1649             {
1650                 /* Do the audit */
1651 #if 0
1652                 SePrivilegeObjectAuditAlarm(Handle,
1653                                             &AccessState->
1654                                             SubjectSecurityContext,
1655                                             GrantedAccess,
1656                                             AuxData->PrivilegeSet,
1657                                             TRUE,
1658                                             ExGetPreviousMode());
1659 #endif
1660             }
1661         }
1662 
1663         /* Return the new object only if caller wanted it biased */
1664         if ((AdditionalReferences) && (ReturnedObject))
1665         {
1666             /* Return it */
1667             *ReturnedObject = Object;
1668         }
1669 
1670         /* Detach if needed */
1671         if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1672 
1673         /* Trace and return */
1674         OBTRACE(OB_HANDLE_DEBUG,
1675                 "%s - Returning Handle: %p HC PC %lx %lx\n",
1676                 __FUNCTION__,
1677                 Handle,
1678                 ObjectHeader->HandleCount,
1679                 ObjectHeader->PointerCount);
1680         return STATUS_SUCCESS;
1681     }
1682 
1683     /* Decrement the handle count and detach */
1684     ObpDecrementHandleCount(&ObjectHeader->Body,
1685                             PsGetCurrentProcess(),
1686                             GrantedAccess,
1687                             ObjectType);
1688 
1689     /* Handle extra references */
1690     if (AdditionalReferences)
1691     {
1692         /* Check how many extra references were added */
1693         if (AdditionalReferences > 1)
1694         {
1695             /* Dereference it many times */
1696             InterlockedExchangeAddSizeT(&ObjectHeader->PointerCount,
1697                                         -(LONG)(AdditionalReferences - 1));
1698         }
1699 
1700         /* Dereference the object one last time */
1701         ObDereferenceObject(Object);
1702     }
1703 
1704     /* Detach if necessary and fail */
1705     if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1706     return STATUS_INSUFFICIENT_RESOURCES;
1707 }
1708 
1709 /*++
1710 * @name ObpCloseHandle
1711 *
1712 *     The ObpCloseHandle routine <FILLMEIN>
1713 *
1714 * @param Handle
1715 *        <FILLMEIN>.
1716 *
1717 * @param AccessMode
1718 *        <FILLMEIN>.
1719 *
1720 * @return <FILLMEIN>.
1721 *
1722 * @remarks None.
1723 *
1724 *--*/
1725 NTSTATUS
1726 NTAPI
1727 ObpCloseHandle(IN HANDLE Handle,
1728                IN KPROCESSOR_MODE AccessMode)
1729 {
1730     PVOID HandleTable;
1731     BOOLEAN AttachedToProcess = FALSE;
1732     KAPC_STATE ApcState;
1733     PHANDLE_TABLE_ENTRY HandleTableEntry;
1734     NTSTATUS Status;
1735     PEPROCESS Process = PsGetCurrentProcess();
1736     PAGED_CODE();
1737     OBTRACE(OB_HANDLE_DEBUG,
1738             "%s - Closing handle: %p\n", __FUNCTION__, Handle);
1739 
1740     if (AccessMode == KernelMode && Handle == (HANDLE)-1)
1741         return STATUS_INVALID_HANDLE;
1742 
1743     /* Check if we're dealing with a kernel handle */
1744     if (ObpIsKernelHandle(Handle, AccessMode))
1745     {
1746         /* Use the kernel table and convert the handle */
1747         HandleTable = ObpKernelHandleTable;
1748         Handle = ObKernelHandleToHandle(Handle);
1749 
1750         /* Check if we're not in the system process */
1751         if (Process != PsInitialSystemProcess)
1752         {
1753             /* Attach to the system process */
1754             KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
1755             AttachedToProcess = TRUE;
1756         }
1757     }
1758     else
1759     {
1760         /* Use the process's handle table */
1761         HandleTable = Process->ObjectTable;
1762     }
1763 
1764     /* Enter a critical region to protect handle access */
1765     KeEnterCriticalRegion();
1766 
1767     /* Get the handle entry */
1768     HandleTableEntry = ExMapHandleToPointer(HandleTable, Handle);
1769     if (HandleTableEntry)
1770     {
1771         /* Now close the entry */
1772         Status = ObpCloseHandleTableEntry(HandleTable,
1773                                           HandleTableEntry,
1774                                           Handle,
1775                                           AccessMode,
1776                                           FALSE);
1777 
1778         /* We can quit the critical region now */
1779         KeLeaveCriticalRegion();
1780 
1781         /* Detach and return success */
1782         if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1783     }
1784     else
1785     {
1786         /* We failed, quit the critical region */
1787         KeLeaveCriticalRegion();
1788 
1789         /* Detach */
1790         if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1791 
1792         /* Check if we have a valid handle that's not the process or thread */
1793         if ((Handle) &&
1794             (Handle != NtCurrentProcess()) &&
1795             (Handle != NtCurrentThread()))
1796         {
1797             /* Check if we came from user mode */
1798             if (AccessMode != KernelMode)
1799             {
1800                 /* Check if we have no debug port */
1801                 if (Process->DebugPort)
1802                 {
1803                     /* Make sure we're not attached */
1804                     if (!KeIsAttachedProcess())
1805                     {
1806                         /* Raise an exception */
1807                         return KeRaiseUserException(STATUS_INVALID_HANDLE);
1808                     }
1809                 }
1810             }
1811             else
1812             {
1813                 /* This is kernel mode. Check if we're exiting */
1814                 if (!(PsIsThreadTerminating(PsGetCurrentThread())) &&
1815                     (Process->Peb))
1816                 {
1817                     /* Check if the debugger is enabled */
1818                     if (KdDebuggerEnabled)
1819                     {
1820                         /* Bugcheck */
1821                         KeBugCheckEx(INVALID_KERNEL_HANDLE, (ULONG_PTR)Handle, 1, 0, 0);
1822                     }
1823                 }
1824             }
1825         }
1826 
1827         /* Set invalid status */
1828         Status = STATUS_INVALID_HANDLE;
1829     }
1830 
1831     /* Return status */
1832     OBTRACE(OB_HANDLE_DEBUG,
1833             "%s - Closed handle: %p S: %lx\n",
1834             __FUNCTION__, Handle, Status);
1835     return Status;
1836 }
1837 
1838 /*++
1839 * @name ObpSetHandleAttributes
1840 *
1841 *     The ObpSetHandleAttributes routine <FILLMEIN>
1842 *
1843 * @param HandleTableEntry
1844 *        <FILLMEIN>.
1845 *
1846 * @param Context
1847 *        <FILLMEIN>.
1848 *
1849 * @return <FILLMEIN>.
1850 *
1851 * @remarks None.
1852 *
1853 *--*/
1854 BOOLEAN
1855 NTAPI
1856 ObpSetHandleAttributes(IN OUT PHANDLE_TABLE_ENTRY HandleTableEntry,
1857                        IN ULONG_PTR Context)
1858 {
1859     POBP_SET_HANDLE_ATTRIBUTES_CONTEXT SetHandleInfo = (PVOID)Context;
1860     POBJECT_HEADER ObjectHeader = ObpGetHandleObject(HandleTableEntry);
1861 
1862     /* Check if making the handle inheritable */
1863     if (SetHandleInfo->Information.Inherit)
1864     {
1865         /* Check if inheriting is not supported for this object */
1866         if (ObjectHeader->Type->TypeInfo.InvalidAttributes & OBJ_INHERIT)
1867         {
1868             /* Fail without changing anything */
1869             return FALSE;
1870         }
1871 
1872         /* Set the flag */
1873         HandleTableEntry->ObAttributes |= OBJ_INHERIT;
1874     }
1875     else
1876     {
1877         /* Otherwise this implies we're removing the flag */
1878         HandleTableEntry->ObAttributes &= ~OBJ_INHERIT;
1879     }
1880 
1881     /* Check if making the handle protected */
1882     if (SetHandleInfo->Information.ProtectFromClose)
1883     {
1884         /* Set the flag */
1885         HandleTableEntry->GrantedAccess |= ObpAccessProtectCloseBit;
1886     }
1887     else
1888     {
1889         /* Otherwise, remove it */
1890         HandleTableEntry->GrantedAccess &= ~ObpAccessProtectCloseBit;
1891     }
1892 
1893     /* Return success */
1894     return TRUE;
1895 }
1896 
1897 /*++
1898 * @name ObpCloseHandleCallback
1899 *
1900 *     The ObpCloseHandleCallback routine <FILLMEIN>
1901 *
1902 * @param HandleTable
1903 *        <FILLMEIN>.
1904 *
1905 * @param Object
1906 *        <FILLMEIN>.
1907 *
1908 * @param GrantedAccess
1909 *        <FILLMEIN>.
1910 *
1911 * @param Context
1912 *        <FILLMEIN>.
1913 *
1914 * @return <FILLMEIN>.
1915 *
1916 * @remarks None.
1917 *
1918 *--*/
1919 BOOLEAN
1920 NTAPI
1921 ObpCloseHandleCallback(IN PHANDLE_TABLE_ENTRY HandleTableEntry,
1922                        IN HANDLE Handle,
1923                        IN PVOID Context)
1924 {
1925     POBP_CLOSE_HANDLE_CONTEXT CloseContext = (POBP_CLOSE_HANDLE_CONTEXT)Context;
1926 
1927     /* Simply decrement the handle count */
1928     ObpCloseHandleTableEntry(CloseContext->HandleTable,
1929                              HandleTableEntry,
1930                              Handle,
1931                              CloseContext->AccessMode,
1932                              TRUE);
1933     return TRUE;
1934 }
1935 
1936 /*++
1937 * @name ObpDuplicateHandleCallback
1938 *
1939 *     The ObpDuplicateHandleCallback routine <FILLMEIN>
1940 *
1941 * @param HandleTable
1942 *        <FILLMEIN>.
1943 *
1944 * @param HandleTableEntry
1945 *        <FILLMEIN>.
1946 *
1947 * @param Context
1948 *        <FILLMEIN>.
1949 *
1950 * @return <FILLMEIN>.
1951 *
1952 * @remarks None.
1953 *
1954 *--*/
1955 BOOLEAN
1956 NTAPI
1957 ObpDuplicateHandleCallback(IN PEPROCESS Process,
1958                            IN PHANDLE_TABLE HandleTable,
1959                            IN PHANDLE_TABLE_ENTRY OldEntry,
1960                            IN PHANDLE_TABLE_ENTRY HandleTableEntry)
1961 {
1962     POBJECT_HEADER ObjectHeader;
1963     BOOLEAN Ret = FALSE;
1964     ACCESS_STATE AccessState;
1965     NTSTATUS Status;
1966     PAGED_CODE();
1967 
1968     /* Make sure that the handle is inheritable */
1969     Ret = (HandleTableEntry->ObAttributes & OBJ_INHERIT) != 0;
1970     if (Ret)
1971     {
1972         /* Get the object header */
1973         ObjectHeader = ObpGetHandleObject(HandleTableEntry);
1974 
1975         /* Increment the pointer count */
1976         InterlockedIncrementSizeT(&ObjectHeader->PointerCount);
1977 
1978         /* Release the handle lock */
1979         ExUnlockHandleTableEntry(HandleTable, OldEntry);
1980 
1981         /* Setup the access state */
1982         AccessState.PreviouslyGrantedAccess = HandleTableEntry->GrantedAccess;
1983 
1984         /* Call the shared routine for incrementing handles */
1985         Status = ObpIncrementHandleCount(&ObjectHeader->Body,
1986                                          &AccessState,
1987                                          KernelMode,
1988                                          HandleTableEntry->ObAttributes & OBJ_HANDLE_ATTRIBUTES,
1989                                          Process,
1990                                          ObInheritHandle);
1991         if (!NT_SUCCESS(Status))
1992         {
1993             /* Return failure */
1994             ObDereferenceObject(&ObjectHeader->Body);
1995             Ret = FALSE;
1996         }
1997     }
1998     else
1999     {
2000         /* Release the handle lock */
2001         ExUnlockHandleTableEntry(HandleTable, OldEntry);
2002     }
2003 
2004     /* Return duplication result */
2005     return Ret;
2006 }
2007 
2008 /*++
2009 * @name ObClearProcessHandleTable
2010 *
2011 *     The ObClearProcessHandleTable routine clears the handle table
2012 *     of the given process.
2013 *
2014 * @param Process
2015 *        The process of which the handle table should be cleared.
2016 *
2017 * @return None.
2018 *
2019 * @remarks None.
2020 *
2021 *--*/
2022 VOID
2023 NTAPI
2024 ObClearProcessHandleTable(IN PEPROCESS Process)
2025 {
2026     PHANDLE_TABLE HandleTable;
2027     OBP_CLOSE_HANDLE_CONTEXT Context;
2028     KAPC_STATE ApcState;
2029     BOOLEAN AttachedToProcess = FALSE;
2030 
2031     ASSERT(Process);
2032 
2033     /* Ensure the handle table doesn't go away while we use it */
2034     HandleTable = ObReferenceProcessHandleTable(Process);
2035     if (!HandleTable) return;
2036 
2037     /* Attach to the current process if needed */
2038     if (PsGetCurrentProcess() != Process)
2039     {
2040         KeStackAttachProcess(&Process->Pcb, &ApcState);
2041         AttachedToProcess = TRUE;
2042     }
2043 
2044     /* Enter a critical region */
2045     KeEnterCriticalRegion();
2046 
2047     /* Fill out the context */
2048     Context.AccessMode = UserMode;
2049     Context.HandleTable = HandleTable;
2050 
2051     /* Sweep the handle table to close all handles */
2052     ExSweepHandleTable(HandleTable,
2053                        ObpCloseHandleCallback,
2054                        &Context);
2055 
2056     /* Leave the critical region */
2057     KeLeaveCriticalRegion();
2058 
2059     /* Detach if needed */
2060     if (AttachedToProcess)
2061         KeUnstackDetachProcess(&ApcState);
2062 
2063     /* Let the handle table go */
2064     ObDereferenceProcessHandleTable(Process);
2065 }
2066 
2067 /*++
2068 * @name ObInitProcess
2069 *
2070 *     The ObInitProcess routine initializes the handle table for the process
2071 *     to be initialized, by either creating a new one or duplicating it from
2072 *     the parent process.
2073 *
2074 * @param Parent
2075 *        A parent process (optional).
2076 *
2077 * @param Process
2078 *        The process to initialize.
2079 *
2080 * @return Success or failure.
2081 *
2082 * @remarks None.
2083 *
2084 *--*/
2085 NTSTATUS
2086 NTAPI
2087 ObInitProcess(IN PEPROCESS Parent OPTIONAL,
2088               IN PEPROCESS Process)
2089 {
2090     PHANDLE_TABLE ParentTable, ObjectTable;
2091 
2092     /* Check for a parent */
2093     if (Parent)
2094     {
2095         /* Reference the parent's table */
2096         ParentTable = ObReferenceProcessHandleTable(Parent);
2097         if (!ParentTable) return STATUS_PROCESS_IS_TERMINATING;
2098 
2099         /* Duplicate it */
2100         ObjectTable = ExDupHandleTable(Process,
2101                                        ParentTable,
2102                                        ObpDuplicateHandleCallback,
2103                                        OBJ_INHERIT);
2104     }
2105     else
2106     {
2107         /* Otherwise just create a new table */
2108         ParentTable = NULL;
2109         ObjectTable = ExCreateHandleTable(Process);
2110     }
2111 
2112     /* Make sure we have a table */
2113     if (ObjectTable)
2114     {
2115         /* Associate it */
2116         Process->ObjectTable = ObjectTable;
2117 
2118         /* Check for auditing */
2119         if (SeDetailedAuditingWithToken(NULL))
2120         {
2121             /* FIXME: TODO */
2122             DPRINT1("Need auditing!\n");
2123         }
2124 
2125         /* Get rid of the old table now */
2126         if (ParentTable) ObDereferenceProcessHandleTable(Parent);
2127 
2128         /* We are done */
2129         return STATUS_SUCCESS;
2130     }
2131     else
2132     {
2133         /* Fail */
2134         Process->ObjectTable = NULL;
2135         if (ParentTable) ObDereferenceProcessHandleTable(Parent);
2136         return STATUS_INSUFFICIENT_RESOURCES;
2137     }
2138 }
2139 
2140 /*++
2141 * @name ObKillProcess
2142 *
2143 *     The ObKillProcess routine performs rundown operations on the process,
2144 *     then clears and destroys its handle table.
2145 *
2146 * @param Process
2147 *        The process to be killed.
2148 *
2149 * @return None.
2150 *
2151 * @remarks Called by the Object Manager cleanup code (kernel)
2152 *          when a process is to be destroyed.
2153 *
2154 *--*/
2155 VOID
2156 NTAPI
2157 ObKillProcess(IN PEPROCESS Process)
2158 {
2159     PHANDLE_TABLE HandleTable;
2160     OBP_CLOSE_HANDLE_CONTEXT Context;
2161     BOOLEAN HardErrors;
2162     PAGED_CODE();
2163 
2164     /* Wait for process rundown and then complete it */
2165     ExWaitForRundownProtectionRelease(&Process->RundownProtect);
2166     ExRundownCompleted(&Process->RundownProtect);
2167 
2168     /* Get the object table */
2169     HandleTable = Process->ObjectTable;
2170     if (!HandleTable) return;
2171 
2172     /* Disable hard errors while we close handles */
2173     HardErrors = IoSetThreadHardErrorMode(FALSE);
2174 
2175     /* Enter a critical region */
2176     KeEnterCriticalRegion();
2177 
2178     /* Fill out the context */
2179     Context.AccessMode = KernelMode;
2180     Context.HandleTable = HandleTable;
2181 
2182     /* Sweep the handle table to close all handles */
2183     ExSweepHandleTable(HandleTable,
2184                        ObpCloseHandleCallback,
2185                        &Context);
2186     ASSERT(HandleTable->HandleCount == 0);
2187 
2188     /* Leave the critical region */
2189     KeLeaveCriticalRegion();
2190 
2191     /* Re-enable hard errors */
2192     IoSetThreadHardErrorMode(HardErrors);
2193 
2194     /* Destroy the object table */
2195     Process->ObjectTable = NULL;
2196     ExDestroyHandleTable(HandleTable, NULL);
2197 }
2198 
2199 NTSTATUS
2200 NTAPI
2201 ObDuplicateObject(IN PEPROCESS SourceProcess,
2202                   IN HANDLE SourceHandle,
2203                   IN PEPROCESS TargetProcess OPTIONAL,
2204                   IN PHANDLE TargetHandle OPTIONAL,
2205                   IN ACCESS_MASK DesiredAccess,
2206                   IN ULONG HandleAttributes,
2207                   IN ULONG Options,
2208                   IN KPROCESSOR_MODE PreviousMode)
2209 {
2210     HANDLE_TABLE_ENTRY NewHandleEntry;
2211     BOOLEAN AttachedToProcess = FALSE;
2212     PVOID SourceObject;
2213     POBJECT_HEADER ObjectHeader;
2214     POBJECT_TYPE ObjectType;
2215     HANDLE NewHandle;
2216     KAPC_STATE ApcState;
2217     NTSTATUS Status;
2218     ACCESS_MASK TargetAccess, SourceAccess;
2219     ACCESS_STATE AccessState;
2220     PACCESS_STATE PassedAccessState = NULL;
2221     AUX_ACCESS_DATA AuxData;
2222     PHANDLE_TABLE HandleTable;
2223     OBJECT_HANDLE_INFORMATION HandleInformation;
2224     ULONG AuditMask;
2225     BOOLEAN KernelHandle = FALSE;
2226 
2227     PAGED_CODE();
2228     OBTRACE(OB_HANDLE_DEBUG,
2229             "%s - Duplicating handle: %p for %p into %p\n",
2230             __FUNCTION__,
2231             SourceHandle,
2232             SourceProcess,
2233             TargetProcess);
2234 
2235     /* Assume failure */
2236     if (TargetHandle) *TargetHandle = NULL;
2237 
2238     /* Check if we're not duplicating the same access */
2239     if (!(Options & DUPLICATE_SAME_ACCESS))
2240     {
2241         /* Validate the desired access */
2242         Status = STATUS_SUCCESS; //ObpValidateDesiredAccess(DesiredAccess);
2243         if (!NT_SUCCESS(Status)) return Status;
2244     }
2245 
2246     /* Reference the object table */
2247     HandleTable = ObReferenceProcessHandleTable(SourceProcess);
2248     if (!HandleTable) return STATUS_PROCESS_IS_TERMINATING;
2249 
2250     /* Reference the process object */
2251     Status = ObpReferenceProcessObjectByHandle(SourceHandle,
2252                                                SourceProcess,
2253                                                HandleTable,
2254                                                PreviousMode,
2255                                                &SourceObject,
2256                                                &HandleInformation,
2257                                                &AuditMask);
2258     if (!NT_SUCCESS(Status))
2259     {
2260         /* Fail */
2261         ObDereferenceProcessHandleTable(SourceProcess);
2262         return Status;
2263     }
2264     else
2265     {
2266         /* Check if we have to don't have to audit object close */
2267         if (!(HandleInformation.HandleAttributes & OBJ_AUDIT_OBJECT_CLOSE))
2268         {
2269             /* Then there is no audit mask */
2270             AuditMask = 0;
2271         }
2272     }
2273 
2274     /* Check if there's no target process */
2275     if (!TargetProcess)
2276     {
2277         /* Check if the caller wanted actual duplication */
2278         if (!(Options & DUPLICATE_CLOSE_SOURCE))
2279         {
2280             /* Invalid request */
2281             Status = STATUS_INVALID_PARAMETER;
2282         }
2283         else
2284         {
2285             /* Otherwise, do the attach */
2286             KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
2287 
2288             /* Close the handle and detach */
2289             NtClose(SourceHandle);
2290             KeUnstackDetachProcess(&ApcState);
2291         }
2292 
2293         /* Return */
2294         ObDereferenceProcessHandleTable(SourceProcess);
2295         ObDereferenceObject(SourceObject);
2296         return Status;
2297     }
2298 
2299     /* Create a kernel handle if asked, but only in the system process */
2300     if (PreviousMode == KernelMode &&
2301         HandleAttributes & OBJ_KERNEL_HANDLE &&
2302         TargetProcess == PsInitialSystemProcess)
2303     {
2304         KernelHandle = TRUE;
2305     }
2306 
2307     /* Get the target handle table */
2308     HandleTable = ObReferenceProcessHandleTable(TargetProcess);
2309     if (!HandleTable)
2310     {
2311         /* Check if the caller wanted us to close the handle */
2312         if (Options & DUPLICATE_CLOSE_SOURCE)
2313         {
2314             /* Do the attach */
2315             KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
2316 
2317             /* Close the handle and detach */
2318             NtClose(SourceHandle);
2319             KeUnstackDetachProcess(&ApcState);
2320         }
2321 
2322         /* Return */
2323         ObDereferenceProcessHandleTable(SourceProcess);
2324         ObDereferenceObject(SourceObject);
2325         return STATUS_PROCESS_IS_TERMINATING;
2326     }
2327 
2328     /* Get the source access */
2329     SourceAccess = HandleInformation.GrantedAccess;
2330 
2331     /* Check if we're not in the target process */
2332     if (TargetProcess != PsGetCurrentProcess())
2333     {
2334         /* Attach to it */
2335         KeStackAttachProcess(&TargetProcess->Pcb, &ApcState);
2336         AttachedToProcess = TRUE;
2337     }
2338 
2339     /* Check if we're duplicating the attributes */
2340     if (Options & DUPLICATE_SAME_ATTRIBUTES)
2341     {
2342         /* Duplicate them */
2343         HandleAttributes = HandleInformation.HandleAttributes;
2344     }
2345     else
2346     {
2347         /* Don't allow caller to bypass auditing */
2348         HandleAttributes |= HandleInformation.HandleAttributes &
2349                             OBJ_AUDIT_OBJECT_CLOSE;
2350     }
2351 
2352     /* Check if we're duplicating the access */
2353     if (Options & DUPLICATE_SAME_ACCESS) DesiredAccess = SourceAccess;
2354 
2355     /* Get object data */
2356     ObjectHeader = OBJECT_TO_OBJECT_HEADER(SourceObject);
2357     ObjectType = ObjectHeader->Type;
2358 
2359     /* Fill out the entry */
2360     RtlZeroMemory(&NewHandleEntry, sizeof(HANDLE_TABLE_ENTRY));
2361     NewHandleEntry.Object = ObjectHeader;
2362     NewHandleEntry.ObAttributes |= (HandleAttributes & OBJ_HANDLE_ATTRIBUTES);
2363 
2364     /* Check if we're using a generic mask */
2365     if (DesiredAccess & GENERIC_ACCESS)
2366     {
2367         /* Map it */
2368         RtlMapGenericMask(&DesiredAccess,
2369                           &ObjectType->TypeInfo.GenericMapping);
2370     }
2371 
2372     /* Set the target access, always propagate ACCESS_SYSTEM_SECURITY */
2373     TargetAccess = DesiredAccess & (ObjectType->TypeInfo.ValidAccessMask |
2374                                     ACCESS_SYSTEM_SECURITY);
2375     NewHandleEntry.GrantedAccess = TargetAccess;
2376 
2377     /* Check if we're asking for new access */
2378     if (TargetAccess & ~SourceAccess)
2379     {
2380         /* We are. We need the security procedure to validate this */
2381         if (ObjectType->TypeInfo.SecurityProcedure == SeDefaultObjectMethod)
2382         {
2383             /* Use our built-in access state */
2384             PassedAccessState = &AccessState;
2385             Status = SeCreateAccessState(&AccessState,
2386                                          &AuxData,
2387                                          TargetAccess,
2388                                          &ObjectType->TypeInfo.GenericMapping);
2389         }
2390         else
2391         {
2392             /* Otherwise we can't allow this privilege elevation */
2393             Status = STATUS_ACCESS_DENIED;
2394         }
2395     }
2396     else
2397     {
2398         /* We don't need an access state */
2399         Status = STATUS_SUCCESS;
2400     }
2401 
2402     /* Make sure the access state was created OK */
2403     if (NT_SUCCESS(Status))
2404     {
2405         /* Add a new handle */
2406         Status = ObpIncrementHandleCount(SourceObject,
2407                                          PassedAccessState,
2408                                          PreviousMode,
2409                                          HandleAttributes,
2410                                          PsGetCurrentProcess(),
2411                                          ObDuplicateHandle);
2412     }
2413 
2414     /* Check if we were attached */
2415     if (AttachedToProcess)
2416     {
2417         /* We can safely detach now */
2418         KeUnstackDetachProcess(&ApcState);
2419         AttachedToProcess = FALSE;
2420     }
2421 
2422     /* Check if we have to close the source handle */
2423     if (Options & DUPLICATE_CLOSE_SOURCE)
2424     {
2425         /* Attach and close */
2426         KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
2427         NtClose(SourceHandle);
2428         KeUnstackDetachProcess(&ApcState);
2429     }
2430 
2431     /* Check if we had an access state */
2432     if (PassedAccessState) SeDeleteAccessState(PassedAccessState);
2433 
2434     /* Now check if incrementing actually failed */
2435     if (!NT_SUCCESS(Status))
2436     {
2437         /* Dereference handle tables */
2438         ObDereferenceProcessHandleTable(SourceProcess);
2439         ObDereferenceProcessHandleTable(TargetProcess);
2440 
2441         /* Dereference the source object */
2442         ObDereferenceObject(SourceObject);
2443         return Status;
2444     }
2445 
2446     /* Now create the handle */
2447     NewHandle = ExCreateHandle(HandleTable, &NewHandleEntry);
2448     if (!NewHandle)
2449     {
2450         /* Undo the increment */
2451         ObpDecrementHandleCount(SourceObject,
2452                                 TargetProcess,
2453                                 TargetAccess,
2454                                 ObjectType);
2455 
2456         /* Deference the object and set failure status */
2457         ObDereferenceObject(SourceObject);
2458         Status = STATUS_INSUFFICIENT_RESOURCES;
2459     }
2460 
2461     /* Mark it as a kernel handle if requested */
2462     if (KernelHandle)
2463     {
2464         NewHandle = ObMarkHandleAsKernelHandle(NewHandle);
2465     }
2466 
2467     /* Return the handle */
2468     if (TargetHandle) *TargetHandle = NewHandle;
2469 
2470     /* Dereference handle tables */
2471     ObDereferenceProcessHandleTable(SourceProcess);
2472     ObDereferenceProcessHandleTable(TargetProcess);
2473 
2474     /* Return status */
2475     OBTRACE(OB_HANDLE_DEBUG,
2476             "%s - Duplicated handle: %p for %p into %p. Source: %p HC PC %lx %lx\n",
2477             __FUNCTION__,
2478             NewHandle,
2479             SourceProcess,
2480             TargetProcess,
2481             SourceObject,
2482             ObjectHeader->PointerCount,
2483             ObjectHeader->HandleCount);
2484     return Status;
2485 }
2486 
2487 /* PUBLIC FUNCTIONS *********************************************************/
2488 
2489 /*++
2490 * @name ObOpenObjectByName
2491 * @implemented NT4
2492 *
2493 *     The ObOpenObjectByName routine <FILLMEIN>
2494 *
2495 * @param ObjectAttributes
2496 *        <FILLMEIN>.
2497 *
2498 * @param ObjectType
2499 *        <FILLMEIN>.
2500 *
2501 * @param AccessMode
2502 *        <FILLMEIN>.
2503 *
2504 * @param PassedAccessState
2505 *        <FILLMEIN>.
2506 *
2507 * @param DesiredAccess
2508 *        <FILLMEIN>.
2509 *
2510 * @param ParseContext
2511 *        <FILLMEIN>.
2512 *
2513 * @param Handle
2514 *        <FILLMEIN>.
2515 *
2516 * @return <FILLMEIN>.
2517 *
2518 * @remarks None.
2519 *
2520 *--*/
2521 NTSTATUS
2522 NTAPI
2523 ObOpenObjectByName(IN POBJECT_ATTRIBUTES ObjectAttributes,
2524                    IN POBJECT_TYPE ObjectType,
2525                    IN KPROCESSOR_MODE AccessMode,
2526                    IN PACCESS_STATE PassedAccessState,
2527                    IN ACCESS_MASK DesiredAccess,
2528                    IN OUT PVOID ParseContext,
2529                    OUT PHANDLE Handle)
2530 {
2531     PVOID Object = NULL;
2532     UNICODE_STRING ObjectName;
2533     NTSTATUS Status, Status2;
2534     POBJECT_HEADER ObjectHeader;
2535     PGENERIC_MAPPING GenericMapping = NULL;
2536     OB_OPEN_REASON OpenReason;
2537     POB_TEMP_BUFFER TempBuffer;
2538     PAGED_CODE();
2539 
2540     /* Assume failure */
2541     *Handle = NULL;
2542 
2543     /* Check if we didn't get any Object Attributes */
2544     if (!ObjectAttributes)
2545     {
2546         /* Fail with special status code */
2547         return STATUS_INVALID_PARAMETER;
2548     }
2549 
2550     /* Allocate the temporary buffer */
2551     TempBuffer = ExAllocatePoolWithTag(NonPagedPool,
2552                                        sizeof(OB_TEMP_BUFFER),
2553                                        TAG_OB_TEMP_STORAGE);
2554     if (!TempBuffer) return STATUS_INSUFFICIENT_RESOURCES;
2555 
2556     /* Capture all the info */
2557     Status = ObpCaptureObjectCreateInformation(ObjectAttributes,
2558                                                AccessMode,
2559                                                AccessMode,
2560                                                TRUE,
2561                                                &TempBuffer->ObjectCreateInfo,
2562                                                &ObjectName);
2563     if (!NT_SUCCESS(Status))
2564     {
2565         /* Fail */
2566         ExFreePoolWithTag(TempBuffer, TAG_OB_TEMP_STORAGE);
2567         return Status;
2568     }
2569 
2570     /* Check if we didn't get an access state */
2571     if (!PassedAccessState)
2572     {
2573         /* Try to get the generic mapping if we can */
2574         if (ObjectType) GenericMapping = &ObjectType->TypeInfo.GenericMapping;
2575 
2576         /* Use our built-in access state */
2577         PassedAccessState = &TempBuffer->LocalAccessState;
2578         Status = SeCreateAccessState(&TempBuffer->LocalAccessState,
2579                                      &TempBuffer->AuxData,
2580                                      DesiredAccess,
2581                                      GenericMapping);
2582         if (!NT_SUCCESS(Status)) goto Quickie;
2583     }
2584 
2585     /* Get the security descriptor */
2586     if (TempBuffer->ObjectCreateInfo.SecurityDescriptor)
2587     {
2588         /* Save it in the access state */
2589         PassedAccessState->SecurityDescriptor =
2590             TempBuffer->ObjectCreateInfo.SecurityDescriptor;
2591     }
2592 
2593     /* Validate the access mask */
2594     Status = ObpValidateAccessMask(PassedAccessState);
2595     if (!NT_SUCCESS(Status))
2596     {
2597         /* Cleanup after lookup */
2598         ObpReleaseLookupContext(&TempBuffer->LookupContext);
2599         goto Cleanup;
2600     }
2601 
2602     /* Now do the lookup */
2603     Status = ObpLookupObjectName(TempBuffer->ObjectCreateInfo.RootDirectory,
2604                                  &ObjectName,
2605                                  TempBuffer->ObjectCreateInfo.Attributes,
2606                                  ObjectType,
2607                                  AccessMode,
2608                                  ParseContext,
2609                                  TempBuffer->ObjectCreateInfo.SecurityQos,
2610                                  NULL,
2611                                  PassedAccessState,
2612                                  &TempBuffer->LookupContext,
2613                                  &Object);
2614     if (!NT_SUCCESS(Status))
2615     {
2616         /* Cleanup after lookup */
2617         ObpReleaseLookupContext(&TempBuffer->LookupContext);
2618         goto Cleanup;
2619     }
2620 
2621     /* Check if this object has create information */
2622     ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
2623     if (ObjectHeader->Flags & OB_FLAG_CREATE_INFO)
2624     {
2625         /* Then we are creating a new handle */
2626         OpenReason = ObCreateHandle;
2627 
2628         /* Check if we still have create info */
2629         if (ObjectHeader->ObjectCreateInfo)
2630         {
2631             /* Free it */
2632             ObpFreeObjectCreateInformation(ObjectHeader->
2633                                                 ObjectCreateInfo);
2634             ObjectHeader->ObjectCreateInfo = NULL;
2635         }
2636     }
2637     else
2638     {
2639         /* Otherwise, we are merely opening it */
2640         OpenReason = ObOpenHandle;
2641     }
2642 
2643     /* Check if we have invalid object attributes */
2644     if (ObjectHeader->Type->TypeInfo.InvalidAttributes &
2645         TempBuffer->ObjectCreateInfo.Attributes)
2646     {
2647         /* Set failure code */
2648         Status = STATUS_INVALID_PARAMETER;
2649 
2650         /* Cleanup after lookup */
2651         ObpReleaseLookupContext(&TempBuffer->LookupContext);
2652 
2653         /* Dereference the object */
2654         ObDereferenceObject(Object);
2655     }
2656     else
2657     {
2658         /* Create the actual handle now */
2659         Status2 = ObpCreateHandle(OpenReason,
2660                                   Object,
2661                                   ObjectType,
2662                                   PassedAccessState,
2663                                   0,
2664                                   TempBuffer->ObjectCreateInfo.Attributes,
2665                                   &TempBuffer->LookupContext,
2666                                   AccessMode,
2667                                   NULL,
2668                                   Handle);
2669         if (!NT_SUCCESS(Status2))
2670         {
2671             ObDereferenceObject(Object);
2672             Status = Status2;
2673         }
2674     }
2675 
2676 Cleanup:
2677     /* Delete the access state */
2678     if (PassedAccessState == &TempBuffer->LocalAccessState)
2679     {
2680         SeDeleteAccessState(PassedAccessState);
2681     }
2682 
2683 Quickie:
2684     /* Release the object attributes and temporary buffer */
2685     ObpReleaseObjectCreateInformation(&TempBuffer->ObjectCreateInfo);
2686     if (ObjectName.Buffer) ObpFreeObjectNameBuffer(&ObjectName);
2687     ExFreePoolWithTag(TempBuffer, TAG_OB_TEMP_STORAGE);
2688 
2689     /* Return status */
2690     OBTRACE(OB_HANDLE_DEBUG,
2691             "%s - returning Object %p with PC S: %lx %lx\n",
2692             __FUNCTION__,
2693             Object,
2694             Object ? OBJECT_TO_OBJECT_HEADER(Object)->PointerCount : -1,
2695             Status);
2696     return Status;
2697 }
2698 
2699 /*++
2700 * @name ObOpenObjectByPointer
2701 * @implemented NT4
2702 *
2703 *     The ObOpenObjectByPointer routine <FILLMEIN>
2704 *
2705 * @param Object
2706 *        <FILLMEIN>.
2707 *
2708 * @param HandleAttributes
2709 *        <FILLMEIN>.
2710 *
2711 * @param PassedAccessState
2712 *        <FILLMEIN>.
2713 *
2714 * @param DesiredAccess
2715 *        <FILLMEIN>.
2716 *
2717 * @param ObjectType
2718 *        <FILLMEIN>.
2719 *
2720 * @param AccessMode
2721 *        <FILLMEIN>.
2722 *
2723 * @param Handle
2724 *        <FILLMEIN>.
2725 *
2726 * @return <FILLMEIN>.
2727 *
2728 * @remarks None.
2729 *
2730 *--*/
2731 NTSTATUS
2732 NTAPI
2733 ObOpenObjectByPointer(IN PVOID Object,
2734                       IN ULONG HandleAttributes,
2735                       IN PACCESS_STATE PassedAccessState,
2736                       IN ACCESS_MASK DesiredAccess,
2737                       IN POBJECT_TYPE ObjectType,
2738                       IN KPROCESSOR_MODE AccessMode,
2739                       OUT PHANDLE Handle)
2740 {
2741     POBJECT_HEADER Header;
2742     NTSTATUS Status;
2743     ACCESS_STATE AccessState;
2744     AUX_ACCESS_DATA AuxData;
2745     PAGED_CODE();
2746 
2747     /* Assume failure */
2748     *Handle = NULL;
2749 
2750     /* Reference the object */
2751     Status = ObReferenceObjectByPointer(Object,
2752                                         0,
2753                                         ObjectType,
2754                                         AccessMode);
2755     if (!NT_SUCCESS(Status)) return Status;
2756 
2757     /* Get the Header Info */
2758     Header = OBJECT_TO_OBJECT_HEADER(Object);
2759 
2760     /* Check if we didn't get an access state */
2761     if (!PassedAccessState)
2762     {
2763         /* Use our built-in access state */
2764         PassedAccessState = &AccessState;
2765         Status = SeCreateAccessState(&AccessState,
2766                                      &AuxData,
2767                                      DesiredAccess,
2768                                      &Header->Type->TypeInfo.GenericMapping);
2769         if (!NT_SUCCESS(Status))
2770         {
2771             /* Fail */
2772             ObDereferenceObject(Object);
2773             return Status;
2774         }
2775     }
2776 
2777     /* Check if we have invalid object attributes */
2778     if (Header->Type->TypeInfo.InvalidAttributes & HandleAttributes)
2779     {
2780         /* Delete the access state */
2781         if (PassedAccessState == &AccessState)
2782         {
2783             SeDeleteAccessState(PassedAccessState);
2784         }
2785 
2786         /* Dereference the object */
2787         ObDereferenceObject(Object);
2788         return STATUS_INVALID_PARAMETER;
2789     }
2790 
2791     /* Create the handle */
2792     Status = ObpCreateHandle(ObOpenHandle,
2793                              Object,
2794                              ObjectType,
2795                              PassedAccessState,
2796                              0,
2797                              HandleAttributes,
2798                              NULL,
2799                              AccessMode,
2800                              NULL,
2801                              Handle);
2802     if (!NT_SUCCESS(Status)) ObDereferenceObject(Object);
2803 
2804     /* Delete the access state */
2805     if (PassedAccessState == &AccessState)
2806     {
2807         SeDeleteAccessState(PassedAccessState);
2808     }
2809 
2810     /* Return */
2811     OBTRACE(OB_HANDLE_DEBUG,
2812             "%s - returning Object with PC S: %lx %lx\n",
2813             __FUNCTION__,
2814             OBJECT_TO_OBJECT_HEADER(Object)->PointerCount,
2815             Status);
2816     return Status;
2817 }
2818 
2819 /*++
2820 * @name ObFindHandleForObject
2821 * @implemented NT4
2822 *
2823 *     The ObFindHandleForObject routine <FILLMEIN>
2824 *
2825 * @param Process
2826 *        <FILLMEIN>.
2827 *
2828 * @param Object
2829 *        <FILLMEIN>.
2830 *
2831 * @param ObjectType
2832 *        <FILLMEIN>.
2833 *
2834 * @param HandleInformation
2835 *        <FILLMEIN>.
2836 *
2837 * @param HandleReturn
2838 *        <FILLMEIN>.
2839 *
2840 * @return <FILLMEIN>.
2841 *
2842 * @remarks None.
2843 *
2844 *--*/
2845 BOOLEAN
2846 NTAPI
2847 ObFindHandleForObject(IN PEPROCESS Process,
2848                       IN PVOID Object,
2849                       IN POBJECT_TYPE ObjectType,
2850                       IN POBJECT_HANDLE_INFORMATION HandleInformation,
2851                       OUT PHANDLE Handle)
2852 {
2853     OBP_FIND_HANDLE_DATA FindData;
2854     BOOLEAN Result = FALSE;
2855     PVOID ObjectTable;
2856 
2857     /* Make sure we have an object table */
2858     ObjectTable = ObReferenceProcessHandleTable(Process);
2859     if (ObjectTable)
2860     {
2861         /* Check if we have an object */
2862         if (Object)
2863         {
2864             /* Set its header */
2865             FindData.ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
2866         }
2867         else
2868         {
2869             /* Otherwise, no object to match*/
2870             FindData.ObjectHeader = NULL;
2871         }
2872 
2873         /* Set other information */
2874         FindData.ObjectType = ObjectType;
2875         FindData.HandleInformation = HandleInformation;
2876 
2877         /* Enumerate the handle table */
2878         if (ExEnumHandleTable(Process->ObjectTable,
2879                               ObpEnumFindHandleProcedure,
2880                               &FindData,
2881                               Handle))
2882         {
2883             /* Set success */
2884             Result = TRUE;
2885         }
2886 
2887         /* Let go of the table */
2888         ObDereferenceProcessHandleTable(Process);
2889     }
2890 
2891     /* Return the result */
2892     return Result;
2893 }
2894 
2895 /*++
2896 * @name ObInsertObject
2897 * @implemented NT4
2898 *
2899 *     The ObInsertObject routine <FILLMEIN>
2900 *
2901 * @param Object
2902 *        <FILLMEIN>.
2903 *
2904 * @param PassedAccessState
2905 *        <FILLMEIN>.
2906 *
2907 * @param DesiredAccess
2908 *        <FILLMEIN>.
2909 *
2910 * @param AdditionalReferences
2911 *        <FILLMEIN>.
2912 *
2913 * @param ReferencedObject
2914 *        <FILLMEIN>.
2915 *
2916 * @param Handle
2917 *        <FILLMEIN>.
2918 *
2919 * @return <FILLMEIN>.
2920 *
2921 * @remarks None.
2922 *
2923 *--*/
2924 NTSTATUS
2925 NTAPI
2926 ObInsertObject(IN PVOID Object,
2927                IN PACCESS_STATE AccessState OPTIONAL,
2928                IN ACCESS_MASK DesiredAccess,
2929                IN ULONG ObjectPointerBias,
2930                OUT PVOID *NewObject OPTIONAL,
2931                OUT PHANDLE Handle)
2932 {
2933     POBJECT_CREATE_INFORMATION ObjectCreateInfo;
2934     POBJECT_HEADER ObjectHeader;
2935     POBJECT_TYPE ObjectType;
2936     PUNICODE_STRING ObjectName;
2937     PVOID InsertObject;
2938     PSECURITY_DESCRIPTOR ParentDescriptor = NULL;
2939     BOOLEAN SdAllocated = FALSE;
2940     POBJECT_HEADER_NAME_INFO ObjectNameInfo;
2941     OBP_LOOKUP_CONTEXT Context;
2942     ACCESS_STATE LocalAccessState;
2943     AUX_ACCESS_DATA AuxData;
2944     OB_OPEN_REASON OpenReason;
2945     KPROCESSOR_MODE PreviousMode;
2946     NTSTATUS Status = STATUS_SUCCESS, RealStatus;
2947     BOOLEAN IsNewObject;
2948     PAGED_CODE();
2949 
2950     /* Get the Header */
2951     ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
2952 
2953     /* Detect invalid insert */
2954     if (!(ObjectHeader->Flags & OB_FLAG_CREATE_INFO))
2955     {
2956         /* Display warning and break into debugger */
2957         DPRINT1("OB: Attempting to insert existing object %p\n", Object);
2958         DbgBreakPoint();
2959 
2960         /* Allow debugger to continue */
2961         ObDereferenceObject(Object);
2962         return STATUS_INVALID_PARAMETER;
2963     }
2964 
2965     /* Get the create and name info, as well as the object type */
2966     ObjectCreateInfo = ObjectHeader->ObjectCreateInfo;
2967     ObjectNameInfo = ObpReferenceNameInfo(ObjectHeader);
2968     ObjectType = ObjectHeader->Type;
2969     ObjectName = NULL;
2970 
2971     /* Check if this is an named object */
2972     if ((ObjectNameInfo) && (ObjectNameInfo->Name.Buffer))
2973     {
2974         /* Get the object name */
2975         ObjectName = &ObjectNameInfo->Name;
2976     }
2977 
2978     /* Sanity check */
2979     ASSERT((Handle) ||
2980            ((ObjectPointerBias == 0) &&
2981             (ObjectName == NULL) &&
2982             (ObjectType->TypeInfo.SecurityRequired) &&
2983             (NewObject == NULL)));
2984 
2985     /* Check if the object is unnamed and also doesn't have security */
2986     PreviousMode = KeGetPreviousMode();
2987     if (!(ObjectType->TypeInfo.SecurityRequired) && !(ObjectName))
2988     {
2989         /* Assume failure */
2990         *Handle = NULL;
2991         ObjectHeader->ObjectCreateInfo = NULL;
2992 
2993         /* Create the handle */
2994         Status = ObpCreateUnnamedHandle(Object,
2995                                         DesiredAccess,
2996                                         ObjectPointerBias + 1,
2997                                         ObjectCreateInfo->Attributes,
2998                                         PreviousMode,
2999                                         NewObject,
3000                                         Handle);
3001 
3002         /* Free the create information */
3003         ObpFreeObjectCreateInformation(ObjectCreateInfo);
3004 
3005         /* Release the object name information */
3006         ObpDereferenceNameInfo(ObjectNameInfo);
3007 
3008         /* Remove the extra keep-alive reference */
3009         ObDereferenceObject(Object);
3010 
3011         /* Return */
3012         OBTRACE(OB_HANDLE_DEBUG,
3013                 "%s - returning Object with PC S: %lx %lx\n",
3014                 __FUNCTION__,
3015                 ObjectHeader->PointerCount,
3016                 Status);
3017         return Status;
3018     }
3019 
3020     /* Check if we didn't get an access state */
3021     if (!AccessState)
3022     {
3023         /* Use our built-in access state */
3024         AccessState = &LocalAccessState;
3025         Status = SeCreateAccessState(&LocalAccessState,
3026                                      &AuxData,
3027                                      DesiredAccess,
3028                                      &ObjectType->TypeInfo.GenericMapping);
3029         if (!NT_SUCCESS(Status))
3030         {
3031             /* Fail */
3032             ObpDereferenceNameInfo(ObjectNameInfo);
3033             ObDereferenceObject(Object);
3034             return Status;
3035         }
3036     }
3037 
3038     /* Save the security descriptor */
3039     AccessState->SecurityDescriptor = ObjectCreateInfo->SecurityDescriptor;
3040 
3041     /* Validate the access mask */
3042     Status = ObpValidateAccessMask(AccessState);
3043     if (!NT_SUCCESS(Status))
3044     {
3045         /* Fail */
3046         ObpDereferenceNameInfo(ObjectNameInfo);
3047         ObDereferenceObject(Object);
3048         return Status;
3049     }
3050 
3051     /* Setup a lookup context */
3052     ObpInitializeLookupContext(&Context);
3053     InsertObject = Object;
3054     OpenReason = ObCreateHandle;
3055 
3056     /* Check if the object is named */
3057     if (ObjectName)
3058     {
3059         /* Look it up */
3060         Status = ObpLookupObjectName(ObjectCreateInfo->RootDirectory,
3061                                      ObjectName,
3062                                      ObjectCreateInfo->Attributes,
3063                                      ObjectType,
3064                                      (ObjectHeader->Flags & OB_FLAG_KERNEL_MODE) ?
3065                                      KernelMode : UserMode,
3066                                      ObjectCreateInfo->ParseContext,
3067                                      ObjectCreateInfo->SecurityQos,
3068                                      Object,
3069                                      AccessState,
3070                                      &Context,
3071                                      &InsertObject);
3072 
3073         /* Check if we found an object that doesn't match the one requested */
3074         if ((NT_SUCCESS(Status)) && (InsertObject) && (Object != InsertObject))
3075         {
3076             /* This means we're opening an object, not creating a new one */
3077             OpenReason = ObOpenHandle;
3078 
3079             /* Make sure the caller said it's OK to do this */
3080             if (ObjectCreateInfo->Attributes & OBJ_OPENIF)
3081             {
3082                 /* He did, but did he want this type? */
3083                 if (ObjectType != OBJECT_TO_OBJECT_HEADER(InsertObject)->Type)
3084                 {
3085                     /* Wrong type, so fail */
3086                     Status = STATUS_OBJECT_TYPE_MISMATCH;
3087                 }
3088                 else
3089                 {
3090                     /* Right type, so warn */
3091                     Status = STATUS_OBJECT_NAME_EXISTS;
3092                 }
3093             }
3094             else
3095             {
3096                 /* Check if this was a symbolic link */
3097                 if (OBJECT_TO_OBJECT_HEADER(InsertObject)->Type ==
3098                     ObpSymbolicLinkObjectType)
3099                 {
3100                     /* Dereference it */
3101                     ObDereferenceObject(InsertObject);
3102                 }
3103 
3104                 /* Caller wanted to create a new object, fail */
3105                 Status = STATUS_OBJECT_NAME_COLLISION;
3106             }
3107         }
3108 
3109         /* Check if anything until now failed */
3110         if (!NT_SUCCESS(Status))
3111         {
3112             /* Cleanup after lookup */
3113             ObpReleaseLookupContext(&Context);
3114 
3115             /* Remove query reference that we added */
3116             ObpDereferenceNameInfo(ObjectNameInfo);
3117 
3118             /* Dereference the object and delete the access state */
3119             ObDereferenceObject(Object);
3120             if (AccessState == &LocalAccessState)
3121             {
3122                 /* We used a local one; delete it */
3123                 SeDeleteAccessState(AccessState);
3124             }
3125 
3126             /* Return failure code */
3127             return Status;
3128         }
3129         else
3130         {
3131             /* Check if this is a symbolic link */
3132             if (ObjectType == ObpSymbolicLinkObjectType)
3133             {
3134                 /* Create the internal name */
3135                 ObpCreateSymbolicLinkName(Object);
3136             }
3137         }
3138     }
3139 
3140     /* Now check if this object is being created */
3141     if (InsertObject == Object)
3142     {
3143         /* Check if it's named or forces security */
3144         if ((ObjectName) || (ObjectType->TypeInfo.SecurityRequired))
3145         {
3146             /* Make sure it's inserted into an object directory */
3147             if ((ObjectNameInfo) && (ObjectNameInfo->Directory))
3148             {
3149                 /* Get the current descriptor */
3150                 ObGetObjectSecurity(ObjectNameInfo->Directory,
3151                                     &ParentDescriptor,
3152                                     &SdAllocated);
3153             }
3154 
3155             /* Now assign it */
3156             Status = ObAssignSecurity(AccessState,
3157                                       ParentDescriptor,
3158                                       Object,
3159                                       ObjectType);
3160 
3161             /* Check if we captured one */
3162             if (ParentDescriptor)
3163             {
3164                 /* We did, release it */
3165                 ObReleaseObjectSecurity(ParentDescriptor, SdAllocated);
3166             }
3167             else if (NT_SUCCESS(Status))
3168             {
3169                 /* Other we didn't, but we were able to use the current SD */
3170                 SeReleaseSecurityDescriptor(ObjectCreateInfo->SecurityDescriptor,
3171                                             ObjectCreateInfo->ProbeMode,
3172                                             TRUE);
3173 
3174                 /* Clear the current one */
3175                 AccessState->SecurityDescriptor =
3176                 ObjectCreateInfo->SecurityDescriptor = NULL;
3177             }
3178         }
3179 
3180         /* Check if anything until now failed */
3181         if (!NT_SUCCESS(Status))
3182         {
3183             /* Check if the directory was added */
3184             if (Context.DirectoryLocked)
3185             {
3186                 /* Weird case where we need to do a manual delete */
3187                 DPRINT1("Unhandled path\n");
3188                 ASSERT(FALSE);
3189             }
3190 
3191             /* Cleanup the lookup */
3192             ObpReleaseLookupContext(&Context);
3193 
3194             /* Remove query reference that we added */
3195             ObpDereferenceNameInfo(ObjectNameInfo);
3196 
3197             /* Dereference the object and delete the access state */
3198             ObDereferenceObject(Object);
3199             if (AccessState == &LocalAccessState)
3200             {
3201                 /* We used a local one; delete it */
3202                 SeDeleteAccessState(AccessState);
3203             }
3204 
3205             /* Return failure code */
3206             ASSERT(FALSE);
3207             return Status;
3208         }
3209     }
3210 
3211     /* Save the actual status until here */
3212     RealStatus = Status;
3213 
3214     /* Check if caller wants us to create a handle */
3215     ObjectHeader->ObjectCreateInfo = NULL;
3216     if (Handle)
3217     {
3218         /* Create the handle */
3219         Status = ObpCreateHandle(OpenReason,
3220                                  InsertObject,
3221                                  NULL,
3222                                  AccessState,
3223                                  ObjectPointerBias + 1,
3224                                  ObjectCreateInfo->Attributes,
3225                                  &Context,
3226                                  PreviousMode,
3227                                  NewObject,
3228                                  Handle);
3229         if (!NT_SUCCESS(Status))
3230         {
3231             /* If the object had a name, backout everything */
3232             if (ObjectName) ObpDeleteNameCheck(Object);
3233 
3234             /* Return the status of the failure */
3235             *Handle = NULL;
3236             RealStatus = Status;
3237         }
3238 
3239         /* Remove a query reference */
3240         ObpDereferenceNameInfo(ObjectNameInfo);
3241 
3242         /* Remove the extra keep-alive reference */
3243         ObDereferenceObject(Object);
3244     }
3245     else
3246     {
3247         /* Otherwise, lock the object */
3248         ObpAcquireObjectLock(ObjectHeader);
3249 
3250         /* And charge quota for the process to make it appear as used */
3251         RealStatus = ObpChargeQuotaForObject(ObjectHeader,
3252                                              ObjectType,
3253                                              &IsNewObject);
3254 
3255         /* Release the lock */
3256         ObpReleaseObjectLock(ObjectHeader);
3257 
3258         /* Check if we failed and dereference the object if so */
3259         if (!NT_SUCCESS(RealStatus)) ObDereferenceObject(Object);
3260     }
3261 
3262     /* We can delete the Create Info now */
3263     ObpFreeObjectCreateInformation(ObjectCreateInfo);
3264 
3265     /* Check if we created our own access state and delete it if so */
3266     if (AccessState == &LocalAccessState) SeDeleteAccessState(AccessState);
3267 
3268     /* Return status code */
3269     OBTRACE(OB_HANDLE_DEBUG,
3270             "%s - returning Object with PC RS/S: %lx %lx %lx\n",
3271             __FUNCTION__,
3272             OBJECT_TO_OBJECT_HEADER(Object)->PointerCount,
3273             RealStatus, Status);
3274     return RealStatus;
3275 }
3276 
3277 /*++
3278 * @name ObSetHandleAttributes
3279 * @implemented NT5.1
3280 *
3281 *     The ObSetHandleAttributes routine <FILLMEIN>
3282 *
3283 * @param Handle
3284 *        <FILLMEIN>.
3285 *
3286 * @param HandleFlags
3287 *        <FILLMEIN>.
3288 *
3289 * @param PreviousMode
3290 *        <FILLMEIN>.
3291 *
3292 * @return <FILLMEIN>.
3293 *
3294 * @remarks None.
3295 *
3296 *--*/
3297 NTSTATUS
3298 NTAPI
3299 ObSetHandleAttributes(IN HANDLE Handle,
3300                       IN POBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleFlags,
3301                       IN KPROCESSOR_MODE PreviousMode)
3302 {
3303     OBP_SET_HANDLE_ATTRIBUTES_CONTEXT SetHandleAttributesContext;
3304     BOOLEAN Result, AttachedToSystemProcess = FALSE;
3305     PHANDLE_TABLE HandleTable;
3306     KAPC_STATE ApcState;
3307     PAGED_CODE();
3308 
3309     /* Check if this is a kernel handle */
3310     if (ObpIsKernelHandle(Handle, PreviousMode))
3311     {
3312         /* Use the kernel table and convert the handle */
3313         HandleTable = ObpKernelHandleTable;
3314         Handle = ObKernelHandleToHandle(Handle);
3315 
3316         /* Check if we're not in the system process */
3317         if (PsGetCurrentProcess() != PsInitialSystemProcess)
3318         {
3319             /* Attach to the system process */
3320             KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
3321             AttachedToSystemProcess = TRUE;
3322         }
3323     }
3324     else
3325     {
3326         /* Get the current process' handle table */
3327         HandleTable = PsGetCurrentProcess()->ObjectTable;
3328     }
3329 
3330     /* Initialize the handle attribute context */
3331     SetHandleAttributesContext.PreviousMode = PreviousMode;
3332     SetHandleAttributesContext.Information = *HandleFlags;
3333 
3334     /* Invoke the ObpSetHandleAttributes callback */
3335     Result = ExChangeHandle(HandleTable,
3336                             Handle,
3337                             ObpSetHandleAttributes,
3338                             (ULONG_PTR)&SetHandleAttributesContext);
3339 
3340     /* Did we attach to the system process? */
3341     if (AttachedToSystemProcess)
3342     {
3343         /* Detach from it */
3344         KeUnstackDetachProcess(&ApcState);
3345     }
3346 
3347     /* Return the result as an NTSTATUS value */
3348     return Result ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
3349 }
3350 
3351 /*++
3352 * @name ObCloseHandle
3353 * @implemented NT5.1
3354 *
3355 *     The ObCloseHandle routine <FILLMEIN>
3356 *
3357 * @param Handle
3358 *        <FILLMEIN>.
3359 *
3360 * @param AccessMode
3361 *        <FILLMEIN>.
3362 *
3363 * @return <FILLMEIN>.
3364 *
3365 * @remarks None.
3366 *
3367 *--*/
3368 NTSTATUS
3369 NTAPI
3370 ObCloseHandle(IN HANDLE Handle,
3371               IN KPROCESSOR_MODE AccessMode)
3372 {
3373     /* Call the internal API */
3374     return ObpCloseHandle(Handle, AccessMode);
3375 }
3376 
3377 /*++
3378 * @name NtClose
3379 * @implemented NT4
3380 *
3381 *     The NtClose routine <FILLMEIN>
3382 *
3383 * @param Handle
3384 *        <FILLMEIN>.
3385 *
3386 * @return <FILLMEIN>.
3387 *
3388 * @remarks None.
3389 *
3390 *--*/
3391 NTSTATUS
3392 NTAPI
3393 NtClose(IN HANDLE Handle)
3394 {
3395     /* Call the internal API */
3396     return ObpCloseHandle(Handle, ExGetPreviousMode());
3397 }
3398 
3399 NTSTATUS
3400 NTAPI
3401 NtDuplicateObject(IN HANDLE SourceProcessHandle,
3402                   IN HANDLE SourceHandle,
3403                   IN HANDLE TargetProcessHandle OPTIONAL,
3404                   OUT PHANDLE TargetHandle OPTIONAL,
3405                   IN ACCESS_MASK DesiredAccess,
3406                   IN ULONG HandleAttributes,
3407                   IN ULONG Options)
3408 {
3409     PEPROCESS SourceProcess, TargetProcess, Target;
3410     HANDLE hTarget;
3411     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
3412     NTSTATUS Status;
3413     OBTRACE(OB_HANDLE_DEBUG,
3414             "%s - Duplicating handle: %p for %p into %p.\n",
3415             __FUNCTION__,
3416             SourceHandle,
3417             SourceProcessHandle,
3418             TargetProcessHandle);
3419 
3420     /* Check if we have a target handle */
3421     if ((TargetHandle) && (PreviousMode != KernelMode))
3422     {
3423         /* Enter SEH */
3424         _SEH2_TRY
3425         {
3426             /* Probe the handle and assume failure */
3427             ProbeForWriteHandle(TargetHandle);
3428             *TargetHandle = NULL;
3429         }
3430         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3431         {
3432             /* Return the exception code */
3433             _SEH2_YIELD(return _SEH2_GetExceptionCode());
3434         }
3435         _SEH2_END;
3436     }
3437 
3438     /* Now reference the input handle */
3439     Status = ObReferenceObjectByHandle(SourceProcessHandle,
3440                                        PROCESS_DUP_HANDLE,
3441                                        PsProcessType,
3442                                        PreviousMode,
3443                                        (PVOID*)&SourceProcess,
3444                                        NULL);
3445     if (!NT_SUCCESS(Status)) return Status;
3446 
3447     /* Check if got a target handle */
3448     if (TargetProcessHandle)
3449     {
3450         /* Now reference the output handle */
3451         Status = ObReferenceObjectByHandle(TargetProcessHandle,
3452                                            PROCESS_DUP_HANDLE,
3453                                            PsProcessType,
3454                                            PreviousMode,
3455                                            (PVOID*)&TargetProcess,
3456                                            NULL);
3457         if (NT_SUCCESS(Status))
3458         {
3459             /* Use this target process */
3460             Target = TargetProcess;
3461         }
3462         else
3463         {
3464             /* No target process */
3465             Target = NULL;
3466         }
3467     }
3468     else
3469     {
3470         /* No target process */
3471         Status = STATUS_SUCCESS;
3472         Target = NULL;
3473     }
3474 
3475     /* Call the internal routine */
3476     Status = ObDuplicateObject(SourceProcess,
3477                                SourceHandle,
3478                                Target,
3479                                &hTarget,
3480                                DesiredAccess,
3481                                HandleAttributes,
3482                                Options,
3483                                PreviousMode);
3484 
3485     /* Check if the caller wanted the return handle */
3486     if (TargetHandle)
3487     {
3488         /* Protect the write to user mode */
3489         _SEH2_TRY
3490         {
3491             /* Write the new handle */
3492             *TargetHandle = hTarget;
3493         }
3494         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3495         {
3496             /* Otherwise, get the exception code */
3497             Status = _SEH2_GetExceptionCode();
3498         }
3499         _SEH2_END;
3500     }
3501 
3502     /* Dereference the processes */
3503     OBTRACE(OB_HANDLE_DEBUG,
3504             "%s - Duplicated handle: %p into %p S %lx\n",
3505             __FUNCTION__,
3506             hTarget,
3507             TargetProcessHandle,
3508             Status);
3509     if (Target) ObDereferenceObject(Target);
3510     ObDereferenceObject(SourceProcess);
3511     return Status;
3512 }
3513 
3514 BOOLEAN
3515 NTAPI
3516 ObIsKernelHandle(IN HANDLE Handle)
3517 {
3518     /* Use the inlined version. We know we are in kernel mode. */
3519     return ObpIsKernelHandle(Handle, KernelMode);
3520 }
3521 
3522 /* EOF */
3523