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.34 2001/12/31 19:06:48 dwelch 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 *******************************************************************/
43 #define HANDLE_BLOCK_ENTRIES ((PAGESIZE-sizeof(LIST_ENTRY))/sizeof(HANDLE_REP))
46 * PURPOSE: Defines a page's worth of handles
51 HANDLE_REP handles
[HANDLE_BLOCK_ENTRIES
];
52 } HANDLE_BLOCK
, *PHANDLE_BLOCK
;
54 /* GLOBALS *******************************************************************/
56 #define TAG_HANDLE_TABLE TAG('H', 'T', 'B', 'L')
58 /* FUNCTIONS ***************************************************************/
61 static PHANDLE_REP
ObpGetObjectByHandle(PHANDLE_TABLE HandleTable
, HANDLE h
)
63 * FUNCTION: Get the data structure for a handle
65 * Process = Process to get the handle for
67 * ARGUMENTS: A pointer to the information about the handle on success,
72 unsigned int handle
= (((unsigned int)h
) - 1) >> 2;
73 unsigned int count
=handle
/HANDLE_BLOCK_ENTRIES
;
74 HANDLE_BLOCK
* blk
= NULL
;
77 DPRINT("ObpGetObjectByHandle(HandleTable %x, h %x)\n",HandleTable
,h
);
79 current
= HandleTable
->ListHead
.Flink
;
80 DPRINT("current %x\n",current
);
84 current
= current
->Flink
;
85 if (current
== (&(HandleTable
->ListHead
)))
91 blk
= CONTAINING_RECORD(current
,HANDLE_BLOCK
,entry
);
92 DPRINT("object: %p\n",&(blk
->handles
[handle
%HANDLE_BLOCK_ENTRIES
]));
93 return(&(blk
->handles
[handle
%HANDLE_BLOCK_ENTRIES
]));
97 NTSTATUS STDCALL
NtDuplicateObject (IN HANDLE SourceProcessHandle
,
98 IN HANDLE SourceHandle
,
99 IN HANDLE TargetProcessHandle
,
100 OUT PHANDLE UnsafeTargetHandle
,
101 IN ACCESS_MASK DesiredAccess
,
102 IN BOOLEAN InheritHandle
,
105 * FUNCTION: Copies a handle from one process space to another
107 * SourceProcessHandle = The source process owning the handle. The
108 * source process should have opened
109 * the SourceHandle with PROCESS_DUP_HANDLE
111 * SourceHandle = The handle to the object.
112 * TargetProcessHandle = The destination process owning the handle
113 * TargetHandle (OUT) = Caller should supply storage for the
115 * DesiredAccess = The desired access to the handle.
116 * InheritHandle = Indicates wheter the new handle will be inheritable
118 * Options = Specifies special actions upon duplicating the handle.
119 * Can be one of the values DUPLICATE_CLOSE_SOURCE |
120 * DUPLICATE_SAME_ACCESS. DUPLICATE_CLOSE_SOURCE specifies
121 * that the source handle should be closed after duplicating.
122 * DUPLICATE_SAME_ACCESS specifies to ignore the
123 * DesiredAccess paramter and just grant the same access to
126 * REMARKS: This function maps to the win32 DuplicateHandle.
129 PEPROCESS SourceProcess
;
130 PEPROCESS TargetProcess
;
131 PHANDLE_REP SourceHandleRep
;
137 ASSERT_IRQL(PASSIVE_LEVEL
);
139 Status
= ObReferenceObjectByHandle(SourceProcessHandle
,
143 (PVOID
*)&SourceProcess
,
145 if (!NT_SUCCESS(Status
))
149 Status
= ObReferenceObjectByHandle(TargetProcessHandle
,
153 (PVOID
*)&TargetProcess
,
155 if (!NT_SUCCESS(Status
))
157 ObDereferenceObject(SourceProcess
);
160 KeAcquireSpinLock(&SourceProcess
->HandleTable
.ListLock
, &oldIrql
);
161 SourceHandleRep
= ObpGetObjectByHandle(&SourceProcess
->HandleTable
,
163 if (SourceHandleRep
== NULL
)
165 KeReleaseSpinLock(&SourceProcess
->HandleTable
.ListLock
, oldIrql
);
166 ObDereferenceObject(SourceProcess
);
167 ObDereferenceObject(TargetProcess
);
168 return(STATUS_INVALID_HANDLE
);
170 ObjectBody
= SourceHandleRep
->ObjectBody
;
171 ObReferenceObjectByPointer(ObjectBody
,
176 if (Options
& DUPLICATE_SAME_ACCESS
)
178 DesiredAccess
= SourceHandleRep
->GrantedAccess
;
181 KeReleaseSpinLock(&SourceProcess
->HandleTable
.ListLock
, oldIrql
);
183 ObCreateHandle(TargetProcess
,
189 if (Options
& DUPLICATE_CLOSE_SOURCE
)
191 ZwClose(SourceHandle
);
194 ObDereferenceObject(TargetProcess
);
195 ObDereferenceObject(SourceProcess
);
196 ObDereferenceObject(ObjectBody
);
198 Status
= MmCopyToCaller(UnsafeTargetHandle
, &TargetHandle
, sizeof(HANDLE
));
199 if (!NT_SUCCESS(Status
))
204 return(STATUS_SUCCESS
);
207 VOID
ObCloseAllHandles(PEPROCESS Process
)
210 PHANDLE_TABLE HandleTable
;
211 PLIST_ENTRY current_entry
;
212 PHANDLE_BLOCK current
;
216 DPRINT("ObCloseAllHandles(Process %x)\n", Process
);
218 HandleTable
= &Process
->HandleTable
;
220 KeAcquireSpinLock(&HandleTable
->ListLock
, &oldIrql
);
222 current_entry
= HandleTable
->ListHead
.Flink
;
224 while (current_entry
!= &HandleTable
->ListHead
)
226 current
= CONTAINING_RECORD(current_entry
, HANDLE_BLOCK
, entry
);
228 for (i
= 0; i
< HANDLE_BLOCK_ENTRIES
; i
++)
230 ObjectBody
= current
->handles
[i
].ObjectBody
;
232 if (ObjectBody
!= NULL
)
234 POBJECT_HEADER Header
= BODY_TO_HEADER(ObjectBody
);
236 if (Header
->ObjectType
== PsProcessType
||
237 Header
->ObjectType
== PsThreadType
)
239 DPRINT("Deleting handle to %x\n", ObjectBody
);
242 ObReferenceObjectByPointer(ObjectBody
,
246 Header
->HandleCount
--;
247 current
->handles
[i
].ObjectBody
= NULL
;
249 KeReleaseSpinLock(&HandleTable
->ListLock
, oldIrql
);
251 if ((Header
->ObjectType
!= NULL
) &&
252 (Header
->ObjectType
->Close
!= NULL
))
254 Header
->ObjectType
->Close(ObjectBody
,
255 Header
->HandleCount
);
258 ObDereferenceObject(ObjectBody
);
259 KeAcquireSpinLock(&HandleTable
->ListLock
, &oldIrql
);
260 current_entry
= &HandleTable
->ListHead
;
265 current_entry
= current_entry
->Flink
;
267 KeReleaseSpinLock(&HandleTable
->ListLock
, oldIrql
);
268 DPRINT("ObCloseAllHandles() finished\n");
269 DPRINT("Type %x\n", BODY_TO_HEADER(Process
)->ObjectType
);
272 VOID
ObDeleteHandleTable(PEPROCESS Process
)
274 * FUNCTION: Deletes the handle table associated with a process
277 PLIST_ENTRY current
= NULL
;
278 PHANDLE_TABLE HandleTable
= NULL
;
280 ObCloseAllHandles(Process
);
282 HandleTable
= &Process
->HandleTable
;
283 current
= RemoveHeadList(&HandleTable
->ListHead
);
285 while (current
!= &HandleTable
->ListHead
)
287 HANDLE_BLOCK
* HandleBlock
= CONTAINING_RECORD(current
,
290 DPRINT("Freeing %x\n", HandleBlock
);
291 ExFreePool(HandleBlock
);
293 current
= RemoveHeadList(&HandleTable
->ListHead
);
298 VOID
ObCreateHandleTable(PEPROCESS Parent
,
302 * FUNCTION: Creates a handle table for a process
304 * Parent = Parent process (or NULL if this is the first process)
305 * Inherit = True if the process should inherit its parent's handles
306 * Process = Process whose handle table is to be created
309 PHANDLE_TABLE ParentHandleTable
;
311 PLIST_ENTRY parent_current
;
314 DPRINT("ObCreateHandleTable(Parent %x, Inherit %d, Process %x)\n",
315 Parent
,Inherit
,Process
);
317 InitializeListHead(&(Process
->HandleTable
.ListHead
));
318 KeInitializeSpinLock(&(Process
->HandleTable
.ListLock
));
322 ParentHandleTable
= &Parent
->HandleTable
;
324 KeAcquireSpinLock(&Parent
->HandleTable
.ListLock
, &oldIrql
);
326 parent_current
= ParentHandleTable
->ListHead
.Flink
;
328 while (parent_current
!= &ParentHandleTable
->ListHead
)
330 HANDLE_BLOCK
* current_block
= CONTAINING_RECORD(parent_current
,
335 for (i
=0; i
<HANDLE_BLOCK_ENTRIES
; i
++)
337 if (Inherit
|| current_block
->handles
[i
].Inherit
)
339 ObCreateHandle(Process
,
340 current_block
->handles
[i
].ObjectBody
,
341 current_block
->handles
[i
].GrantedAccess
,
342 current_block
->handles
[i
].Inherit
,
347 ObCreateHandle(Process
,
350 current_block
->handles
[i
].Inherit
,
355 parent_current
= parent_current
->Flink
;
358 KeReleaseSpinLock(&Parent
->HandleTable
.ListLock
, oldIrql
);
363 PVOID
ObDeleteHandle(PEPROCESS Process
, HANDLE Handle
)
368 PHANDLE_TABLE HandleTable
;
369 POBJECT_HEADER Header
;
371 DPRINT("ObDeleteHandle(Handle %x)\n",Handle
);
373 HandleTable
= &Process
->HandleTable
;
375 KeAcquireSpinLock(&HandleTable
->ListLock
, &oldIrql
);
377 Rep
= ObpGetObjectByHandle(HandleTable
, Handle
);
380 KeReleaseSpinLock(&HandleTable
->ListLock
, oldIrql
);
384 ObjectBody
= Rep
->ObjectBody
;
385 DPRINT("ObjectBody %x\n", ObjectBody
);
386 if (ObjectBody
!= NULL
)
388 Header
= BODY_TO_HEADER(ObjectBody
);
389 BODY_TO_HEADER(ObjectBody
)->HandleCount
--;
390 ObReferenceObjectByPointer(ObjectBody
,
394 Rep
->ObjectBody
= NULL
;
396 KeReleaseSpinLock(&HandleTable
->ListLock
, oldIrql
);
398 if ((Header
->ObjectType
!= NULL
) &&
399 (Header
->ObjectType
->Close
!= NULL
))
401 Header
->ObjectType
->Close(ObjectBody
, Header
->HandleCount
);
406 KeReleaseSpinLock(&HandleTable
->ListLock
, oldIrql
);
409 DPRINT("Finished ObDeleteHandle()\n");
414 NTSTATUS
ObCreateHandle(PEPROCESS Process
,
416 ACCESS_MASK GrantedAccess
,
418 PHANDLE HandleReturn
)
420 * FUNCTION: Add a handle referencing an object
422 * obj = Object body that the handle should refer to
423 * RETURNS: The created handle
424 * NOTE: The handle is valid only in the context of the current process
428 unsigned int handle
=1;
430 HANDLE_BLOCK
* new_blk
= NULL
;
431 PHANDLE_TABLE HandleTable
;
434 DPRINT("ObCreateHandle(Process %x, obj %x)\n",Process
,ObjectBody
);
438 if (ObjectBody
!= NULL
)
440 BODY_TO_HEADER(ObjectBody
)->HandleCount
++;
442 HandleTable
= &Process
->HandleTable
;
443 KeAcquireSpinLock(&HandleTable
->ListLock
, &oldlvl
);
444 current
= HandleTable
->ListHead
.Flink
;
446 * Scan through the currently allocated handle blocks looking for a free
449 while (current
!= (&HandleTable
->ListHead
))
451 HANDLE_BLOCK
* blk
= CONTAINING_RECORD(current
,HANDLE_BLOCK
,entry
);
453 DPRINT("Current %x\n",current
);
455 for (i
=0;i
<HANDLE_BLOCK_ENTRIES
;i
++)
457 DPRINT("Considering slot %d containing %x\n",i
,blk
->handles
[i
]);
458 if (blk
->handles
[i
].ObjectBody
==NULL
)
460 blk
->handles
[i
].ObjectBody
= ObjectBody
;
461 blk
->handles
[i
].GrantedAccess
= GrantedAccess
;
462 blk
->handles
[i
].Inherit
= Inherit
;
463 KeReleaseSpinLock(&HandleTable
->ListLock
, oldlvl
);
464 *HandleReturn
= (HANDLE
)((handle
+ i
) << 2);
465 return(STATUS_SUCCESS
);
469 handle
= handle
+ HANDLE_BLOCK_ENTRIES
;
470 current
= current
->Flink
;
474 * Add a new handle block to the end of the list
477 (HANDLE_BLOCK
*)ExAllocatePoolWithTag(NonPagedPool
,sizeof(HANDLE_BLOCK
),
481 *HandleReturn
= (PHANDLE
)NULL
;
482 return(STATUS_INSUFFICIENT_RESOURCES
);
484 RtlZeroMemory(new_blk
,sizeof(HANDLE_BLOCK
));
485 InsertTailList(&(Process
->HandleTable
.ListHead
),
487 KeReleaseSpinLock(&HandleTable
->ListLock
, oldlvl
);
488 new_blk
->handles
[0].ObjectBody
= ObjectBody
;
489 new_blk
->handles
[0].GrantedAccess
= GrantedAccess
;
490 new_blk
->handles
[0].Inherit
= Inherit
;
491 *HandleReturn
= (HANDLE
)(handle
<< 2);
492 return(STATUS_SUCCESS
);
497 ObReferenceObjectByHandle(HANDLE Handle
,
498 ACCESS_MASK DesiredAccess
,
499 POBJECT_TYPE ObjectType
,
500 KPROCESSOR_MODE AccessMode
,
502 POBJECT_HANDLE_INFORMATION HandleInformationPtr
)
504 * FUNCTION: Increments the reference count for an object and returns a
505 * pointer to its body
507 * Handle = Handle for the object
508 * DesiredAccess = Desired access to the object
511 * Object (OUT) = Points to the object body on return
512 * HandleInformation (OUT) = Contains information about the handle
517 PHANDLE_REP HandleRep
;
518 POBJECT_HEADER ObjectHeader
;
521 ACCESS_MASK GrantedAccess
;
523 ASSERT_IRQL(PASSIVE_LEVEL
);
525 DPRINT("ObReferenceObjectByHandle(Handle %x, DesiredAccess %x, "
526 "ObjectType %x, AccessMode %d, Object %x)\n",Handle
,DesiredAccess
,
527 ObjectType
,AccessMode
,Object
);
531 * Handle special handle names
533 if (Handle
== NtCurrentProcess() &&
534 (ObjectType
== PsProcessType
|| ObjectType
== NULL
))
536 DPRINT("Reference from %x\n", ((PULONG
)&Handle
)[-1]);
538 ObReferenceObjectByPointer(PsGetCurrentProcess(),
542 *Object
= PsGetCurrentProcess();
543 DPRINT("Referencing current process %x\n", PsGetCurrentProcess());
544 return(STATUS_SUCCESS
);
546 else if (Handle
== NtCurrentProcess())
549 return(STATUS_OBJECT_TYPE_MISMATCH
);
551 if (Handle
== NtCurrentThread() &&
552 (ObjectType
== PsThreadType
|| ObjectType
== NULL
))
554 ObReferenceObjectByPointer(PsGetCurrentThread(),
558 *Object
= PsGetCurrentThread();
560 return(STATUS_SUCCESS
);
562 else if (Handle
== NtCurrentThread())
565 return(STATUS_OBJECT_TYPE_MISMATCH
);
568 KeAcquireSpinLock(&PsGetCurrentProcess()->HandleTable
.ListLock
,
570 HandleRep
= ObpGetObjectByHandle(&PsGetCurrentProcess()->HandleTable
,
572 if (HandleRep
== NULL
|| HandleRep
->ObjectBody
== NULL
)
574 KeReleaseSpinLock(&PsGetCurrentProcess()->HandleTable
.ListLock
,
576 return(STATUS_INVALID_HANDLE
);
578 ObjectBody
= HandleRep
->ObjectBody
;
579 DPRINT("ObjectBody %p\n",ObjectBody
);
580 ObjectHeader
= BODY_TO_HEADER(ObjectBody
);
581 DPRINT("ObjectHeader->RefCount %lu\n",ObjectHeader
->RefCount
);
582 ObReferenceObjectByPointer(ObjectBody
,
586 GrantedAccess
= HandleRep
->GrantedAccess
;
587 KeReleaseSpinLock(&PsGetCurrentProcess()->HandleTable
.ListLock
,
590 ObjectHeader
= BODY_TO_HEADER(ObjectBody
);
591 DPRINT("ObjectHeader->RefCount %lu\n",ObjectHeader
->RefCount
);
593 if (ObjectType
!= NULL
&& ObjectType
!= ObjectHeader
->ObjectType
)
596 return(STATUS_OBJECT_TYPE_MISMATCH
);
599 if (ObjectHeader
->ObjectType
== PsProcessType
)
601 DPRINT("Reference from %x\n", ((PULONG
)&Handle
)[-1]);
604 if (AccessMode
== UserMode
)
606 RtlMapGenericMask(&DesiredAccess
, ObjectHeader
->ObjectType
->Mapping
);
608 if (!(GrantedAccess
& DesiredAccess
) &&
609 !((~GrantedAccess
) & DesiredAccess
))
612 return(STATUS_ACCESS_DENIED
);
616 *Object
= ObjectBody
;
619 return(STATUS_SUCCESS
);
623 /**********************************************************************
628 * Closes a handle reference to an object.
637 NTSTATUS STDCALL
NtClose(HANDLE Handle
)
640 POBJECT_HEADER Header
;
642 assert_irql(PASSIVE_LEVEL
);
644 DPRINT("NtClose(Handle %x)\n",Handle
);
646 ObjectBody
= ObDeleteHandle(PsGetCurrentProcess(), Handle
);
647 if (ObjectBody
== NULL
)
649 return(STATUS_INVALID_HANDLE
);
652 Header
= BODY_TO_HEADER(ObjectBody
);
654 DPRINT("Dereferencing %x\n", ObjectBody
);
655 ObDereferenceObject(ObjectBody
);
657 return(STATUS_SUCCESS
);
661 ObInsertObject(PVOID Object
,
662 PACCESS_STATE PassedAccessState
,
663 ACCESS_MASK DesiredAccess
,
664 ULONG AdditionalReferences
,
665 PVOID
* ReferencedObject
,
668 return(ObCreateHandle(PsGetCurrentProcess(),