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