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