3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
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.
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.
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.
19 /* $Id: handle.c,v 1.47 2003/07/10 21:34:29 royce Exp $
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)
30 /* INCLUDES ****************************************************************/
32 #define NTOS_MODE_KERNEL
34 #include <internal/ob.h>
35 #include <internal/ps.h>
36 #include <internal/pool.h>
37 #include <internal/safe.h>
40 #include <internal/debug.h>
42 /* TYPES *******************************************************************/
45 * PURPOSE: Defines a handle
50 ACCESS_MASK GrantedAccess
;
52 } HANDLE_REP
, *PHANDLE_REP
;
54 #define HANDLE_BLOCK_ENTRIES ((PAGE_SIZE-sizeof(LIST_ENTRY))/sizeof(HANDLE_REP))
58 * PURPOSE: Defines a page's worth of handles
63 HANDLE_REP handles
[HANDLE_BLOCK_ENTRIES
];
64 } HANDLE_BLOCK
, *PHANDLE_BLOCK
;
67 /* GLOBALS *******************************************************************/
69 #define TAG_HANDLE_TABLE TAG('H', 'T', 'B', 'L')
71 /* FUNCTIONS ***************************************************************/
74 static PHANDLE_REP
ObpGetObjectByHandle(PHANDLE_TABLE HandleTable
, HANDLE h
)
76 * FUNCTION: Get the data structure for a handle
78 * Process = Process to get the handle for
80 * ARGUMENTS: A pointer to the information about the handle on success,
85 unsigned int handle
= (((unsigned int)h
) >> 2) - 1;
86 unsigned int count
=handle
/HANDLE_BLOCK_ENTRIES
;
87 HANDLE_BLOCK
* blk
= NULL
;
90 DPRINT("ObpGetObjectByHandle(HandleTable %x, h %x)\n",HandleTable
,h
);
92 current
= HandleTable
->ListHead
.Flink
;
93 DPRINT("current %x\n",current
);
97 current
= current
->Flink
;
98 if (current
== (&(HandleTable
->ListHead
)))
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
]));
110 ObDuplicateObject(PEPROCESS SourceProcess
,
111 PEPROCESS TargetProcess
,
113 PHANDLE TargetHandle
,
114 ACCESS_MASK DesiredAccess
,
115 BOOLEAN InheritHandle
,
119 PHANDLE_REP SourceHandleRep
;
122 KeAcquireSpinLock(&SourceProcess
->HandleTable
.ListLock
, &oldIrql
);
123 SourceHandleRep
= ObpGetObjectByHandle(&SourceProcess
->HandleTable
,
125 if (SourceHandleRep
== NULL
)
127 KeReleaseSpinLock(&SourceProcess
->HandleTable
.ListLock
, oldIrql
);
128 return(STATUS_INVALID_HANDLE
);
130 ObjectBody
= SourceHandleRep
->ObjectBody
;
131 ObReferenceObjectByPointer(ObjectBody
,
136 if (Options
& DUPLICATE_SAME_ACCESS
)
138 DesiredAccess
= SourceHandleRep
->GrantedAccess
;
141 KeReleaseSpinLock(&SourceProcess
->HandleTable
.ListLock
, oldIrql
);
142 ObCreateHandle(TargetProcess
,
148 if (Options
& DUPLICATE_CLOSE_SOURCE
)
150 ZwClose(SourceHandle
);
153 ObDereferenceObject(ObjectBody
);
154 return(STATUS_SUCCESS
);
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
,
169 * FUNCTION: Copies a handle from one process space to another
171 * SourceProcessHandle = The source process owning the handle. The
172 * source process should have opened
173 * the SourceHandle with PROCESS_DUP_HANDLE
175 * SourceHandle = The handle to the object.
176 * TargetProcessHandle = The destination process owning the handle
177 * TargetHandle (OUT) = Caller should supply storage for the
179 * DesiredAccess = The desired access to the handle.
180 * InheritHandle = Indicates wheter the new handle will be inheritable
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
190 * REMARKS: This function maps to the win32 DuplicateHandle.
193 PEPROCESS SourceProcess
;
194 PEPROCESS TargetProcess
;
195 PHANDLE_REP SourceHandleRep
;
201 ASSERT_IRQL(PASSIVE_LEVEL
);
203 Status
= ObReferenceObjectByHandle(SourceProcessHandle
,
207 (PVOID
*)&SourceProcess
,
209 if (!NT_SUCCESS(Status
))
213 Status
= ObReferenceObjectByHandle(TargetProcessHandle
,
217 (PVOID
*)&TargetProcess
,
219 if (!NT_SUCCESS(Status
))
221 ObDereferenceObject(SourceProcess
);
225 /* Check for magic handle first */
226 if (SourceHandle
== NtCurrentThread())
228 ObReferenceObjectByHandle(SourceHandle
,
235 ObCreateHandle(TargetProcess
,
243 KeAcquireSpinLock(&SourceProcess
->HandleTable
.ListLock
, &oldIrql
);
244 SourceHandleRep
= ObpGetObjectByHandle(&SourceProcess
->HandleTable
,
246 if (SourceHandleRep
== NULL
)
248 KeReleaseSpinLock(&SourceProcess
->HandleTable
.ListLock
, oldIrql
);
249 ObDereferenceObject(SourceProcess
);
250 ObDereferenceObject(TargetProcess
);
251 return(STATUS_INVALID_HANDLE
);
253 ObjectBody
= SourceHandleRep
->ObjectBody
;
254 ObReferenceObjectByPointer(ObjectBody
,
259 if (Options
& DUPLICATE_SAME_ACCESS
)
261 DesiredAccess
= SourceHandleRep
->GrantedAccess
;
264 KeReleaseSpinLock(&SourceProcess
->HandleTable
.ListLock
, oldIrql
);
265 if (!SourceHandleRep
->Inherit
)
267 ObDereferenceObject(TargetProcess
);
268 ObDereferenceObject(SourceProcess
);
269 ObDereferenceObject(ObjectBody
);
270 return STATUS_INVALID_HANDLE
;
272 ObCreateHandle(TargetProcess
,
279 if (Options
& DUPLICATE_CLOSE_SOURCE
)
281 ZwClose(SourceHandle
);
284 ObDereferenceObject(TargetProcess
);
285 ObDereferenceObject(SourceProcess
);
286 ObDereferenceObject(ObjectBody
);
288 Status
= MmCopyToCaller(UnsafeTargetHandle
, &TargetHandle
, sizeof(HANDLE
));
289 if (!NT_SUCCESS(Status
))
294 return(STATUS_SUCCESS
);
297 VOID
ObCloseAllHandles(PEPROCESS Process
)
300 PHANDLE_TABLE HandleTable
;
301 PLIST_ENTRY current_entry
;
302 PHANDLE_BLOCK current
;
305 BOOLEAN IsProcessHandle
;
307 DPRINT("ObCloseAllHandles(Process %x)\n", Process
);
309 HandleTable
= &Process
->HandleTable
;
311 KeAcquireSpinLock(&HandleTable
->ListLock
, &oldIrql
);
313 current_entry
= HandleTable
->ListHead
.Flink
;
315 while (current_entry
!= &HandleTable
->ListHead
)
317 current
= CONTAINING_RECORD(current_entry
, HANDLE_BLOCK
, entry
);
319 for (i
= 0; i
< HANDLE_BLOCK_ENTRIES
; i
++)
321 ObjectBody
= current
->handles
[i
].ObjectBody
;
323 if (ObjectBody
!= NULL
)
325 POBJECT_HEADER Header
= BODY_TO_HEADER(ObjectBody
);
327 if (Header
->ObjectType
== PsProcessType
||
328 Header
->ObjectType
== PsThreadType
)
330 DPRINT("Deleting handle to %x\n", ObjectBody
);
333 ObReferenceObjectByPointer(ObjectBody
,
337 InterlockedDecrement(&Header
->HandleCount
);
338 current
->handles
[i
].ObjectBody
= NULL
;
340 KeReleaseSpinLock(&HandleTable
->ListLock
, oldIrql
);
342 if (Header
->ObjectType
== PsProcessType
)
344 IsProcessHandle
= TRUE
;
349 IsProcessHandle
= FALSE
;
351 if ((Header
->ObjectType
!= NULL
) &&
352 (Header
->ObjectType
->Close
!= NULL
))
354 Header
->ObjectType
->Close(ObjectBody
,
355 Header
->HandleCount
);
358 ObDereferenceObject(ObjectBody
);
361 KeAttachProcess(Process
);
363 KeAcquireSpinLock(&HandleTable
->ListLock
, &oldIrql
);
364 current_entry
= &HandleTable
->ListHead
;
369 current_entry
= current_entry
->Flink
;
371 KeReleaseSpinLock(&HandleTable
->ListLock
, oldIrql
);
372 DPRINT("ObCloseAllHandles() finished\n");
373 DPRINT("Type %x\n", BODY_TO_HEADER(Process
)->ObjectType
);
376 VOID
ObDeleteHandleTable(PEPROCESS Process
)
378 * FUNCTION: Deletes the handle table associated with a process
381 PLIST_ENTRY current
= NULL
;
382 PHANDLE_TABLE HandleTable
= NULL
;
384 ObCloseAllHandles(Process
);
386 HandleTable
= &Process
->HandleTable
;
387 current
= RemoveHeadList(&HandleTable
->ListHead
);
389 while (current
!= &HandleTable
->ListHead
)
391 HANDLE_BLOCK
* HandleBlock
= CONTAINING_RECORD(current
,
394 DPRINT("Freeing %x\n", HandleBlock
);
395 ExFreePool(HandleBlock
);
397 current
= RemoveHeadList(&HandleTable
->ListHead
);
402 VOID
ObCreateHandleTable(PEPROCESS Parent
,
406 * FUNCTION: Creates a handle table for a process
408 * Parent = Parent process (or NULL if this is the first process)
409 * Inherit = True if the process should inherit its parent's handles
410 * Process = Process whose handle table is to be created
413 PHANDLE_TABLE ParentHandleTable
, HandleTable
;
415 PLIST_ENTRY parent_current
;
417 PHANDLE_BLOCK current_block
, new_block
;
419 DPRINT("ObCreateHandleTable(Parent %x, Inherit %d, Process %x)\n",
420 Parent
,Inherit
,Process
);
422 InitializeListHead(&(Process
->HandleTable
.ListHead
));
423 KeInitializeSpinLock(&(Process
->HandleTable
.ListLock
));
427 ParentHandleTable
= &Parent
->HandleTable
;
428 HandleTable
= &Process
->HandleTable
;
430 KeAcquireSpinLock(&Parent
->HandleTable
.ListLock
, &oldIrql
);
431 KeAcquireSpinLockAtDpcLevel(&Process
->HandleTable
.ListLock
);
433 parent_current
= ParentHandleTable
->ListHead
.Flink
;
435 while (parent_current
!= &ParentHandleTable
->ListHead
)
437 current_block
= CONTAINING_RECORD(parent_current
,
440 new_block
= ExAllocatePoolWithTag(NonPagedPool
,
441 sizeof(HANDLE_BLOCK
),
443 if (new_block
== NULL
)
447 RtlZeroMemory(new_block
, sizeof(HANDLE_BLOCK
));
449 for (i
=0; i
<HANDLE_BLOCK_ENTRIES
; i
++)
451 if (current_block
->handles
[i
].ObjectBody
)
453 if (current_block
->handles
[i
].Inherit
&& Inherit
)
455 new_block
->handles
[i
].ObjectBody
=
456 current_block
->handles
[i
].ObjectBody
;
457 new_block
->handles
[i
].GrantedAccess
=
458 current_block
->handles
[i
].GrantedAccess
;
459 new_block
->handles
[i
].Inherit
= TRUE
;
460 InterlockedIncrement(&(BODY_TO_HEADER(current_block
->handles
[i
].ObjectBody
)->HandleCount
));
464 InsertTailList(&Process
->HandleTable
.ListHead
, &new_block
->entry
);
465 parent_current
= parent_current
->Flink
;
467 KeReleaseSpinLockFromDpcLevel(&Process
->HandleTable
.ListLock
);
468 KeReleaseSpinLock(&Parent
->HandleTable
.ListLock
, oldIrql
);
473 PVOID
ObDeleteHandle(PEPROCESS Process
, HANDLE Handle
)
478 PHANDLE_TABLE HandleTable
;
479 POBJECT_HEADER Header
;
481 DPRINT("ObDeleteHandle(Handle %x)\n",Handle
);
483 HandleTable
= &Process
->HandleTable
;
485 KeAcquireSpinLock(&HandleTable
->ListLock
, &oldIrql
);
487 Rep
= ObpGetObjectByHandle(HandleTable
, Handle
);
490 KeReleaseSpinLock(&HandleTable
->ListLock
, oldIrql
);
494 ObjectBody
= Rep
->ObjectBody
;
495 DPRINT("ObjectBody %x\n", ObjectBody
);
496 if (ObjectBody
!= NULL
)
498 Header
= BODY_TO_HEADER(ObjectBody
);
499 InterlockedDecrement(&(BODY_TO_HEADER(ObjectBody
)->HandleCount
));
500 ObReferenceObjectByPointer(ObjectBody
,
504 Rep
->ObjectBody
= NULL
;
506 KeReleaseSpinLock(&HandleTable
->ListLock
, oldIrql
);
508 if ((Header
->ObjectType
!= NULL
) &&
509 (Header
->ObjectType
->Close
!= NULL
))
511 Header
->ObjectType
->Close(ObjectBody
, Header
->HandleCount
);
516 KeReleaseSpinLock(&HandleTable
->ListLock
, oldIrql
);
519 DPRINT("Finished ObDeleteHandle()\n");
524 NTSTATUS
ObCreateHandle(PEPROCESS Process
,
526 ACCESS_MASK GrantedAccess
,
528 PHANDLE HandleReturn
)
530 * FUNCTION: Add a handle referencing an object
532 * obj = Object body that the handle should refer to
533 * RETURNS: The created handle
534 * NOTE: The handle is valid only in the context of the current process
538 unsigned int handle
=1;
540 HANDLE_BLOCK
* new_blk
= NULL
;
541 PHANDLE_TABLE HandleTable
;
544 DPRINT("ObCreateHandle(Process %x, obj %x)\n",Process
,ObjectBody
);
548 if (ObjectBody
!= NULL
)
550 InterlockedIncrement(&(BODY_TO_HEADER(ObjectBody
)->HandleCount
));
552 HandleTable
= &Process
->HandleTable
;
553 KeAcquireSpinLock(&HandleTable
->ListLock
, &oldlvl
);
554 current
= HandleTable
->ListHead
.Flink
;
556 * Scan through the currently allocated handle blocks looking for a free
559 while (current
!= (&HandleTable
->ListHead
))
561 HANDLE_BLOCK
* blk
= CONTAINING_RECORD(current
,HANDLE_BLOCK
,entry
);
563 DPRINT("Current %x\n",current
);
565 for (i
=0;i
<HANDLE_BLOCK_ENTRIES
;i
++)
567 DPRINT("Considering slot %d containing %x\n",i
,blk
->handles
[i
]);
568 if (blk
->handles
[i
].ObjectBody
==NULL
)
570 blk
->handles
[i
].ObjectBody
= ObjectBody
;
571 blk
->handles
[i
].GrantedAccess
= GrantedAccess
;
572 blk
->handles
[i
].Inherit
= Inherit
;
573 KeReleaseSpinLock(&HandleTable
->ListLock
, oldlvl
);
574 *HandleReturn
= (HANDLE
)((handle
+ i
) << 2);
575 return(STATUS_SUCCESS
);
579 handle
= handle
+ HANDLE_BLOCK_ENTRIES
;
580 current
= current
->Flink
;
584 * Add a new handle block to the end of the list
587 (HANDLE_BLOCK
*)ExAllocatePoolWithTag(NonPagedPool
,sizeof(HANDLE_BLOCK
),
591 *HandleReturn
= (PHANDLE
)NULL
;
592 return(STATUS_INSUFFICIENT_RESOURCES
);
594 RtlZeroMemory(new_blk
,sizeof(HANDLE_BLOCK
));
595 InsertTailList(&(Process
->HandleTable
.ListHead
),
597 new_blk
->handles
[0].ObjectBody
= ObjectBody
;
598 new_blk
->handles
[0].GrantedAccess
= GrantedAccess
;
599 new_blk
->handles
[0].Inherit
= Inherit
;
600 KeReleaseSpinLock(&HandleTable
->ListLock
, oldlvl
);
601 *HandleReturn
= (HANDLE
)(handle
<< 2);
602 return(STATUS_SUCCESS
);
610 ObReferenceObjectByHandle(HANDLE Handle
,
611 ACCESS_MASK DesiredAccess
,
612 POBJECT_TYPE ObjectType
,
613 KPROCESSOR_MODE AccessMode
,
615 POBJECT_HANDLE_INFORMATION HandleInformationPtr
)
617 * FUNCTION: Increments the reference count for an object and returns a
618 * pointer to its body
620 * Handle = Handle for the object
621 * DesiredAccess = Desired access to the object
624 * Object (OUT) = Points to the object body on return
625 * HandleInformation (OUT) = Contains information about the handle
630 PHANDLE_REP HandleRep
;
631 POBJECT_HEADER ObjectHeader
;
634 ACCESS_MASK GrantedAccess
;
637 ASSERT_IRQL(PASSIVE_LEVEL
);
639 DPRINT("ObReferenceObjectByHandle(Handle %x, DesiredAccess %x, "
640 "ObjectType %x, AccessMode %d, Object %x)\n",Handle
,DesiredAccess
,
641 ObjectType
,AccessMode
,Object
);
645 * Handle special handle names
647 if (Handle
== NtCurrentProcess() &&
648 (ObjectType
== PsProcessType
|| ObjectType
== NULL
))
650 DPRINT("Reference from %x\n", ((PULONG
)&Handle
)[-1]);
652 Status
= ObReferenceObjectByPointer(PsGetCurrentProcess(),
656 if (! NT_SUCCESS(Status
))
661 *Object
= PsGetCurrentProcess();
662 DPRINT("Referencing current process %x\n", PsGetCurrentProcess());
663 return STATUS_SUCCESS
;
665 else if (Handle
== NtCurrentProcess())
668 return(STATUS_OBJECT_TYPE_MISMATCH
);
670 if (Handle
== NtCurrentThread() &&
671 (ObjectType
== PsThreadType
|| ObjectType
== NULL
))
673 Status
= ObReferenceObjectByPointer(PsGetCurrentThread(),
677 if (! NT_SUCCESS(Status
))
682 *Object
= PsGetCurrentThread();
684 return STATUS_SUCCESS
;
686 else if (Handle
== NtCurrentThread())
689 return(STATUS_OBJECT_TYPE_MISMATCH
);
692 KeAcquireSpinLock(&PsGetCurrentProcess()->HandleTable
.ListLock
,
694 HandleRep
= ObpGetObjectByHandle(&PsGetCurrentProcess()->HandleTable
,
696 if (HandleRep
== NULL
|| HandleRep
->ObjectBody
== NULL
)
698 KeReleaseSpinLock(&PsGetCurrentProcess()->HandleTable
.ListLock
,
700 return(STATUS_INVALID_HANDLE
);
702 ObjectBody
= HandleRep
->ObjectBody
;
703 DPRINT("ObjectBody %p\n",ObjectBody
);
704 ObjectHeader
= BODY_TO_HEADER(ObjectBody
);
705 DPRINT("ObjectHeader->RefCount %lu\n",ObjectHeader
->RefCount
);
706 ObReferenceObjectByPointer(ObjectBody
,
710 GrantedAccess
= HandleRep
->GrantedAccess
;
711 KeReleaseSpinLock(&PsGetCurrentProcess()->HandleTable
.ListLock
,
714 ObjectHeader
= BODY_TO_HEADER(ObjectBody
);
715 DPRINT("ObjectHeader->RefCount %lu\n",ObjectHeader
->RefCount
);
717 if (ObjectType
!= NULL
&& ObjectType
!= ObjectHeader
->ObjectType
)
720 return(STATUS_OBJECT_TYPE_MISMATCH
);
723 if (ObjectHeader
->ObjectType
== PsProcessType
)
725 DPRINT("Reference from %x\n", ((PULONG
)&Handle
)[-1]);
728 if (DesiredAccess
&& AccessMode
== UserMode
)
730 RtlMapGenericMask(&DesiredAccess
, ObjectHeader
->ObjectType
->Mapping
);
732 if (!(GrantedAccess
& DesiredAccess
) &&
733 !((~GrantedAccess
) & DesiredAccess
))
736 return(STATUS_ACCESS_DENIED
);
740 *Object
= ObjectBody
;
743 return(STATUS_SUCCESS
);
747 /**********************************************************************
752 * Closes a handle reference to an object.
763 NTSTATUS STDCALL
NtClose(HANDLE Handle
)
766 POBJECT_HEADER Header
;
768 assert_irql(PASSIVE_LEVEL
);
770 DPRINT("NtClose(Handle %x)\n",Handle
);
772 ObjectBody
= ObDeleteHandle(PsGetCurrentProcess(), Handle
);
773 if (ObjectBody
== NULL
)
775 return(STATUS_INVALID_HANDLE
);
778 Header
= BODY_TO_HEADER(ObjectBody
);
780 DPRINT("Dereferencing %x\n", ObjectBody
);
781 ObDereferenceObject(ObjectBody
);
783 return(STATUS_SUCCESS
);
790 ObInsertObject(PVOID Object
,
791 PACCESS_STATE PassedAccessState
,
792 ACCESS_MASK DesiredAccess
,
793 ULONG AdditionalReferences
,
794 PVOID
* ReferencedObject
,
797 return(ObCreateHandle(PsGetCurrentProcess(),