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.
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;
306 DPRINT("ObCloseAllHandles(Process %x)\n", Process);
308 HandleTable = &Process->HandleTable;
310 KeAcquireSpinLock(&HandleTable->ListLock, &oldIrql);
312 current_entry = HandleTable->ListHead.Flink;
314 while (current_entry != &HandleTable->ListHead)
316 current = CONTAINING_RECORD(current_entry, HANDLE_BLOCK, entry);
318 for (i = 0; i < HANDLE_BLOCK_ENTRIES; i++)
320 ObjectBody = current->handles[i].ObjectBody;
322 if (ObjectBody != NULL)
324 POBJECT_HEADER Header = BODY_TO_HEADER(ObjectBody);
326 if (Header->ObjectType == PsProcessType ||
327 Header->ObjectType == PsThreadType)
329 DPRINT("Deleting handle to %x\n", ObjectBody);
332 ObReferenceObjectByPointer(ObjectBody,
336 InterlockedDecrement(&Header->HandleCount);
337 current->handles[i].ObjectBody = NULL;
339 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
340 if ((Header->ObjectType != NULL) &&
341 (Header->ObjectType->Close != NULL))
343 Header->ObjectType->Close(ObjectBody,
344 Header->HandleCount);
347 ObDereferenceObject(ObjectBody);
348 KeAcquireSpinLock(&HandleTable->ListLock, &oldIrql);
349 current_entry = &HandleTable->ListHead;
354 current_entry = current_entry->Flink;
356 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
357 DPRINT("ObCloseAllHandles() finished\n");
358 DPRINT("Type %x\n", BODY_TO_HEADER(Process)->ObjectType);
361 VOID ObDeleteHandleTable(PEPROCESS Process)
363 * FUNCTION: Deletes the handle table associated with a process
366 PLIST_ENTRY current = NULL;
367 PHANDLE_TABLE HandleTable = NULL;
369 ObCloseAllHandles(Process);
371 HandleTable = &Process->HandleTable;
372 current = RemoveHeadList(&HandleTable->ListHead);
374 while (current != &HandleTable->ListHead)
376 HANDLE_BLOCK* HandleBlock = CONTAINING_RECORD(current,
379 DPRINT("Freeing %x\n", HandleBlock);
380 ExFreePool(HandleBlock);
382 current = RemoveHeadList(&HandleTable->ListHead);
387 VOID ObCreateHandleTable(PEPROCESS Parent,
391 * FUNCTION: Creates a handle table for a process
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
398 PHANDLE_TABLE ParentHandleTable, HandleTable;
400 PLIST_ENTRY parent_current;
402 PHANDLE_BLOCK current_block, new_block;
404 DPRINT("ObCreateHandleTable(Parent %x, Inherit %d, Process %x)\n",
405 Parent,Inherit,Process);
407 InitializeListHead(&(Process->HandleTable.ListHead));
408 KeInitializeSpinLock(&(Process->HandleTable.ListLock));
412 ParentHandleTable = &Parent->HandleTable;
413 HandleTable = &Process->HandleTable;
415 KeAcquireSpinLock(&Parent->HandleTable.ListLock, &oldIrql);
416 KeAcquireSpinLockAtDpcLevel(&Process->HandleTable.ListLock);
418 parent_current = ParentHandleTable->ListHead.Flink;
420 while (parent_current != &ParentHandleTable->ListHead)
422 current_block = CONTAINING_RECORD(parent_current,
425 new_block = ExAllocatePoolWithTag(NonPagedPool,
426 sizeof(HANDLE_BLOCK),
428 if (new_block == NULL)
432 RtlZeroMemory(new_block, sizeof(HANDLE_BLOCK));
434 for (i=0; i<HANDLE_BLOCK_ENTRIES; i++)
436 if (current_block->handles[i].ObjectBody)
438 if (current_block->handles[i].Inherit && Inherit)
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));
449 InsertTailList(&Process->HandleTable.ListHead, &new_block->entry);
450 parent_current = parent_current->Flink;
452 KeReleaseSpinLockFromDpcLevel(&Process->HandleTable.ListLock);
453 KeReleaseSpinLock(&Parent->HandleTable.ListLock, oldIrql);
458 PVOID ObDeleteHandle(PEPROCESS Process, HANDLE Handle)
463 PHANDLE_TABLE HandleTable;
464 POBJECT_HEADER Header;
466 DPRINT("ObDeleteHandle(Handle %x)\n",Handle);
468 HandleTable = &Process->HandleTable;
470 KeAcquireSpinLock(&HandleTable->ListLock, &oldIrql);
472 Rep = ObpGetObjectByHandle(HandleTable, Handle);
475 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
479 ObjectBody = Rep->ObjectBody;
480 DPRINT("ObjectBody %x\n", ObjectBody);
481 if (ObjectBody != NULL)
483 Header = BODY_TO_HEADER(ObjectBody);
484 ObReferenceObjectByPointer(ObjectBody,
488 InterlockedDecrement(&(BODY_TO_HEADER(ObjectBody)->HandleCount));
489 Rep->ObjectBody = NULL;
491 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
493 if ((Header->ObjectType != NULL) &&
494 (Header->ObjectType->Close != NULL))
496 Header->ObjectType->Close(ObjectBody, Header->HandleCount);
501 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
504 DPRINT("Finished ObDeleteHandle()\n");
509 NTSTATUS ObCreateHandle(PEPROCESS Process,
511 ACCESS_MASK GrantedAccess,
513 PHANDLE HandleReturn)
515 * FUNCTION: Add a handle referencing an object
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
523 unsigned int handle=1;
525 HANDLE_BLOCK* new_blk = NULL;
526 PHANDLE_TABLE HandleTable;
529 DPRINT("ObCreateHandle(Process %x, obj %x)\n",Process,ObjectBody);
533 if (ObjectBody != NULL)
535 InterlockedIncrement(&(BODY_TO_HEADER(ObjectBody)->HandleCount));
537 HandleTable = &Process->HandleTable;
538 KeAcquireSpinLock(&HandleTable->ListLock, &oldlvl);
539 current = HandleTable->ListHead.Flink;
541 * Scan through the currently allocated handle blocks looking for a free
544 while (current != (&HandleTable->ListHead))
546 HANDLE_BLOCK* blk = CONTAINING_RECORD(current,HANDLE_BLOCK,entry);
548 DPRINT("Current %x\n",current);
550 for (i=0;i<HANDLE_BLOCK_ENTRIES;i++)
552 DPRINT("Considering slot %d containing %x\n",i,blk->handles[i]);
553 if (blk->handles[i].ObjectBody==NULL)
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);
564 handle = handle + HANDLE_BLOCK_ENTRIES;
565 current = current->Flink;
569 * Add a new handle block to the end of the list
572 (HANDLE_BLOCK *)ExAllocatePoolWithTag(NonPagedPool,sizeof(HANDLE_BLOCK),
576 *HandleReturn = (PHANDLE)NULL;
577 return(STATUS_INSUFFICIENT_RESOURCES);
579 RtlZeroMemory(new_blk,sizeof(HANDLE_BLOCK));
580 InsertTailList(&(Process->HandleTable.ListHead),
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);
595 ObReferenceObjectByHandle(HANDLE Handle,
596 ACCESS_MASK DesiredAccess,
597 POBJECT_TYPE ObjectType,
598 KPROCESSOR_MODE AccessMode,
600 POBJECT_HANDLE_INFORMATION HandleInformationPtr)
602 * FUNCTION: Increments the reference count for an object and returns a
603 * pointer to its body
605 * Handle = Handle for the object
606 * DesiredAccess = Desired access to the object
609 * Object (OUT) = Points to the object body on return
610 * HandleInformation (OUT) = Contains information about the handle
615 PHANDLE_REP HandleRep;
616 POBJECT_HEADER ObjectHeader;
619 ACCESS_MASK GrantedAccess;
622 ASSERT_IRQL(PASSIVE_LEVEL);
624 DPRINT("ObReferenceObjectByHandle(Handle %x, DesiredAccess %x, "
625 "ObjectType %x, AccessMode %d, Object %x)\n",Handle,DesiredAccess,
626 ObjectType,AccessMode,Object);
630 * Handle special handle names
632 if (Handle == NtCurrentProcess() &&
633 (ObjectType == PsProcessType || ObjectType == NULL))
635 DPRINT("Reference from %x\n", ((PULONG)&Handle)[-1]);
637 Status = ObReferenceObjectByPointer(PsGetCurrentProcess(),
641 if (! NT_SUCCESS(Status))
646 *Object = PsGetCurrentProcess();
647 DPRINT("Referencing current process %x\n", PsGetCurrentProcess());
648 return STATUS_SUCCESS;
650 else if (Handle == NtCurrentProcess())
653 return(STATUS_OBJECT_TYPE_MISMATCH);
655 if (Handle == NtCurrentThread() &&
656 (ObjectType == PsThreadType || ObjectType == NULL))
658 Status = ObReferenceObjectByPointer(PsGetCurrentThread(),
662 if (! NT_SUCCESS(Status))
667 *Object = PsGetCurrentThread();
669 return STATUS_SUCCESS;
671 else if (Handle == NtCurrentThread())
674 return(STATUS_OBJECT_TYPE_MISMATCH);
677 KeAcquireSpinLock(&PsGetCurrentProcess()->HandleTable.ListLock,
679 HandleRep = ObpGetObjectByHandle(&PsGetCurrentProcess()->HandleTable,
681 if (HandleRep == NULL || HandleRep->ObjectBody == NULL)
683 KeReleaseSpinLock(&PsGetCurrentProcess()->HandleTable.ListLock,
685 return(STATUS_INVALID_HANDLE);
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,
695 GrantedAccess = HandleRep->GrantedAccess;
696 KeReleaseSpinLock(&PsGetCurrentProcess()->HandleTable.ListLock,
699 ObjectHeader = BODY_TO_HEADER(ObjectBody);
700 DPRINT("ObjectHeader->RefCount %lu\n",ObjectHeader->RefCount);
702 if (ObjectType != NULL && ObjectType != ObjectHeader->ObjectType)
705 return(STATUS_OBJECT_TYPE_MISMATCH);
708 if (ObjectHeader->ObjectType == PsProcessType)
710 DPRINT("Reference from %x\n", ((PULONG)&Handle)[-1]);
713 if (DesiredAccess && AccessMode == UserMode)
715 RtlMapGenericMask(&DesiredAccess, ObjectHeader->ObjectType->Mapping);
717 if (!(GrantedAccess & DesiredAccess) &&
718 !((~GrantedAccess) & DesiredAccess))
721 return(STATUS_ACCESS_DENIED);
725 *Object = ObjectBody;
728 return(STATUS_SUCCESS);
732 /**********************************************************************
737 * Closes a handle reference to an object.
748 NTSTATUS STDCALL NtClose(HANDLE Handle)
751 POBJECT_HEADER Header;
753 assert_irql(PASSIVE_LEVEL);
755 DPRINT("NtClose(Handle %x)\n",Handle);
757 ObjectBody = ObDeleteHandle(PsGetCurrentProcess(), Handle);
758 if (ObjectBody == NULL)
760 if(((PEPROCESS)(KeGetCurrentThread()->ApcState.Process))->ExceptionPort)
761 KeRaiseUserException(STATUS_INVALID_HANDLE);
762 return(STATUS_INVALID_HANDLE);
765 Header = BODY_TO_HEADER(ObjectBody);
767 DPRINT("Dereferencing %x\n", ObjectBody);
768 ObDereferenceObject(ObjectBody);
770 return(STATUS_SUCCESS);
777 ObInsertObject(PVOID Object,
778 PACCESS_STATE PassedAccessState,
779 ACCESS_MASK DesiredAccess,
780 ULONG AdditionalReferences,
781 PVOID* ReferencedObject,
784 return(ObCreateHandle(PsGetCurrentProcess(),