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