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 #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 ((PAGE_SIZE-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 ObDuplicateObject(PEPROCESS SourceProcess,
110 PEPROCESS TargetProcess,
112 PHANDLE TargetHandle,
113 ACCESS_MASK DesiredAccess,
114 BOOLEAN InheritHandle,
118 PHANDLE_REP SourceHandleRep;
121 KeAcquireSpinLock(&SourceProcess->HandleTable.ListLock, &oldIrql);
122 SourceHandleRep = ObpGetObjectByHandle(&SourceProcess->HandleTable,
124 if (SourceHandleRep == NULL)
126 KeReleaseSpinLock(&SourceProcess->HandleTable.ListLock, oldIrql);
127 return(STATUS_INVALID_HANDLE);
129 ObjectBody = SourceHandleRep->ObjectBody;
130 ObReferenceObjectByPointer(ObjectBody,
135 if (Options & DUPLICATE_SAME_ACCESS)
137 DesiredAccess = SourceHandleRep->GrantedAccess;
140 KeReleaseSpinLock(&SourceProcess->HandleTable.ListLock, oldIrql);
141 ObCreateHandle(TargetProcess,
147 if (Options & DUPLICATE_CLOSE_SOURCE)
149 ZwClose(SourceHandle);
152 ObDereferenceObject(ObjectBody);
153 return(STATUS_SUCCESS);
157 NtDuplicateObject (IN HANDLE SourceProcessHandle,
158 IN HANDLE SourceHandle,
159 IN HANDLE TargetProcessHandle,
160 OUT PHANDLE UnsafeTargetHandle,
161 IN ACCESS_MASK DesiredAccess,
162 IN BOOLEAN InheritHandle,
165 * FUNCTION: Copies a handle from one process space to another
167 * SourceProcessHandle = The source process owning the handle. The
168 * source process should have opened
169 * the SourceHandle with PROCESS_DUP_HANDLE
171 * SourceHandle = The handle to the object.
172 * TargetProcessHandle = The destination process owning the handle
173 * TargetHandle (OUT) = Caller should supply storage for the
175 * DesiredAccess = The desired access to the handle.
176 * InheritHandle = Indicates wheter the new handle will be inheritable
178 * Options = Specifies special actions upon duplicating the handle.
179 * Can be one of the values DUPLICATE_CLOSE_SOURCE |
180 * DUPLICATE_SAME_ACCESS. DUPLICATE_CLOSE_SOURCE specifies
181 * that the source handle should be closed after duplicating.
182 * DUPLICATE_SAME_ACCESS specifies to ignore the
183 * DesiredAccess paramter and just grant the same access to
186 * REMARKS: This function maps to the win32 DuplicateHandle.
189 PEPROCESS SourceProcess;
190 PEPROCESS TargetProcess;
191 PHANDLE_REP SourceHandleRep;
197 ASSERT_IRQL(PASSIVE_LEVEL);
199 Status = ObReferenceObjectByHandle(SourceProcessHandle,
203 (PVOID*)&SourceProcess,
205 if (!NT_SUCCESS(Status))
209 Status = ObReferenceObjectByHandle(TargetProcessHandle,
213 (PVOID*)&TargetProcess,
215 if (!NT_SUCCESS(Status))
217 ObDereferenceObject(SourceProcess);
221 /* Check for magic handle first */
222 if (SourceHandle == NtCurrentThread())
224 ObReferenceObjectByHandle(SourceHandle,
231 ObCreateHandle(TargetProcess,
239 KeAcquireSpinLock(&SourceProcess->HandleTable.ListLock, &oldIrql);
240 SourceHandleRep = ObpGetObjectByHandle(&SourceProcess->HandleTable,
242 if (SourceHandleRep == NULL)
244 KeReleaseSpinLock(&SourceProcess->HandleTable.ListLock, oldIrql);
245 ObDereferenceObject(SourceProcess);
246 ObDereferenceObject(TargetProcess);
247 return(STATUS_INVALID_HANDLE);
249 ObjectBody = SourceHandleRep->ObjectBody;
250 ObReferenceObjectByPointer(ObjectBody,
255 if (Options & DUPLICATE_SAME_ACCESS)
257 DesiredAccess = SourceHandleRep->GrantedAccess;
260 KeReleaseSpinLock(&SourceProcess->HandleTable.ListLock, oldIrql);
261 if (!SourceHandleRep->Inherit)
263 ObDereferenceObject(TargetProcess);
264 ObDereferenceObject(SourceProcess);
265 ObDereferenceObject(ObjectBody);
266 return STATUS_INVALID_HANDLE;
268 ObCreateHandle(TargetProcess,
275 if (Options & DUPLICATE_CLOSE_SOURCE)
277 ZwClose(SourceHandle);
280 ObDereferenceObject(TargetProcess);
281 ObDereferenceObject(SourceProcess);
282 ObDereferenceObject(ObjectBody);
284 Status = MmCopyToCaller(UnsafeTargetHandle, &TargetHandle, sizeof(HANDLE));
285 if (!NT_SUCCESS(Status))
290 return(STATUS_SUCCESS);
293 VOID ObCloseAllHandles(PEPROCESS Process)
296 PHANDLE_TABLE HandleTable;
297 PLIST_ENTRY current_entry;
298 PHANDLE_BLOCK current;
301 BOOLEAN IsProcessHandle;
303 DPRINT("ObCloseAllHandles(Process %x)\n", Process);
305 HandleTable = &Process->HandleTable;
307 KeAcquireSpinLock(&HandleTable->ListLock, &oldIrql);
309 current_entry = HandleTable->ListHead.Flink;
311 while (current_entry != &HandleTable->ListHead)
313 current = CONTAINING_RECORD(current_entry, HANDLE_BLOCK, entry);
315 for (i = 0; i < HANDLE_BLOCK_ENTRIES; i++)
317 ObjectBody = current->handles[i].ObjectBody;
319 if (ObjectBody != NULL)
321 POBJECT_HEADER Header = BODY_TO_HEADER(ObjectBody);
323 if (Header->ObjectType == PsProcessType ||
324 Header->ObjectType == PsThreadType)
326 DPRINT("Deleting handle to %x\n", ObjectBody);
329 ObReferenceObjectByPointer(ObjectBody,
333 InterlockedDecrement(&Header->HandleCount);
334 current->handles[i].ObjectBody = NULL;
336 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
338 if (Header->ObjectType == PsProcessType)
340 IsProcessHandle = TRUE;
345 IsProcessHandle = FALSE;
347 if ((Header->ObjectType != NULL) &&
348 (Header->ObjectType->Close != NULL))
350 Header->ObjectType->Close(ObjectBody,
351 Header->HandleCount);
354 ObDereferenceObject(ObjectBody);
357 KeAttachProcess(Process);
359 KeAcquireSpinLock(&HandleTable->ListLock, &oldIrql);
360 current_entry = &HandleTable->ListHead;
365 current_entry = current_entry->Flink;
367 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
368 DPRINT("ObCloseAllHandles() finished\n");
369 DPRINT("Type %x\n", BODY_TO_HEADER(Process)->ObjectType);
372 VOID ObDeleteHandleTable(PEPROCESS Process)
374 * FUNCTION: Deletes the handle table associated with a process
377 PLIST_ENTRY current = NULL;
378 PHANDLE_TABLE HandleTable = NULL;
380 ObCloseAllHandles(Process);
382 HandleTable = &Process->HandleTable;
383 current = RemoveHeadList(&HandleTable->ListHead);
385 while (current != &HandleTable->ListHead)
387 HANDLE_BLOCK* HandleBlock = CONTAINING_RECORD(current,
390 DPRINT("Freeing %x\n", HandleBlock);
391 ExFreePool(HandleBlock);
393 current = RemoveHeadList(&HandleTable->ListHead);
398 VOID ObCreateHandleTable(PEPROCESS Parent,
402 * FUNCTION: Creates a handle table for a process
404 * Parent = Parent process (or NULL if this is the first process)
405 * Inherit = True if the process should inherit its parent's handles
406 * Process = Process whose handle table is to be created
409 PHANDLE_TABLE ParentHandleTable, HandleTable;
411 PLIST_ENTRY parent_current;
413 PHANDLE_BLOCK current_block, new_block;
415 DPRINT("ObCreateHandleTable(Parent %x, Inherit %d, Process %x)\n",
416 Parent,Inherit,Process);
418 InitializeListHead(&(Process->HandleTable.ListHead));
419 KeInitializeSpinLock(&(Process->HandleTable.ListLock));
423 ParentHandleTable = &Parent->HandleTable;
424 HandleTable = &Process->HandleTable;
426 KeAcquireSpinLock(&Parent->HandleTable.ListLock, &oldIrql);
427 KeAcquireSpinLockAtDpcLevel(&Process->HandleTable.ListLock);
429 parent_current = ParentHandleTable->ListHead.Flink;
431 while (parent_current != &ParentHandleTable->ListHead)
433 current_block = CONTAINING_RECORD(parent_current,
436 new_block = ExAllocatePoolWithTag(NonPagedPool,
437 sizeof(HANDLE_BLOCK),
439 if (new_block == NULL)
443 RtlZeroMemory(new_block, sizeof(HANDLE_BLOCK));
445 for (i=0; i<HANDLE_BLOCK_ENTRIES; i++)
447 if (current_block->handles[i].ObjectBody)
449 if (current_block->handles[i].Inherit && Inherit)
451 new_block->handles[i].ObjectBody =
452 current_block->handles[i].ObjectBody;
453 new_block->handles[i].GrantedAccess =
454 current_block->handles[i].GrantedAccess;
455 new_block->handles[i].Inherit = TRUE;
456 InterlockedIncrement(&(BODY_TO_HEADER(current_block->handles[i].ObjectBody)->HandleCount));
460 InsertTailList(&Process->HandleTable.ListHead, &new_block->entry);
461 parent_current = parent_current->Flink;
463 KeReleaseSpinLockFromDpcLevel(&Process->HandleTable.ListLock);
464 KeReleaseSpinLock(&Parent->HandleTable.ListLock, oldIrql);
469 PVOID ObDeleteHandle(PEPROCESS Process, HANDLE Handle)
474 PHANDLE_TABLE HandleTable;
475 POBJECT_HEADER Header;
477 DPRINT("ObDeleteHandle(Handle %x)\n",Handle);
479 HandleTable = &Process->HandleTable;
481 KeAcquireSpinLock(&HandleTable->ListLock, &oldIrql);
483 Rep = ObpGetObjectByHandle(HandleTable, Handle);
486 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
490 ObjectBody = Rep->ObjectBody;
491 DPRINT("ObjectBody %x\n", ObjectBody);
492 if (ObjectBody != NULL)
494 Header = BODY_TO_HEADER(ObjectBody);
495 InterlockedDecrement(&(BODY_TO_HEADER(ObjectBody)->HandleCount));
496 ObReferenceObjectByPointer(ObjectBody,
500 Rep->ObjectBody = NULL;
502 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
504 if ((Header->ObjectType != NULL) &&
505 (Header->ObjectType->Close != NULL))
507 Header->ObjectType->Close(ObjectBody, Header->HandleCount);
512 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
515 DPRINT("Finished ObDeleteHandle()\n");
520 NTSTATUS ObCreateHandle(PEPROCESS Process,
522 ACCESS_MASK GrantedAccess,
524 PHANDLE HandleReturn)
526 * FUNCTION: Add a handle referencing an object
528 * obj = Object body that the handle should refer to
529 * RETURNS: The created handle
530 * NOTE: The handle is valid only in the context of the current process
534 unsigned int handle=1;
536 HANDLE_BLOCK* new_blk = NULL;
537 PHANDLE_TABLE HandleTable;
540 DPRINT("ObCreateHandle(Process %x, obj %x)\n",Process,ObjectBody);
544 if (ObjectBody != NULL)
546 InterlockedIncrement(&(BODY_TO_HEADER(ObjectBody)->HandleCount));
548 HandleTable = &Process->HandleTable;
549 KeAcquireSpinLock(&HandleTable->ListLock, &oldlvl);
550 current = HandleTable->ListHead.Flink;
552 * Scan through the currently allocated handle blocks looking for a free
555 while (current != (&HandleTable->ListHead))
557 HANDLE_BLOCK* blk = CONTAINING_RECORD(current,HANDLE_BLOCK,entry);
559 DPRINT("Current %x\n",current);
561 for (i=0;i<HANDLE_BLOCK_ENTRIES;i++)
563 DPRINT("Considering slot %d containing %x\n",i,blk->handles[i]);
564 if (blk->handles[i].ObjectBody==NULL)
566 blk->handles[i].ObjectBody = ObjectBody;
567 blk->handles[i].GrantedAccess = GrantedAccess;
568 blk->handles[i].Inherit = Inherit;
569 KeReleaseSpinLock(&HandleTable->ListLock, oldlvl);
570 *HandleReturn = (HANDLE)((handle + i) << 2);
571 return(STATUS_SUCCESS);
575 handle = handle + HANDLE_BLOCK_ENTRIES;
576 current = current->Flink;
580 * Add a new handle block to the end of the list
583 (HANDLE_BLOCK *)ExAllocatePoolWithTag(NonPagedPool,sizeof(HANDLE_BLOCK),
587 *HandleReturn = (PHANDLE)NULL;
588 return(STATUS_INSUFFICIENT_RESOURCES);
590 RtlZeroMemory(new_blk,sizeof(HANDLE_BLOCK));
591 InsertTailList(&(Process->HandleTable.ListHead),
593 new_blk->handles[0].ObjectBody = ObjectBody;
594 new_blk->handles[0].GrantedAccess = GrantedAccess;
595 new_blk->handles[0].Inherit = Inherit;
596 KeReleaseSpinLock(&HandleTable->ListLock, oldlvl);
597 *HandleReturn = (HANDLE)(handle << 2);
598 return(STATUS_SUCCESS);
603 ObReferenceObjectByHandle(HANDLE Handle,
604 ACCESS_MASK DesiredAccess,
605 POBJECT_TYPE ObjectType,
606 KPROCESSOR_MODE AccessMode,
608 POBJECT_HANDLE_INFORMATION HandleInformationPtr)
610 * FUNCTION: Increments the reference count for an object and returns a
611 * pointer to its body
613 * Handle = Handle for the object
614 * DesiredAccess = Desired access to the object
617 * Object (OUT) = Points to the object body on return
618 * HandleInformation (OUT) = Contains information about the handle
623 PHANDLE_REP HandleRep;
624 POBJECT_HEADER ObjectHeader;
627 ACCESS_MASK GrantedAccess;
629 ASSERT_IRQL(PASSIVE_LEVEL);
631 DPRINT("ObReferenceObjectByHandle(Handle %x, DesiredAccess %x, "
632 "ObjectType %x, AccessMode %d, Object %x)\n",Handle,DesiredAccess,
633 ObjectType,AccessMode,Object);
637 * Handle special handle names
639 if (Handle == NtCurrentProcess() &&
640 (ObjectType == PsProcessType || ObjectType == NULL))
642 DPRINT("Reference from %x\n", ((PULONG)&Handle)[-1]);
644 ObReferenceObjectByPointer(PsGetCurrentProcess(),
648 *Object = PsGetCurrentProcess();
649 DPRINT("Referencing current process %x\n", PsGetCurrentProcess());
650 return(STATUS_SUCCESS);
652 else if (Handle == NtCurrentProcess())
655 return(STATUS_OBJECT_TYPE_MISMATCH);
657 if (Handle == NtCurrentThread() &&
658 (ObjectType == PsThreadType || ObjectType == NULL))
660 ObReferenceObjectByPointer(PsGetCurrentThread(),
664 *Object = PsGetCurrentThread();
666 return(STATUS_SUCCESS);
668 else if (Handle == NtCurrentThread())
671 return(STATUS_OBJECT_TYPE_MISMATCH);
674 KeAcquireSpinLock(&PsGetCurrentProcess()->HandleTable.ListLock,
676 HandleRep = ObpGetObjectByHandle(&PsGetCurrentProcess()->HandleTable,
678 if (HandleRep == NULL || HandleRep->ObjectBody == NULL)
680 KeReleaseSpinLock(&PsGetCurrentProcess()->HandleTable.ListLock,
682 return(STATUS_INVALID_HANDLE);
684 ObjectBody = HandleRep->ObjectBody;
685 DPRINT("ObjectBody %p\n",ObjectBody);
686 ObjectHeader = BODY_TO_HEADER(ObjectBody);
687 DPRINT("ObjectHeader->RefCount %lu\n",ObjectHeader->RefCount);
688 ObReferenceObjectByPointer(ObjectBody,
692 GrantedAccess = HandleRep->GrantedAccess;
693 KeReleaseSpinLock(&PsGetCurrentProcess()->HandleTable.ListLock,
696 ObjectHeader = BODY_TO_HEADER(ObjectBody);
697 DPRINT("ObjectHeader->RefCount %lu\n",ObjectHeader->RefCount);
699 if (ObjectType != NULL && ObjectType != ObjectHeader->ObjectType)
702 return(STATUS_OBJECT_TYPE_MISMATCH);
705 if (ObjectHeader->ObjectType == PsProcessType)
707 DPRINT("Reference from %x\n", ((PULONG)&Handle)[-1]);
710 if (DesiredAccess && AccessMode == UserMode)
712 RtlMapGenericMask(&DesiredAccess, ObjectHeader->ObjectType->Mapping);
714 if (!(GrantedAccess & DesiredAccess) &&
715 !((~GrantedAccess) & DesiredAccess))
718 return(STATUS_ACCESS_DENIED);
722 *Object = ObjectBody;
725 return(STATUS_SUCCESS);
729 /**********************************************************************
734 * Closes a handle reference to an object.
743 NTSTATUS STDCALL NtClose(HANDLE Handle)
746 POBJECT_HEADER Header;
748 assert_irql(PASSIVE_LEVEL);
750 DPRINT("NtClose(Handle %x)\n",Handle);
752 ObjectBody = ObDeleteHandle(PsGetCurrentProcess(), Handle);
753 if (ObjectBody == NULL)
755 return(STATUS_INVALID_HANDLE);
758 Header = BODY_TO_HEADER(ObjectBody);
760 DPRINT("Dereferencing %x\n", ObjectBody);
761 ObDereferenceObject(ObjectBody);
763 return(STATUS_SUCCESS);
767 ObInsertObject(PVOID Object,
768 PACCESS_STATE PassedAccessState,
769 ACCESS_MASK DesiredAccess,
770 ULONG AdditionalReferences,
771 PVOID* ReferencedObject,
774 return(ObCreateHandle(PsGetCurrentProcess(),