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.37 2002/05/07 22:38:29 hbirr 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 #include <ddk/ntddk.h>
33 #include <internal/ob.h>
34 #include <internal/ps.h>
35 #include <internal/pool.h>
36 #include <internal/safe.h>
39 #include <internal/debug.h>
41 /* TYPES *******************************************************************/
44 * PURPOSE: Defines a handle
49 ACCESS_MASK GrantedAccess
;
51 } HANDLE_REP
, *PHANDLE_REP
;
53 #define HANDLE_BLOCK_ENTRIES ((PAGESIZE-sizeof(LIST_ENTRY))/sizeof(HANDLE_REP))
57 * PURPOSE: Defines a page's worth of handles
62 HANDLE_REP handles
[HANDLE_BLOCK_ENTRIES
];
63 } HANDLE_BLOCK
, *PHANDLE_BLOCK
;
66 /* GLOBALS *******************************************************************/
68 #define TAG_HANDLE_TABLE TAG('H', 'T', 'B', 'L')
70 /* FUNCTIONS ***************************************************************/
73 static PHANDLE_REP
ObpGetObjectByHandle(PHANDLE_TABLE HandleTable
, HANDLE h
)
75 * FUNCTION: Get the data structure for a handle
77 * Process = Process to get the handle for
79 * ARGUMENTS: A pointer to the information about the handle on success,
84 unsigned int handle
= (((unsigned int)h
) >> 2) - 1;
85 unsigned int count
=handle
/HANDLE_BLOCK_ENTRIES
;
86 HANDLE_BLOCK
* blk
= NULL
;
89 DPRINT("ObpGetObjectByHandle(HandleTable %x, h %x)\n",HandleTable
,h
);
91 current
= HandleTable
->ListHead
.Flink
;
92 DPRINT("current %x\n",current
);
96 current
= current
->Flink
;
97 if (current
== (&(HandleTable
->ListHead
)))
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
]));
109 NTSTATUS STDCALL
NtDuplicateObject (IN HANDLE SourceProcessHandle
,
110 IN HANDLE SourceHandle
,
111 IN HANDLE TargetProcessHandle
,
112 OUT PHANDLE UnsafeTargetHandle
,
113 IN ACCESS_MASK DesiredAccess
,
114 IN BOOLEAN InheritHandle
,
117 * FUNCTION: Copies a handle from one process space to another
119 * SourceProcessHandle = The source process owning the handle. The
120 * source process should have opened
121 * the SourceHandle with PROCESS_DUP_HANDLE
123 * SourceHandle = The handle to the object.
124 * TargetProcessHandle = The destination process owning the handle
125 * TargetHandle (OUT) = Caller should supply storage for the
127 * DesiredAccess = The desired access to the handle.
128 * InheritHandle = Indicates wheter the new handle will be inheritable
130 * Options = Specifies special actions upon duplicating the handle.
131 * Can be one of the values DUPLICATE_CLOSE_SOURCE |
132 * DUPLICATE_SAME_ACCESS. DUPLICATE_CLOSE_SOURCE specifies
133 * that the source handle should be closed after duplicating.
134 * DUPLICATE_SAME_ACCESS specifies to ignore the
135 * DesiredAccess paramter and just grant the same access to
138 * REMARKS: This function maps to the win32 DuplicateHandle.
141 PEPROCESS SourceProcess
;
142 PEPROCESS TargetProcess
;
143 PHANDLE_REP SourceHandleRep
;
149 ASSERT_IRQL(PASSIVE_LEVEL
);
151 Status
= ObReferenceObjectByHandle(SourceProcessHandle
,
155 (PVOID
*)&SourceProcess
,
157 if (!NT_SUCCESS(Status
))
161 Status
= ObReferenceObjectByHandle(TargetProcessHandle
,
165 (PVOID
*)&TargetProcess
,
167 if (!NT_SUCCESS(Status
))
169 ObDereferenceObject(SourceProcess
);
172 KeAcquireSpinLock(&SourceProcess
->HandleTable
.ListLock
, &oldIrql
);
173 SourceHandleRep
= ObpGetObjectByHandle(&SourceProcess
->HandleTable
,
175 if (SourceHandleRep
== NULL
)
177 KeReleaseSpinLock(&SourceProcess
->HandleTable
.ListLock
, oldIrql
);
178 ObDereferenceObject(SourceProcess
);
179 ObDereferenceObject(TargetProcess
);
180 return(STATUS_INVALID_HANDLE
);
182 ObjectBody
= SourceHandleRep
->ObjectBody
;
183 ObReferenceObjectByPointer(ObjectBody
,
188 if (Options
& DUPLICATE_SAME_ACCESS
)
190 DesiredAccess
= SourceHandleRep
->GrantedAccess
;
193 KeReleaseSpinLock(&SourceProcess
->HandleTable
.ListLock
, oldIrql
);
195 if (!SourceHandleRep
->Inherit
)
197 ObDereferenceObject(TargetProcess
);
198 ObDereferenceObject(SourceProcess
);
199 ObDereferenceObject(ObjectBody
);
200 return STATUS_INVALID_HANDLE
;
203 ObCreateHandle(TargetProcess
,
209 if (Options
& DUPLICATE_CLOSE_SOURCE
)
211 ZwClose(SourceHandle
);
214 ObDereferenceObject(TargetProcess
);
215 ObDereferenceObject(SourceProcess
);
216 ObDereferenceObject(ObjectBody
);
218 Status
= MmCopyToCaller(UnsafeTargetHandle
, &TargetHandle
, sizeof(HANDLE
));
219 if (!NT_SUCCESS(Status
))
224 return(STATUS_SUCCESS
);
227 VOID
ObCloseAllHandles(PEPROCESS Process
)
230 PHANDLE_TABLE HandleTable
;
231 PLIST_ENTRY current_entry
;
232 PHANDLE_BLOCK current
;
236 DPRINT("ObCloseAllHandles(Process %x)\n", Process
);
238 HandleTable
= &Process
->HandleTable
;
240 KeAcquireSpinLock(&HandleTable
->ListLock
, &oldIrql
);
242 current_entry
= HandleTable
->ListHead
.Flink
;
244 while (current_entry
!= &HandleTable
->ListHead
)
246 current
= CONTAINING_RECORD(current_entry
, HANDLE_BLOCK
, entry
);
248 for (i
= 0; i
< HANDLE_BLOCK_ENTRIES
; i
++)
250 ObjectBody
= current
->handles
[i
].ObjectBody
;
252 if (ObjectBody
!= NULL
)
254 POBJECT_HEADER Header
= BODY_TO_HEADER(ObjectBody
);
256 if (Header
->ObjectType
== PsProcessType
||
257 Header
->ObjectType
== PsThreadType
)
259 DPRINT("Deleting handle to %x\n", ObjectBody
);
262 ObReferenceObjectByPointer(ObjectBody
,
266 InterlockedDecrement(&Header
->HandleCount
);
267 current
->handles
[i
].ObjectBody
= NULL
;
269 KeReleaseSpinLock(&HandleTable
->ListLock
, oldIrql
);
272 if ((Header
->ObjectType
!= NULL
) &&
273 (Header
->ObjectType
->Close
!= NULL
))
275 Header
->ObjectType
->Close(ObjectBody
,
276 Header
->HandleCount
);
279 ObDereferenceObject(ObjectBody
);
280 KeAttachProcess( Process
);
281 KeAcquireSpinLock(&HandleTable
->ListLock
, &oldIrql
);
282 current_entry
= &HandleTable
->ListHead
;
287 current_entry
= current_entry
->Flink
;
289 KeReleaseSpinLock(&HandleTable
->ListLock
, oldIrql
);
290 DPRINT("ObCloseAllHandles() finished\n");
291 DPRINT("Type %x\n", BODY_TO_HEADER(Process
)->ObjectType
);
294 VOID
ObDeleteHandleTable(PEPROCESS Process
)
296 * FUNCTION: Deletes the handle table associated with a process
299 PLIST_ENTRY current
= NULL
;
300 PHANDLE_TABLE HandleTable
= NULL
;
302 ObCloseAllHandles(Process
);
304 HandleTable
= &Process
->HandleTable
;
305 current
= RemoveHeadList(&HandleTable
->ListHead
);
307 while (current
!= &HandleTable
->ListHead
)
309 HANDLE_BLOCK
* HandleBlock
= CONTAINING_RECORD(current
,
312 DPRINT("Freeing %x\n", HandleBlock
);
313 ExFreePool(HandleBlock
);
315 current
= RemoveHeadList(&HandleTable
->ListHead
);
320 VOID
ObCreateHandleTable(PEPROCESS Parent
,
324 * FUNCTION: Creates a handle table for a process
326 * Parent = Parent process (or NULL if this is the first process)
327 * Inherit = True if the process should inherit its parent's handles
328 * Process = Process whose handle table is to be created
331 PHANDLE_TABLE ParentHandleTable
, HandleTable
;
333 PLIST_ENTRY parent_current
;
335 PHANDLE_BLOCK current_block
, new_block
;
337 DPRINT("ObCreateHandleTable(Parent %x, Inherit %d, Process %x)\n",
338 Parent
,Inherit
,Process
);
340 InitializeListHead(&(Process
->HandleTable
.ListHead
));
341 KeInitializeSpinLock(&(Process
->HandleTable
.ListLock
));
345 ParentHandleTable
= &Parent
->HandleTable
;
346 HandleTable
= &Process
->HandleTable
;
348 KeAcquireSpinLock(&Parent
->HandleTable
.ListLock
, &oldIrql
);
349 KeAcquireSpinLockAtDpcLevel(&Process
->HandleTable
.ListLock
);
351 parent_current
= ParentHandleTable
->ListHead
.Flink
;
353 while (parent_current
!= &ParentHandleTable
->ListHead
)
355 current_block
= CONTAINING_RECORD(parent_current
,
358 new_block
= ExAllocatePoolWithTag(NonPagedPool
,
359 sizeof(HANDLE_BLOCK
),
361 if (new_block
== NULL
)
365 RtlZeroMemory(new_block
, sizeof(HANDLE_BLOCK
));
367 for (i
=0; i
<HANDLE_BLOCK_ENTRIES
; i
++)
369 if (current_block
->handles
[i
].ObjectBody
)
371 if (current_block
->handles
[i
].Inherit
&& Inherit
)
373 new_block
->handles
[i
].ObjectBody
= current_block
->handles
[i
].ObjectBody
;
374 new_block
->handles
[i
].GrantedAccess
= current_block
->handles
[i
].GrantedAccess
;
375 new_block
->handles
[i
].Inherit
= TRUE
;
376 InterlockedIncrement(&(BODY_TO_HEADER(current_block
->handles
[i
].ObjectBody
)->HandleCount
));
380 InsertTailList(&(Process
->HandleTable
.ListHead
), &new_block
->entry
);
381 parent_current
= parent_current
->Flink
;
383 KeReleaseSpinLockFromDpcLevel(&Process
->HandleTable
.ListLock
);
384 KeReleaseSpinLock(&Parent
->HandleTable
.ListLock
, oldIrql
);
389 PVOID
ObDeleteHandle(PEPROCESS Process
, HANDLE Handle
)
394 PHANDLE_TABLE HandleTable
;
395 POBJECT_HEADER Header
;
397 DPRINT("ObDeleteHandle(Handle %x)\n",Handle
);
399 HandleTable
= &Process
->HandleTable
;
401 KeAcquireSpinLock(&HandleTable
->ListLock
, &oldIrql
);
403 Rep
= ObpGetObjectByHandle(HandleTable
, Handle
);
406 KeReleaseSpinLock(&HandleTable
->ListLock
, oldIrql
);
410 ObjectBody
= Rep
->ObjectBody
;
411 DPRINT("ObjectBody %x\n", ObjectBody
);
412 if (ObjectBody
!= NULL
)
414 Header
= BODY_TO_HEADER(ObjectBody
);
415 InterlockedDecrement(&(BODY_TO_HEADER(ObjectBody
)->HandleCount
));
416 ObReferenceObjectByPointer(ObjectBody
,
420 Rep
->ObjectBody
= NULL
;
422 KeReleaseSpinLock(&HandleTable
->ListLock
, oldIrql
);
424 if ((Header
->ObjectType
!= NULL
) &&
425 (Header
->ObjectType
->Close
!= NULL
))
427 Header
->ObjectType
->Close(ObjectBody
, Header
->HandleCount
);
432 KeReleaseSpinLock(&HandleTable
->ListLock
, oldIrql
);
435 DPRINT("Finished ObDeleteHandle()\n");
440 NTSTATUS
ObCreateHandle(PEPROCESS Process
,
442 ACCESS_MASK GrantedAccess
,
444 PHANDLE HandleReturn
)
446 * FUNCTION: Add a handle referencing an object
448 * obj = Object body that the handle should refer to
449 * RETURNS: The created handle
450 * NOTE: The handle is valid only in the context of the current process
454 unsigned int handle
=1;
456 HANDLE_BLOCK
* new_blk
= NULL
;
457 PHANDLE_TABLE HandleTable
;
460 DPRINT("ObCreateHandle(Process %x, obj %x)\n",Process
,ObjectBody
);
464 if (ObjectBody
!= NULL
)
466 InterlockedIncrement(&(BODY_TO_HEADER(ObjectBody
)->HandleCount
));
468 HandleTable
= &Process
->HandleTable
;
469 KeAcquireSpinLock(&HandleTable
->ListLock
, &oldlvl
);
470 current
= HandleTable
->ListHead
.Flink
;
472 * Scan through the currently allocated handle blocks looking for a free
475 while (current
!= (&HandleTable
->ListHead
))
477 HANDLE_BLOCK
* blk
= CONTAINING_RECORD(current
,HANDLE_BLOCK
,entry
);
479 DPRINT("Current %x\n",current
);
481 for (i
=0;i
<HANDLE_BLOCK_ENTRIES
;i
++)
483 DPRINT("Considering slot %d containing %x\n",i
,blk
->handles
[i
]);
484 if (blk
->handles
[i
].ObjectBody
==NULL
)
486 blk
->handles
[i
].ObjectBody
= ObjectBody
;
487 blk
->handles
[i
].GrantedAccess
= GrantedAccess
;
488 blk
->handles
[i
].Inherit
= Inherit
;
489 KeReleaseSpinLock(&HandleTable
->ListLock
, oldlvl
);
490 *HandleReturn
= (HANDLE
)((handle
+ i
) << 2);
491 return(STATUS_SUCCESS
);
495 handle
= handle
+ HANDLE_BLOCK_ENTRIES
;
496 current
= current
->Flink
;
500 * Add a new handle block to the end of the list
503 (HANDLE_BLOCK
*)ExAllocatePoolWithTag(NonPagedPool
,sizeof(HANDLE_BLOCK
),
507 *HandleReturn
= (PHANDLE
)NULL
;
508 return(STATUS_INSUFFICIENT_RESOURCES
);
510 RtlZeroMemory(new_blk
,sizeof(HANDLE_BLOCK
));
511 InsertTailList(&(Process
->HandleTable
.ListHead
),
513 new_blk
->handles
[0].ObjectBody
= ObjectBody
;
514 new_blk
->handles
[0].GrantedAccess
= GrantedAccess
;
515 new_blk
->handles
[0].Inherit
= Inherit
;
516 KeReleaseSpinLock(&HandleTable
->ListLock
, oldlvl
);
517 *HandleReturn
= (HANDLE
)(handle
<< 2);
518 return(STATUS_SUCCESS
);
523 ObReferenceObjectByHandle(HANDLE Handle
,
524 ACCESS_MASK DesiredAccess
,
525 POBJECT_TYPE ObjectType
,
526 KPROCESSOR_MODE AccessMode
,
528 POBJECT_HANDLE_INFORMATION HandleInformationPtr
)
530 * FUNCTION: Increments the reference count for an object and returns a
531 * pointer to its body
533 * Handle = Handle for the object
534 * DesiredAccess = Desired access to the object
537 * Object (OUT) = Points to the object body on return
538 * HandleInformation (OUT) = Contains information about the handle
543 PHANDLE_REP HandleRep
;
544 POBJECT_HEADER ObjectHeader
;
547 ACCESS_MASK GrantedAccess
;
549 ASSERT_IRQL(PASSIVE_LEVEL
);
551 DPRINT("ObReferenceObjectByHandle(Handle %x, DesiredAccess %x, "
552 "ObjectType %x, AccessMode %d, Object %x)\n",Handle
,DesiredAccess
,
553 ObjectType
,AccessMode
,Object
);
557 * Handle special handle names
559 if (Handle
== NtCurrentProcess() &&
560 (ObjectType
== PsProcessType
|| ObjectType
== NULL
))
562 DPRINT("Reference from %x\n", ((PULONG
)&Handle
)[-1]);
564 ObReferenceObjectByPointer(PsGetCurrentProcess(),
568 *Object
= PsGetCurrentProcess();
569 DPRINT("Referencing current process %x\n", PsGetCurrentProcess());
570 return(STATUS_SUCCESS
);
572 else if (Handle
== NtCurrentProcess())
575 return(STATUS_OBJECT_TYPE_MISMATCH
);
577 if (Handle
== NtCurrentThread() &&
578 (ObjectType
== PsThreadType
|| ObjectType
== NULL
))
580 ObReferenceObjectByPointer(PsGetCurrentThread(),
584 *Object
= PsGetCurrentThread();
586 return(STATUS_SUCCESS
);
588 else if (Handle
== NtCurrentThread())
591 return(STATUS_OBJECT_TYPE_MISMATCH
);
594 KeAcquireSpinLock(&PsGetCurrentProcess()->HandleTable
.ListLock
,
596 HandleRep
= ObpGetObjectByHandle(&PsGetCurrentProcess()->HandleTable
,
598 if (HandleRep
== NULL
|| HandleRep
->ObjectBody
== NULL
)
600 KeReleaseSpinLock(&PsGetCurrentProcess()->HandleTable
.ListLock
,
602 return(STATUS_INVALID_HANDLE
);
604 ObjectBody
= HandleRep
->ObjectBody
;
605 DPRINT("ObjectBody %p\n",ObjectBody
);
606 ObjectHeader
= BODY_TO_HEADER(ObjectBody
);
607 DPRINT("ObjectHeader->RefCount %lu\n",ObjectHeader
->RefCount
);
608 ObReferenceObjectByPointer(ObjectBody
,
612 GrantedAccess
= HandleRep
->GrantedAccess
;
613 KeReleaseSpinLock(&PsGetCurrentProcess()->HandleTable
.ListLock
,
616 ObjectHeader
= BODY_TO_HEADER(ObjectBody
);
617 DPRINT("ObjectHeader->RefCount %lu\n",ObjectHeader
->RefCount
);
619 if (ObjectType
!= NULL
&& ObjectType
!= ObjectHeader
->ObjectType
)
622 return(STATUS_OBJECT_TYPE_MISMATCH
);
625 if (ObjectHeader
->ObjectType
== PsProcessType
)
627 DPRINT("Reference from %x\n", ((PULONG
)&Handle
)[-1]);
630 if (AccessMode
== UserMode
)
632 RtlMapGenericMask(&DesiredAccess
, ObjectHeader
->ObjectType
->Mapping
);
634 if (!(GrantedAccess
& DesiredAccess
) &&
635 !((~GrantedAccess
) & DesiredAccess
))
638 return(STATUS_ACCESS_DENIED
);
642 *Object
= ObjectBody
;
645 return(STATUS_SUCCESS
);
649 /**********************************************************************
654 * Closes a handle reference to an object.
663 NTSTATUS STDCALL
NtClose(HANDLE Handle
)
666 POBJECT_HEADER Header
;
668 assert_irql(PASSIVE_LEVEL
);
670 DPRINT("NtClose(Handle %x)\n",Handle
);
672 ObjectBody
= ObDeleteHandle(PsGetCurrentProcess(), Handle
);
673 if (ObjectBody
== NULL
)
675 return(STATUS_INVALID_HANDLE
);
678 Header
= BODY_TO_HEADER(ObjectBody
);
680 DPRINT("Dereferencing %x\n", ObjectBody
);
681 ObDereferenceObject(ObjectBody
);
683 return(STATUS_SUCCESS
);
687 ObInsertObject(PVOID Object
,
688 PACCESS_STATE PassedAccessState
,
689 ACCESS_MASK DesiredAccess
,
690 ULONG AdditionalReferences
,
691 PVOID
* ReferencedObject
,
694 return(ObCreateHandle(PsGetCurrentProcess(),