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.36 2002/04/07 09:24:36 sedwards 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
) - 1) >> 2;
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 ObCreateHandle(TargetProcess
,
201 if (Options
& DUPLICATE_CLOSE_SOURCE
)
203 ZwClose(SourceHandle
);
206 ObDereferenceObject(TargetProcess
);
207 ObDereferenceObject(SourceProcess
);
208 ObDereferenceObject(ObjectBody
);
210 Status
= MmCopyToCaller(UnsafeTargetHandle
, &TargetHandle
, sizeof(HANDLE
));
211 if (!NT_SUCCESS(Status
))
216 return(STATUS_SUCCESS
);
219 VOID
ObCloseAllHandles(PEPROCESS Process
)
222 PHANDLE_TABLE HandleTable
;
223 PLIST_ENTRY current_entry
;
224 PHANDLE_BLOCK current
;
228 DPRINT("ObCloseAllHandles(Process %x)\n", Process
);
230 HandleTable
= &Process
->HandleTable
;
232 KeAcquireSpinLock(&HandleTable
->ListLock
, &oldIrql
);
234 current_entry
= HandleTable
->ListHead
.Flink
;
236 while (current_entry
!= &HandleTable
->ListHead
)
238 current
= CONTAINING_RECORD(current_entry
, HANDLE_BLOCK
, entry
);
240 for (i
= 0; i
< HANDLE_BLOCK_ENTRIES
; i
++)
242 ObjectBody
= current
->handles
[i
].ObjectBody
;
244 if (ObjectBody
!= NULL
)
246 POBJECT_HEADER Header
= BODY_TO_HEADER(ObjectBody
);
248 if (Header
->ObjectType
== PsProcessType
||
249 Header
->ObjectType
== PsThreadType
)
251 DPRINT("Deleting handle to %x\n", ObjectBody
);
254 ObReferenceObjectByPointer(ObjectBody
,
258 Header
->HandleCount
--;
259 current
->handles
[i
].ObjectBody
= NULL
;
261 KeReleaseSpinLock(&HandleTable
->ListLock
, oldIrql
);
264 if ((Header
->ObjectType
!= NULL
) &&
265 (Header
->ObjectType
->Close
!= NULL
))
267 Header
->ObjectType
->Close(ObjectBody
,
268 Header
->HandleCount
);
271 ObDereferenceObject(ObjectBody
);
272 KeAttachProcess( Process
);
273 KeAcquireSpinLock(&HandleTable
->ListLock
, &oldIrql
);
274 current_entry
= &HandleTable
->ListHead
;
279 current_entry
= current_entry
->Flink
;
281 KeReleaseSpinLock(&HandleTable
->ListLock
, oldIrql
);
282 DPRINT("ObCloseAllHandles() finished\n");
283 DPRINT("Type %x\n", BODY_TO_HEADER(Process
)->ObjectType
);
286 VOID
ObDeleteHandleTable(PEPROCESS Process
)
288 * FUNCTION: Deletes the handle table associated with a process
291 PLIST_ENTRY current
= NULL
;
292 PHANDLE_TABLE HandleTable
= NULL
;
294 ObCloseAllHandles(Process
);
296 HandleTable
= &Process
->HandleTable
;
297 current
= RemoveHeadList(&HandleTable
->ListHead
);
299 while (current
!= &HandleTable
->ListHead
)
301 HANDLE_BLOCK
* HandleBlock
= CONTAINING_RECORD(current
,
304 DPRINT("Freeing %x\n", HandleBlock
);
305 ExFreePool(HandleBlock
);
307 current
= RemoveHeadList(&HandleTable
->ListHead
);
312 VOID
ObCreateHandleTable(PEPROCESS Parent
,
316 * FUNCTION: Creates a handle table for a process
318 * Parent = Parent process (or NULL if this is the first process)
319 * Inherit = True if the process should inherit its parent's handles
320 * Process = Process whose handle table is to be created
323 PHANDLE_TABLE ParentHandleTable
;
325 PLIST_ENTRY parent_current
;
328 DPRINT("ObCreateHandleTable(Parent %x, Inherit %d, Process %x)\n",
329 Parent
,Inherit
,Process
);
331 InitializeListHead(&(Process
->HandleTable
.ListHead
));
332 KeInitializeSpinLock(&(Process
->HandleTable
.ListLock
));
336 ParentHandleTable
= &Parent
->HandleTable
;
338 KeAcquireSpinLock(&Parent
->HandleTable
.ListLock
, &oldIrql
);
340 parent_current
= ParentHandleTable
->ListHead
.Flink
;
342 while (parent_current
!= &ParentHandleTable
->ListHead
)
344 HANDLE_BLOCK
* current_block
= CONTAINING_RECORD(parent_current
,
349 for (i
=0; i
<HANDLE_BLOCK_ENTRIES
; i
++)
351 if (Inherit
|| current_block
->handles
[i
].Inherit
)
353 ObCreateHandle(Process
,
354 current_block
->handles
[i
].ObjectBody
,
355 current_block
->handles
[i
].GrantedAccess
,
356 current_block
->handles
[i
].Inherit
,
361 ObCreateHandle(Process
,
364 current_block
->handles
[i
].Inherit
,
369 parent_current
= parent_current
->Flink
;
372 KeReleaseSpinLock(&Parent
->HandleTable
.ListLock
, oldIrql
);
377 PVOID
ObDeleteHandle(PEPROCESS Process
, HANDLE Handle
)
382 PHANDLE_TABLE HandleTable
;
383 POBJECT_HEADER Header
;
385 DPRINT("ObDeleteHandle(Handle %x)\n",Handle
);
387 HandleTable
= &Process
->HandleTable
;
389 KeAcquireSpinLock(&HandleTable
->ListLock
, &oldIrql
);
391 Rep
= ObpGetObjectByHandle(HandleTable
, Handle
);
394 KeReleaseSpinLock(&HandleTable
->ListLock
, oldIrql
);
398 ObjectBody
= Rep
->ObjectBody
;
399 DPRINT("ObjectBody %x\n", ObjectBody
);
400 if (ObjectBody
!= NULL
)
402 Header
= BODY_TO_HEADER(ObjectBody
);
403 BODY_TO_HEADER(ObjectBody
)->HandleCount
--;
404 ObReferenceObjectByPointer(ObjectBody
,
408 Rep
->ObjectBody
= NULL
;
410 KeReleaseSpinLock(&HandleTable
->ListLock
, oldIrql
);
412 if ((Header
->ObjectType
!= NULL
) &&
413 (Header
->ObjectType
->Close
!= NULL
))
415 Header
->ObjectType
->Close(ObjectBody
, Header
->HandleCount
);
420 KeReleaseSpinLock(&HandleTable
->ListLock
, oldIrql
);
423 DPRINT("Finished ObDeleteHandle()\n");
428 NTSTATUS
ObCreateHandle(PEPROCESS Process
,
430 ACCESS_MASK GrantedAccess
,
432 PHANDLE HandleReturn
)
434 * FUNCTION: Add a handle referencing an object
436 * obj = Object body that the handle should refer to
437 * RETURNS: The created handle
438 * NOTE: The handle is valid only in the context of the current process
442 unsigned int handle
=1;
444 HANDLE_BLOCK
* new_blk
= NULL
;
445 PHANDLE_TABLE HandleTable
;
448 DPRINT("ObCreateHandle(Process %x, obj %x)\n",Process
,ObjectBody
);
452 if (ObjectBody
!= NULL
)
454 BODY_TO_HEADER(ObjectBody
)->HandleCount
++;
456 HandleTable
= &Process
->HandleTable
;
457 KeAcquireSpinLock(&HandleTable
->ListLock
, &oldlvl
);
458 current
= HandleTable
->ListHead
.Flink
;
460 * Scan through the currently allocated handle blocks looking for a free
463 while (current
!= (&HandleTable
->ListHead
))
465 HANDLE_BLOCK
* blk
= CONTAINING_RECORD(current
,HANDLE_BLOCK
,entry
);
467 DPRINT("Current %x\n",current
);
469 for (i
=0;i
<HANDLE_BLOCK_ENTRIES
;i
++)
471 DPRINT("Considering slot %d containing %x\n",i
,blk
->handles
[i
]);
472 if (blk
->handles
[i
].ObjectBody
==NULL
)
474 blk
->handles
[i
].ObjectBody
= ObjectBody
;
475 blk
->handles
[i
].GrantedAccess
= GrantedAccess
;
476 blk
->handles
[i
].Inherit
= Inherit
;
477 KeReleaseSpinLock(&HandleTable
->ListLock
, oldlvl
);
478 *HandleReturn
= (HANDLE
)((handle
+ i
) << 2);
479 return(STATUS_SUCCESS
);
483 handle
= handle
+ HANDLE_BLOCK_ENTRIES
;
484 current
= current
->Flink
;
488 * Add a new handle block to the end of the list
491 (HANDLE_BLOCK
*)ExAllocatePoolWithTag(NonPagedPool
,sizeof(HANDLE_BLOCK
),
495 *HandleReturn
= (PHANDLE
)NULL
;
496 return(STATUS_INSUFFICIENT_RESOURCES
);
498 RtlZeroMemory(new_blk
,sizeof(HANDLE_BLOCK
));
499 InsertTailList(&(Process
->HandleTable
.ListHead
),
501 KeReleaseSpinLock(&HandleTable
->ListLock
, oldlvl
);
502 new_blk
->handles
[0].ObjectBody
= ObjectBody
;
503 new_blk
->handles
[0].GrantedAccess
= GrantedAccess
;
504 new_blk
->handles
[0].Inherit
= Inherit
;
505 *HandleReturn
= (HANDLE
)(handle
<< 2);
506 return(STATUS_SUCCESS
);
511 ObReferenceObjectByHandle(HANDLE Handle
,
512 ACCESS_MASK DesiredAccess
,
513 POBJECT_TYPE ObjectType
,
514 KPROCESSOR_MODE AccessMode
,
516 POBJECT_HANDLE_INFORMATION HandleInformationPtr
)
518 * FUNCTION: Increments the reference count for an object and returns a
519 * pointer to its body
521 * Handle = Handle for the object
522 * DesiredAccess = Desired access to the object
525 * Object (OUT) = Points to the object body on return
526 * HandleInformation (OUT) = Contains information about the handle
531 PHANDLE_REP HandleRep
;
532 POBJECT_HEADER ObjectHeader
;
535 ACCESS_MASK GrantedAccess
;
537 ASSERT_IRQL(PASSIVE_LEVEL
);
539 DPRINT("ObReferenceObjectByHandle(Handle %x, DesiredAccess %x, "
540 "ObjectType %x, AccessMode %d, Object %x)\n",Handle
,DesiredAccess
,
541 ObjectType
,AccessMode
,Object
);
545 * Handle special handle names
547 if (Handle
== NtCurrentProcess() &&
548 (ObjectType
== PsProcessType
|| ObjectType
== NULL
))
550 DPRINT("Reference from %x\n", ((PULONG
)&Handle
)[-1]);
552 ObReferenceObjectByPointer(PsGetCurrentProcess(),
556 *Object
= PsGetCurrentProcess();
557 DPRINT("Referencing current process %x\n", PsGetCurrentProcess());
558 return(STATUS_SUCCESS
);
560 else if (Handle
== NtCurrentProcess())
563 return(STATUS_OBJECT_TYPE_MISMATCH
);
565 if (Handle
== NtCurrentThread() &&
566 (ObjectType
== PsThreadType
|| ObjectType
== NULL
))
568 ObReferenceObjectByPointer(PsGetCurrentThread(),
572 *Object
= PsGetCurrentThread();
574 return(STATUS_SUCCESS
);
576 else if (Handle
== NtCurrentThread())
579 return(STATUS_OBJECT_TYPE_MISMATCH
);
582 KeAcquireSpinLock(&PsGetCurrentProcess()->HandleTable
.ListLock
,
584 HandleRep
= ObpGetObjectByHandle(&PsGetCurrentProcess()->HandleTable
,
586 if (HandleRep
== NULL
|| HandleRep
->ObjectBody
== NULL
)
588 KeReleaseSpinLock(&PsGetCurrentProcess()->HandleTable
.ListLock
,
590 return(STATUS_INVALID_HANDLE
);
592 ObjectBody
= HandleRep
->ObjectBody
;
593 DPRINT("ObjectBody %p\n",ObjectBody
);
594 ObjectHeader
= BODY_TO_HEADER(ObjectBody
);
595 DPRINT("ObjectHeader->RefCount %lu\n",ObjectHeader
->RefCount
);
596 ObReferenceObjectByPointer(ObjectBody
,
600 GrantedAccess
= HandleRep
->GrantedAccess
;
601 KeReleaseSpinLock(&PsGetCurrentProcess()->HandleTable
.ListLock
,
604 ObjectHeader
= BODY_TO_HEADER(ObjectBody
);
605 DPRINT("ObjectHeader->RefCount %lu\n",ObjectHeader
->RefCount
);
607 if (ObjectType
!= NULL
&& ObjectType
!= ObjectHeader
->ObjectType
)
610 return(STATUS_OBJECT_TYPE_MISMATCH
);
613 if (ObjectHeader
->ObjectType
== PsProcessType
)
615 DPRINT("Reference from %x\n", ((PULONG
)&Handle
)[-1]);
618 if (AccessMode
== UserMode
)
620 RtlMapGenericMask(&DesiredAccess
, ObjectHeader
->ObjectType
->Mapping
);
622 if (!(GrantedAccess
& DesiredAccess
) &&
623 !((~GrantedAccess
) & DesiredAccess
))
626 return(STATUS_ACCESS_DENIED
);
630 *Object
= ObjectBody
;
633 return(STATUS_SUCCESS
);
637 /**********************************************************************
642 * Closes a handle reference to an object.
651 NTSTATUS STDCALL
NtClose(HANDLE Handle
)
654 POBJECT_HEADER Header
;
656 assert_irql(PASSIVE_LEVEL
);
658 DPRINT("NtClose(Handle %x)\n",Handle
);
660 ObjectBody
= ObDeleteHandle(PsGetCurrentProcess(), Handle
);
661 if (ObjectBody
== NULL
)
663 return(STATUS_INVALID_HANDLE
);
666 Header
= BODY_TO_HEADER(ObjectBody
);
668 DPRINT("Dereferencing %x\n", ObjectBody
);
669 ObDereferenceObject(ObjectBody
);
671 return(STATUS_SUCCESS
);
675 ObInsertObject(PVOID Object
,
676 PACCESS_STATE PassedAccessState
,
677 ACCESS_MASK DesiredAccess
,
678 ULONG AdditionalReferences
,
679 PVOID
* ReferencedObject
,
682 return(ObCreateHandle(PsGetCurrentProcess(),