branch update for HEAD-2003021201
[reactos.git] / ntoskrnl / ob / handle.c
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 /* $Id$
20  *
21  * COPYRIGHT:          See COPYING in the top level directory
22  * PROJECT:            ReactOS kernel
23  * FILE:               ntoskrnl/ob/handle.c
24  * PURPOSE:            Managing handles
25  * PROGRAMMER:         David Welch (welch@cwcom.net)
26  * REVISION HISTORY:
27  *                 17/06/98: Created
28  */
29
30 /* INCLUDES ****************************************************************/
31
32 #include <ddk/ntddk.h>
33 #include <internal/ob.h>
34 #include <internal/ps.h>
35 #include <internal/pool.h>
36 #include <internal/safe.h>
37
38 #define NDEBUG
39 #include <internal/debug.h>
40
41 /* TYPES *******************************************************************/
42
43 /*
44  * PURPOSE: Defines a handle
45  */
46 typedef struct
47 {
48    PVOID ObjectBody;
49    ACCESS_MASK GrantedAccess;
50    BOOLEAN Inherit;
51 } HANDLE_REP, *PHANDLE_REP;
52
53 #define HANDLE_BLOCK_ENTRIES ((PAGE_SIZE-sizeof(LIST_ENTRY))/sizeof(HANDLE_REP))
54
55
56 /*
57  * PURPOSE: Defines a page's worth of handles
58  */
59 typedef struct
60 {
61    LIST_ENTRY entry;
62    HANDLE_REP handles[HANDLE_BLOCK_ENTRIES];
63 } HANDLE_BLOCK, *PHANDLE_BLOCK;
64
65
66 /* GLOBALS *******************************************************************/
67
68 #define TAG_HANDLE_TABLE    TAG('H', 'T', 'B', 'L')
69
70 /* FUNCTIONS ***************************************************************/
71
72
73 static PHANDLE_REP ObpGetObjectByHandle(PHANDLE_TABLE HandleTable, HANDLE h)
74 /*
75  * FUNCTION: Get the data structure for a handle
76  * ARGUMENTS:
77  *         Process = Process to get the handle for
78  *         h = Handle
79  * ARGUMENTS: A pointer to the information about the handle on success,
80  *            NULL on failure
81  */
82 {
83    PLIST_ENTRY current;
84    unsigned int handle = (((unsigned int)h) >> 2) - 1;
85    unsigned int count=handle/HANDLE_BLOCK_ENTRIES;
86    HANDLE_BLOCK* blk = NULL;
87    unsigned int i;
88    
89    DPRINT("ObpGetObjectByHandle(HandleTable %x, h %x)\n",HandleTable,h);
90    
91    current = HandleTable->ListHead.Flink;
92    DPRINT("current %x\n",current);
93    
94    for (i=0;i<count;i++)
95      {
96         current = current->Flink;
97         if (current == (&(HandleTable->ListHead)))
98           {
99              return(NULL);
100           }
101      }
102    
103    blk = CONTAINING_RECORD(current,HANDLE_BLOCK,entry);
104    DPRINT("object: %p\n",&(blk->handles[handle%HANDLE_BLOCK_ENTRIES]));
105    return(&(blk->handles[handle%HANDLE_BLOCK_ENTRIES]));
106 }
107
108 #ifndef LIBCAPTIVE
109
110 NTSTATUS
111 ObDuplicateObject(PEPROCESS SourceProcess,
112                   PEPROCESS TargetProcess,
113                   HANDLE SourceHandle,
114                   PHANDLE TargetHandle,
115                   ACCESS_MASK DesiredAccess,
116                   BOOLEAN InheritHandle,
117                   ULONG Options)
118 {
119   KIRQL oldIrql;
120   PHANDLE_REP SourceHandleRep;
121   PVOID ObjectBody;
122
123   KeAcquireSpinLock(&SourceProcess->HandleTable.ListLock, &oldIrql);
124   SourceHandleRep = ObpGetObjectByHandle(&SourceProcess->HandleTable,
125                                          SourceHandle);
126   if (SourceHandleRep == NULL)
127     {
128       KeReleaseSpinLock(&SourceProcess->HandleTable.ListLock, oldIrql);
129       return(STATUS_INVALID_HANDLE);
130     }
131   ObjectBody = SourceHandleRep->ObjectBody;
132   ObReferenceObjectByPointer(ObjectBody,
133                              0,
134                              NULL,
135                              UserMode);
136   
137   if (Options & DUPLICATE_SAME_ACCESS)
138     {
139       DesiredAccess = SourceHandleRep->GrantedAccess;
140     }
141   
142   KeReleaseSpinLock(&SourceProcess->HandleTable.ListLock, oldIrql);
143   ObCreateHandle(TargetProcess,
144                  ObjectBody,
145                  DesiredAccess,
146                  InheritHandle,
147                  TargetHandle);
148   
149   if (Options & DUPLICATE_CLOSE_SOURCE)
150     {
151       ZwClose(SourceHandle);
152     }
153   
154   ObDereferenceObject(ObjectBody);
155   return(STATUS_SUCCESS);
156 }
157
158 NTSTATUS STDCALL 
159 NtDuplicateObject (IN   HANDLE          SourceProcessHandle,
160                    IN   HANDLE          SourceHandle,
161                    IN   HANDLE          TargetProcessHandle,
162                    OUT  PHANDLE         UnsafeTargetHandle,
163                    IN   ACCESS_MASK     DesiredAccess,
164                    IN   BOOLEAN         InheritHandle,
165                    ULONG                Options)
166 /*
167  * FUNCTION: Copies a handle from one process space to another
168  * ARGUMENTS:
169  *         SourceProcessHandle = The source process owning the handle. The 
170  *                               source process should have opened
171  *                               the SourceHandle with PROCESS_DUP_HANDLE 
172  *                               access.
173  *         SourceHandle = The handle to the object.
174  *         TargetProcessHandle = The destination process owning the handle 
175  *         TargetHandle (OUT) = Caller should supply storage for the 
176  *                              duplicated handle. 
177  *         DesiredAccess = The desired access to the handle.
178  *         InheritHandle = Indicates wheter the new handle will be inheritable
179  *                         or not.
180  *         Options = Specifies special actions upon duplicating the handle. 
181  *                   Can be one of the values DUPLICATE_CLOSE_SOURCE | 
182  *                   DUPLICATE_SAME_ACCESS. DUPLICATE_CLOSE_SOURCE specifies 
183  *                   that the source handle should be closed after duplicating. 
184  *                   DUPLICATE_SAME_ACCESS specifies to ignore the 
185  *                   DesiredAccess paramter and just grant the same access to 
186  *                   the new handle.
187  * RETURNS: Status
188  * REMARKS: This function maps to the win32 DuplicateHandle.
189  */
190 {
191    PEPROCESS SourceProcess;
192    PEPROCESS TargetProcess;
193    PHANDLE_REP SourceHandleRep;
194    KIRQL oldIrql;
195    PVOID ObjectBody;
196    HANDLE TargetHandle;
197    NTSTATUS Status;
198    
199    ASSERT_IRQL(PASSIVE_LEVEL);
200    
201    Status = ObReferenceObjectByHandle(SourceProcessHandle,
202                                       PROCESS_DUP_HANDLE,
203                                       NULL,
204                                       UserMode,
205                                       (PVOID*)&SourceProcess,
206                                       NULL);
207    if (!NT_SUCCESS(Status))
208      {
209        return(Status);
210      }
211    Status = ObReferenceObjectByHandle(TargetProcessHandle,
212                                       PROCESS_DUP_HANDLE,
213                                       NULL,
214                                       UserMode,
215                                       (PVOID*)&TargetProcess,
216                                       NULL);
217    if (!NT_SUCCESS(Status))
218      {
219        ObDereferenceObject(SourceProcess);
220        return(Status);
221      }
222    KeAcquireSpinLock(&SourceProcess->HandleTable.ListLock, &oldIrql);
223    SourceHandleRep = ObpGetObjectByHandle(&SourceProcess->HandleTable,
224                                           SourceHandle);
225    if (SourceHandleRep == NULL)
226      {
227         KeReleaseSpinLock(&SourceProcess->HandleTable.ListLock, oldIrql);
228         ObDereferenceObject(SourceProcess);
229         ObDereferenceObject(TargetProcess);
230         return(STATUS_INVALID_HANDLE);
231      }
232    ObjectBody = SourceHandleRep->ObjectBody;
233    ObReferenceObjectByPointer(ObjectBody,
234                               0,
235                               NULL,
236                               UserMode);
237    
238    if (Options & DUPLICATE_SAME_ACCESS)
239      {
240         DesiredAccess = SourceHandleRep->GrantedAccess;
241      }
242    
243    KeReleaseSpinLock(&SourceProcess->HandleTable.ListLock, oldIrql);
244    if (!SourceHandleRep->Inherit)
245      {
246        ObDereferenceObject(TargetProcess);
247        ObDereferenceObject(SourceProcess);
248        ObDereferenceObject(ObjectBody);
249        return STATUS_INVALID_HANDLE;
250      }
251    ObCreateHandle(TargetProcess,
252                   ObjectBody,
253                   DesiredAccess,
254                   InheritHandle,
255                   &TargetHandle);
256    
257    if (Options & DUPLICATE_CLOSE_SOURCE)
258      {
259         ZwClose(SourceHandle);
260      }
261    
262    ObDereferenceObject(TargetProcess);
263    ObDereferenceObject(SourceProcess);
264    ObDereferenceObject(ObjectBody);
265    
266    Status = MmCopyToCaller(UnsafeTargetHandle, &TargetHandle, sizeof(HANDLE));
267    if (!NT_SUCCESS(Status))
268      {
269        return(Status);
270      }
271
272    return(STATUS_SUCCESS);
273 }
274
275 VOID ObCloseAllHandles(PEPROCESS Process)
276 {
277    KIRQL oldIrql;
278    PHANDLE_TABLE HandleTable;
279    PLIST_ENTRY current_entry;
280    PHANDLE_BLOCK current;
281    ULONG i;
282    PVOID ObjectBody;
283    BOOLEAN IsProcessHandle;
284    
285    DPRINT("ObCloseAllHandles(Process %x)\n", Process);
286    
287    HandleTable = &Process->HandleTable;
288    
289    KeAcquireSpinLock(&HandleTable->ListLock, &oldIrql);
290    
291    current_entry = HandleTable->ListHead.Flink;
292    
293    while (current_entry != &HandleTable->ListHead)
294      {
295         current = CONTAINING_RECORD(current_entry, HANDLE_BLOCK, entry);
296         
297         for (i = 0; i < HANDLE_BLOCK_ENTRIES; i++)
298           {
299              ObjectBody = current->handles[i].ObjectBody;
300              
301              if (ObjectBody != NULL)
302                {
303                   POBJECT_HEADER Header = BODY_TO_HEADER(ObjectBody);
304                   
305                   if (Header->ObjectType == PsProcessType ||
306                       Header->ObjectType == PsThreadType)
307                     {
308                        DPRINT("Deleting handle to %x\n", ObjectBody);
309                     }
310                   
311                   ObReferenceObjectByPointer(ObjectBody,
312                                              0,
313                                              NULL,
314                                              UserMode);
315                   InterlockedDecrement(&Header->HandleCount);
316                   current->handles[i].ObjectBody = NULL;
317                   
318                   KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
319                   
320                   if (Header->ObjectType == PsProcessType)
321                   {
322                      IsProcessHandle = TRUE;
323                      KeDetachProcess();
324                   }
325                   else
326                   {
327                      IsProcessHandle = FALSE;
328                   }
329                   if ((Header->ObjectType != NULL) &&
330                       (Header->ObjectType->Close != NULL))
331                     {
332                        Header->ObjectType->Close(ObjectBody, 
333                                                  Header->HandleCount);
334                     }
335                   
336                   ObDereferenceObject(ObjectBody);
337                   if (IsProcessHandle)
338                   {
339                      KeAttachProcess(Process);
340                   }
341                   KeAcquireSpinLock(&HandleTable->ListLock, &oldIrql);
342                   current_entry = &HandleTable->ListHead;
343                   break;
344                }
345           }
346         
347         current_entry = current_entry->Flink;
348      }
349    KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
350    DPRINT("ObCloseAllHandles() finished\n");
351    DPRINT("Type %x\n", BODY_TO_HEADER(Process)->ObjectType);
352 }
353
354 VOID ObDeleteHandleTable(PEPROCESS Process)
355 /*
356  * FUNCTION: Deletes the handle table associated with a process
357  */
358 {
359    PLIST_ENTRY current = NULL;
360    PHANDLE_TABLE HandleTable = NULL;
361    
362    ObCloseAllHandles(Process);
363    
364    HandleTable = &Process->HandleTable;
365    current = RemoveHeadList(&HandleTable->ListHead);
366    
367    while (current != &HandleTable->ListHead)
368      {
369         HANDLE_BLOCK* HandleBlock = CONTAINING_RECORD(current,
370                                                       HANDLE_BLOCK,
371                                                       entry);
372         DPRINT("Freeing %x\n", HandleBlock);
373         ExFreePool(HandleBlock);
374         
375         current = RemoveHeadList(&HandleTable->ListHead);
376      }
377 }
378
379 #endif /* LIBCAPTIVE */
380
381 VOID ObCreateHandleTable(PEPROCESS Parent,
382                          BOOLEAN Inherit,
383                          PEPROCESS Process)
384 /*
385  * FUNCTION: Creates a handle table for a process
386  * ARGUMENTS:
387  *       Parent = Parent process (or NULL if this is the first process)
388  *       Inherit = True if the process should inherit its parent's handles
389  *       Process = Process whose handle table is to be created
390  */
391 {
392    PHANDLE_TABLE ParentHandleTable, HandleTable;
393    KIRQL oldIrql;
394    PLIST_ENTRY parent_current;
395    ULONG i;
396    PHANDLE_BLOCK current_block, new_block;   
397
398    DPRINT("ObCreateHandleTable(Parent %x, Inherit %d, Process %x)\n",
399           Parent,Inherit,Process);
400    
401    InitializeListHead(&(Process->HandleTable.ListHead));
402    KeInitializeSpinLock(&(Process->HandleTable.ListLock));
403    
404    if (Parent != NULL)
405      {
406         ParentHandleTable = &Parent->HandleTable;
407         HandleTable = &Process->HandleTable;
408
409         KeAcquireSpinLock(&Parent->HandleTable.ListLock, &oldIrql);
410         KeAcquireSpinLockAtDpcLevel(&Process->HandleTable.ListLock);
411         
412         parent_current = ParentHandleTable->ListHead.Flink;
413         
414         while (parent_current != &ParentHandleTable->ListHead)
415           {
416              current_block = CONTAINING_RECORD(parent_current,
417                                                HANDLE_BLOCK,
418                                                entry);
419              new_block = ExAllocatePoolWithTag(NonPagedPool,
420                                                sizeof(HANDLE_BLOCK),
421                                                TAG_HANDLE_TABLE);
422              if (new_block == NULL)
423              {
424                 break;
425              }
426              RtlZeroMemory(new_block, sizeof(HANDLE_BLOCK));
427
428              for (i=0; i<HANDLE_BLOCK_ENTRIES; i++)
429              {
430                 if (current_block->handles[i].ObjectBody)
431                 {
432                    if (current_block->handles[i].Inherit && Inherit)
433                    {
434                       new_block->handles[i].ObjectBody = 
435                         current_block->handles[i].ObjectBody;
436                       new_block->handles[i].GrantedAccess = 
437                         current_block->handles[i].GrantedAccess;
438                       new_block->handles[i].Inherit = TRUE;
439                       InterlockedIncrement(&(BODY_TO_HEADER(current_block->handles[i].ObjectBody)->HandleCount));
440                    }
441                 }
442              }
443              InsertTailList(&Process->HandleTable.ListHead, &new_block->entry);
444              parent_current = parent_current->Flink;
445           }
446         KeReleaseSpinLockFromDpcLevel(&Process->HandleTable.ListLock);
447         KeReleaseSpinLock(&Parent->HandleTable.ListLock, oldIrql);
448      }
449 }
450
451
452 PVOID ObDeleteHandle(PEPROCESS Process, HANDLE Handle)
453 {
454    PHANDLE_REP Rep;
455    PVOID ObjectBody;
456    KIRQL oldIrql;
457    PHANDLE_TABLE HandleTable;
458    POBJECT_HEADER Header;
459    
460    DPRINT("ObDeleteHandle(Handle %x)\n",Handle);
461    
462    HandleTable = &Process->HandleTable;
463    
464    KeAcquireSpinLock(&HandleTable->ListLock, &oldIrql);
465    
466    Rep = ObpGetObjectByHandle(HandleTable, Handle);
467    if (Rep == NULL)
468      {
469         KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);     
470         return(NULL);
471      }
472    
473    ObjectBody = Rep->ObjectBody;
474    DPRINT("ObjectBody %x\n", ObjectBody);
475    if (ObjectBody != NULL)
476      {
477         Header = BODY_TO_HEADER(ObjectBody);
478         InterlockedDecrement(&(BODY_TO_HEADER(ObjectBody)->HandleCount));
479         ObReferenceObjectByPointer(ObjectBody,
480                                    0,
481                                    NULL,
482                                    UserMode);
483         Rep->ObjectBody = NULL;
484    
485         KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
486    
487         if ((Header->ObjectType != NULL) &&
488             (Header->ObjectType->Close != NULL))
489           {
490              Header->ObjectType->Close(ObjectBody, Header->HandleCount);
491           }
492      }
493    else
494      {
495         KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
496      }
497    
498    DPRINT("Finished ObDeleteHandle()\n");
499    return(ObjectBody);
500 }
501
502
503 NTSTATUS ObCreateHandle(PEPROCESS Process,
504                         PVOID ObjectBody,
505                         ACCESS_MASK GrantedAccess,
506                         BOOLEAN Inherit,
507                         PHANDLE HandleReturn)
508 /*
509  * FUNCTION: Add a handle referencing an object
510  * ARGUMENTS:
511  *         obj = Object body that the handle should refer to
512  * RETURNS: The created handle
513  * NOTE: The handle is valid only in the context of the current process
514  */
515 {
516    LIST_ENTRY* current;
517    unsigned int handle=1;
518    unsigned int i;
519    HANDLE_BLOCK* new_blk = NULL;
520    PHANDLE_TABLE HandleTable;
521    KIRQL oldlvl;
522
523    DPRINT("ObCreateHandle(Process %x, obj %x)\n",Process,ObjectBody);
524
525    assert(Process);
526
527    if (ObjectBody != NULL)
528      {
529         InterlockedIncrement(&(BODY_TO_HEADER(ObjectBody)->HandleCount));
530      }
531    HandleTable = &Process->HandleTable;
532    KeAcquireSpinLock(&HandleTable->ListLock, &oldlvl);
533    current = HandleTable->ListHead.Flink;
534    /*
535     * Scan through the currently allocated handle blocks looking for a free
536     * slot
537     */
538    while (current != (&HandleTable->ListHead))
539      {
540         HANDLE_BLOCK* blk = CONTAINING_RECORD(current,HANDLE_BLOCK,entry);
541
542         DPRINT("Current %x\n",current);
543
544         for (i=0;i<HANDLE_BLOCK_ENTRIES;i++)
545           {
546              DPRINT("Considering slot %d containing %x\n",i,blk->handles[i]);
547              if (blk->handles[i].ObjectBody==NULL)
548                {
549                   blk->handles[i].ObjectBody = ObjectBody;
550                   blk->handles[i].GrantedAccess = GrantedAccess;
551                   blk->handles[i].Inherit = Inherit;
552                   KeReleaseSpinLock(&HandleTable->ListLock, oldlvl);
553                   *HandleReturn = (HANDLE)((handle + i) << 2);
554                   return(STATUS_SUCCESS);
555                }
556           }
557         
558         handle = handle + HANDLE_BLOCK_ENTRIES;
559         current = current->Flink;
560      }
561
562    /*
563     * Add a new handle block to the end of the list
564     */
565    new_blk = 
566      (HANDLE_BLOCK *)ExAllocatePoolWithTag(NonPagedPool,sizeof(HANDLE_BLOCK),
567                                            TAG_HANDLE_TABLE);
568    if (!new_blk)
569     {
570       *HandleReturn = (PHANDLE)NULL;
571       return(STATUS_INSUFFICIENT_RESOURCES);
572     }
573    RtlZeroMemory(new_blk,sizeof(HANDLE_BLOCK));
574    InsertTailList(&(Process->HandleTable.ListHead),
575                   &new_blk->entry);
576    new_blk->handles[0].ObjectBody = ObjectBody;
577    new_blk->handles[0].GrantedAccess = GrantedAccess;
578    new_blk->handles[0].Inherit = Inherit;
579    KeReleaseSpinLock(&HandleTable->ListLock, oldlvl);
580    *HandleReturn = (HANDLE)(handle << 2);
581    return(STATUS_SUCCESS);
582 }
583
584
585 NTSTATUS STDCALL
586 ObReferenceObjectByHandle(HANDLE Handle,
587                           ACCESS_MASK DesiredAccess,
588                           POBJECT_TYPE ObjectType,
589                           KPROCESSOR_MODE AccessMode,
590                           PVOID* Object,
591                           POBJECT_HANDLE_INFORMATION HandleInformationPtr)
592 /*
593  * FUNCTION: Increments the reference count for an object and returns a 
594  * pointer to its body
595  * ARGUMENTS:
596  *         Handle = Handle for the object
597  *         DesiredAccess = Desired access to the object
598  *         ObjectType
599  *         AccessMode 
600  *         Object (OUT) = Points to the object body on return
601  *         HandleInformation (OUT) = Contains information about the handle 
602  *                                   on return
603  * RETURNS: Status
604  */
605 {
606    PHANDLE_REP HandleRep;
607    POBJECT_HEADER ObjectHeader;
608    KIRQL oldIrql;
609    PVOID ObjectBody;
610    ACCESS_MASK GrantedAccess;
611    
612    ASSERT_IRQL(PASSIVE_LEVEL);
613    
614    DPRINT("ObReferenceObjectByHandle(Handle %x, DesiredAccess %x, "
615            "ObjectType %x, AccessMode %d, Object %x)\n",Handle,DesiredAccess,
616            ObjectType,AccessMode,Object);
617
618    
619    /*
620     * Handle special handle names
621     */
622    if (Handle == NtCurrentProcess() && 
623        (ObjectType == PsProcessType || ObjectType == NULL))
624      {
625         DPRINT("Reference from %x\n", ((PULONG)&Handle)[-1]);
626         
627         ObReferenceObjectByPointer(PsGetCurrentProcess(),
628                                    PROCESS_ALL_ACCESS,
629                                    PsProcessType,
630                                    UserMode);
631         *Object = PsGetCurrentProcess();
632         DPRINT("Referencing current process %x\n", PsGetCurrentProcess());
633         return(STATUS_SUCCESS);
634      }
635    else if (Handle == NtCurrentProcess())
636      {
637         CHECKPOINT;
638         return(STATUS_OBJECT_TYPE_MISMATCH);
639      }
640    if (Handle == NtCurrentThread() && 
641        (ObjectType == PsThreadType || ObjectType == NULL))
642      {
643         ObReferenceObjectByPointer(PsGetCurrentThread(),
644                                    THREAD_ALL_ACCESS,
645                                    PsThreadType,
646                                    UserMode);
647         *Object = PsGetCurrentThread();
648         CHECKPOINT;
649         return(STATUS_SUCCESS);
650      }
651    else if (Handle == NtCurrentThread())
652      {
653         CHECKPOINT;
654         return(STATUS_OBJECT_TYPE_MISMATCH);
655      }
656    
657    KeAcquireSpinLock(&PsGetCurrentProcess()->HandleTable.ListLock,
658                      &oldIrql);
659    HandleRep = ObpGetObjectByHandle(&PsGetCurrentProcess()->HandleTable,
660                                     Handle);
661    if (HandleRep == NULL || HandleRep->ObjectBody == NULL)
662      {
663         KeReleaseSpinLock(&PsGetCurrentProcess()->HandleTable.ListLock,
664                           oldIrql);
665         return(STATUS_INVALID_HANDLE);
666      }
667    ObjectBody = HandleRep->ObjectBody;
668    DPRINT("ObjectBody %p\n",ObjectBody);
669    ObjectHeader = BODY_TO_HEADER(ObjectBody);
670    DPRINT("ObjectHeader->RefCount %lu\n",ObjectHeader->RefCount);
671    ObReferenceObjectByPointer(ObjectBody,
672                               0,
673                               NULL,
674                               UserMode);
675    GrantedAccess = HandleRep->GrantedAccess;
676    KeReleaseSpinLock(&PsGetCurrentProcess()->HandleTable.ListLock,
677                      oldIrql);
678    
679    ObjectHeader = BODY_TO_HEADER(ObjectBody);
680    DPRINT("ObjectHeader->RefCount %lu\n",ObjectHeader->RefCount);
681
682    if (ObjectType != NULL && ObjectType != ObjectHeader->ObjectType)
683      {
684         CHECKPOINT;
685         return(STATUS_OBJECT_TYPE_MISMATCH);
686      }
687    
688    if (ObjectHeader->ObjectType == PsProcessType)
689      {
690         DPRINT("Reference from %x\n", ((PULONG)&Handle)[-1]);
691      }
692    
693    if (AccessMode == UserMode)
694      {
695         RtlMapGenericMask(&DesiredAccess, ObjectHeader->ObjectType->Mapping);
696
697         if (!(GrantedAccess & DesiredAccess) &&
698             !((~GrantedAccess) & DesiredAccess))
699           {
700              CHECKPOINT;
701              return(STATUS_ACCESS_DENIED);
702           }
703      }
704    
705    *Object = ObjectBody;
706    
707    CHECKPOINT;
708    return(STATUS_SUCCESS);
709 }
710
711 /**********************************************************************
712  * NAME                                                 EXPORTED
713  *      NtClose
714  *      
715  * DESCRIPTION
716  *      Closes a handle reference to an object.
717  *      
718  * ARGUMENTS
719  *      Handle
720  *              Handle to close.
721  *              
722  * RETURN VALUE
723  *      Status.
724  */
725 NTSTATUS STDCALL NtClose(HANDLE Handle)
726 {
727    PVOID                ObjectBody;
728    POBJECT_HEADER       Header;
729    
730    assert_irql(PASSIVE_LEVEL);
731    
732    DPRINT("NtClose(Handle %x)\n",Handle);
733    
734    ObjectBody = ObDeleteHandle(PsGetCurrentProcess(), Handle);
735    if (ObjectBody == NULL)
736      {
737         return(STATUS_INVALID_HANDLE);
738      }
739    
740    Header = BODY_TO_HEADER(ObjectBody);
741    
742    DPRINT("Dereferencing %x\n", ObjectBody);
743    ObDereferenceObject(ObjectBody);
744    
745    return(STATUS_SUCCESS);
746 }
747
748 #ifndef LIBCAPTIVE
749
750 NTSTATUS STDCALL
751 ObInsertObject(PVOID Object,
752                PACCESS_STATE PassedAccessState,
753                ACCESS_MASK DesiredAccess,
754                ULONG AdditionalReferences,
755                PVOID* ReferencedObject,
756                PHANDLE Handle)
757 {
758   return(ObCreateHandle(PsGetCurrentProcess(),
759                         Object,
760                         DesiredAccess,
761                         FALSE,
762                         Handle));
763 }
764
765 #endif /* LIBCAPTIVE */
766
767 /* EOF */