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]));
111 ObDuplicateObject(PEPROCESS SourceProcess,
112 PEPROCESS TargetProcess,
114 PHANDLE TargetHandle,
115 ACCESS_MASK DesiredAccess,
116 BOOLEAN InheritHandle,
120 PHANDLE_REP SourceHandleRep;
123 KeAcquireSpinLock(&SourceProcess->HandleTable.ListLock, &oldIrql);
124 SourceHandleRep = ObpGetObjectByHandle(&SourceProcess->HandleTable,
126 if (SourceHandleRep == NULL)
128 KeReleaseSpinLock(&SourceProcess->HandleTable.ListLock, oldIrql);
129 return(STATUS_INVALID_HANDLE);
131 ObjectBody = SourceHandleRep->ObjectBody;
132 ObReferenceObjectByPointer(ObjectBody,
137 if (Options & DUPLICATE_SAME_ACCESS)
139 DesiredAccess = SourceHandleRep->GrantedAccess;
142 KeReleaseSpinLock(&SourceProcess->HandleTable.ListLock, oldIrql);
143 ObCreateHandle(TargetProcess,
149 if (Options & DUPLICATE_CLOSE_SOURCE)
151 ZwClose(SourceHandle);
154 ObDereferenceObject(ObjectBody);
155 return(STATUS_SUCCESS);
159 NtDuplicateObject (IN HANDLE SourceProcessHandle,
160 IN HANDLE SourceHandle,
161 IN HANDLE TargetProcessHandle,
162 OUT PHANDLE UnsafeTargetHandle,
163 IN ACCESS_MASK DesiredAccess,
164 IN BOOLEAN InheritHandle,
167 * FUNCTION: Copies a handle from one process space to another
169 * SourceProcessHandle = The source process owning the handle. The
170 * source process should have opened
171 * the SourceHandle with PROCESS_DUP_HANDLE
173 * SourceHandle = The handle to the object.
174 * TargetProcessHandle = The destination process owning the handle
175 * TargetHandle (OUT) = Caller should supply storage for the
177 * DesiredAccess = The desired access to the handle.
178 * InheritHandle = Indicates wheter the new handle will be inheritable
180 * Options = Specifies special actions upon duplicating the handle.
181 * Can be one of the values DUPLICATE_CLOSE_SOURCE |
182 * DUPLICATE_SAME_ACCESS. DUPLICATE_CLOSE_SOURCE specifies
183 * that the source handle should be closed after duplicating.
184 * DUPLICATE_SAME_ACCESS specifies to ignore the
185 * DesiredAccess paramter and just grant the same access to
188 * REMARKS: This function maps to the win32 DuplicateHandle.
191 PEPROCESS SourceProcess;
192 PEPROCESS TargetProcess;
193 PHANDLE_REP SourceHandleRep;
199 ASSERT_IRQL(PASSIVE_LEVEL);
201 Status = ObReferenceObjectByHandle(SourceProcessHandle,
205 (PVOID*)&SourceProcess,
207 if (!NT_SUCCESS(Status))
211 Status = ObReferenceObjectByHandle(TargetProcessHandle,
215 (PVOID*)&TargetProcess,
217 if (!NT_SUCCESS(Status))
219 ObDereferenceObject(SourceProcess);
223 /* Check for magic handle first */
224 if (SourceHandle == NtCurrentThread())
226 ObReferenceObjectByHandle(SourceHandle,
233 ObCreateHandle(TargetProcess,
241 KeAcquireSpinLock(&SourceProcess->HandleTable.ListLock, &oldIrql);
242 SourceHandleRep = ObpGetObjectByHandle(&SourceProcess->HandleTable,
244 if (SourceHandleRep == NULL)
246 KeReleaseSpinLock(&SourceProcess->HandleTable.ListLock, oldIrql);
247 ObDereferenceObject(SourceProcess);
248 ObDereferenceObject(TargetProcess);
249 return(STATUS_INVALID_HANDLE);
251 ObjectBody = SourceHandleRep->ObjectBody;
252 ObReferenceObjectByPointer(ObjectBody,
257 if (Options & DUPLICATE_SAME_ACCESS)
259 DesiredAccess = SourceHandleRep->GrantedAccess;
262 KeReleaseSpinLock(&SourceProcess->HandleTable.ListLock, oldIrql);
263 if (!SourceHandleRep->Inherit)
265 ObDereferenceObject(TargetProcess);
266 ObDereferenceObject(SourceProcess);
267 ObDereferenceObject(ObjectBody);
268 return STATUS_INVALID_HANDLE;
270 ObCreateHandle(TargetProcess,
277 if (Options & DUPLICATE_CLOSE_SOURCE)
279 ZwClose(SourceHandle);
282 ObDereferenceObject(TargetProcess);
283 ObDereferenceObject(SourceProcess);
284 ObDereferenceObject(ObjectBody);
286 Status = MmCopyToCaller(UnsafeTargetHandle, &TargetHandle, sizeof(HANDLE));
287 if (!NT_SUCCESS(Status))
292 return(STATUS_SUCCESS);
295 VOID ObCloseAllHandles(PEPROCESS Process)
298 PHANDLE_TABLE HandleTable;
299 PLIST_ENTRY current_entry;
300 PHANDLE_BLOCK current;
303 BOOLEAN IsProcessHandle;
305 DPRINT("ObCloseAllHandles(Process %x)\n", Process);
307 HandleTable = &Process->HandleTable;
309 KeAcquireSpinLock(&HandleTable->ListLock, &oldIrql);
311 current_entry = HandleTable->ListHead.Flink;
313 while (current_entry != &HandleTable->ListHead)
315 current = CONTAINING_RECORD(current_entry, HANDLE_BLOCK, entry);
317 for (i = 0; i < HANDLE_BLOCK_ENTRIES; i++)
319 ObjectBody = current->handles[i].ObjectBody;
321 if (ObjectBody != NULL)
323 POBJECT_HEADER Header = BODY_TO_HEADER(ObjectBody);
325 if (Header->ObjectType == PsProcessType ||
326 Header->ObjectType == PsThreadType)
328 DPRINT("Deleting handle to %x\n", ObjectBody);
331 ObReferenceObjectByPointer(ObjectBody,
335 InterlockedDecrement(&Header->HandleCount);
336 current->handles[i].ObjectBody = NULL;
338 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
340 if (Header->ObjectType == PsProcessType)
342 IsProcessHandle = TRUE;
347 IsProcessHandle = FALSE;
349 if ((Header->ObjectType != NULL) &&
350 (Header->ObjectType->Close != NULL))
352 Header->ObjectType->Close(ObjectBody,
353 Header->HandleCount);
356 ObDereferenceObject(ObjectBody);
359 KeAttachProcess(Process);
361 KeAcquireSpinLock(&HandleTable->ListLock, &oldIrql);
362 current_entry = &HandleTable->ListHead;
367 current_entry = current_entry->Flink;
369 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
370 DPRINT("ObCloseAllHandles() finished\n");
371 DPRINT("Type %x\n", BODY_TO_HEADER(Process)->ObjectType);
374 VOID ObDeleteHandleTable(PEPROCESS Process)
376 * FUNCTION: Deletes the handle table associated with a process
379 PLIST_ENTRY current = NULL;
380 PHANDLE_TABLE HandleTable = NULL;
382 ObCloseAllHandles(Process);
384 HandleTable = &Process->HandleTable;
385 current = RemoveHeadList(&HandleTable->ListHead);
387 while (current != &HandleTable->ListHead)
389 HANDLE_BLOCK* HandleBlock = CONTAINING_RECORD(current,
392 DPRINT("Freeing %x\n", HandleBlock);
393 ExFreePool(HandleBlock);
395 current = RemoveHeadList(&HandleTable->ListHead);
399 #endif /* LIBCAPTIVE */
401 VOID ObCreateHandleTable(PEPROCESS Parent,
405 * FUNCTION: Creates a handle table for a process
407 * Parent = Parent process (or NULL if this is the first process)
408 * Inherit = True if the process should inherit its parent's handles
409 * Process = Process whose handle table is to be created
412 PHANDLE_TABLE ParentHandleTable, HandleTable;
414 PLIST_ENTRY parent_current;
416 PHANDLE_BLOCK current_block, new_block;
418 DPRINT("ObCreateHandleTable(Parent %x, Inherit %d, Process %x)\n",
419 Parent,Inherit,Process);
421 InitializeListHead(&(Process->HandleTable.ListHead));
422 KeInitializeSpinLock(&(Process->HandleTable.ListLock));
426 ParentHandleTable = &Parent->HandleTable;
427 HandleTable = &Process->HandleTable;
429 KeAcquireSpinLock(&Parent->HandleTable.ListLock, &oldIrql);
430 KeAcquireSpinLockAtDpcLevel(&Process->HandleTable.ListLock);
432 parent_current = ParentHandleTable->ListHead.Flink;
434 while (parent_current != &ParentHandleTable->ListHead)
436 current_block = CONTAINING_RECORD(parent_current,
439 new_block = ExAllocatePoolWithTag(NonPagedPool,
440 sizeof(HANDLE_BLOCK),
442 if (new_block == NULL)
446 RtlZeroMemory(new_block, sizeof(HANDLE_BLOCK));
448 for (i=0; i<HANDLE_BLOCK_ENTRIES; i++)
450 if (current_block->handles[i].ObjectBody)
452 if (current_block->handles[i].Inherit && Inherit)
454 new_block->handles[i].ObjectBody =
455 current_block->handles[i].ObjectBody;
456 new_block->handles[i].GrantedAccess =
457 current_block->handles[i].GrantedAccess;
458 new_block->handles[i].Inherit = TRUE;
459 InterlockedIncrement(&(BODY_TO_HEADER(current_block->handles[i].ObjectBody)->HandleCount));
463 InsertTailList(&Process->HandleTable.ListHead, &new_block->entry);
464 parent_current = parent_current->Flink;
466 KeReleaseSpinLockFromDpcLevel(&Process->HandleTable.ListLock);
467 KeReleaseSpinLock(&Parent->HandleTable.ListLock, oldIrql);
472 PVOID ObDeleteHandle(PEPROCESS Process, HANDLE Handle)
477 PHANDLE_TABLE HandleTable;
478 POBJECT_HEADER Header;
480 DPRINT("ObDeleteHandle(Handle %x)\n",Handle);
482 HandleTable = &Process->HandleTable;
484 KeAcquireSpinLock(&HandleTable->ListLock, &oldIrql);
486 Rep = ObpGetObjectByHandle(HandleTable, Handle);
489 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
493 ObjectBody = Rep->ObjectBody;
494 DPRINT("ObjectBody %x\n", ObjectBody);
495 if (ObjectBody != NULL)
497 Header = BODY_TO_HEADER(ObjectBody);
498 InterlockedDecrement(&(BODY_TO_HEADER(ObjectBody)->HandleCount));
499 ObReferenceObjectByPointer(ObjectBody,
503 Rep->ObjectBody = NULL;
505 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
507 if ((Header->ObjectType != NULL) &&
508 (Header->ObjectType->Close != NULL))
510 Header->ObjectType->Close(ObjectBody, Header->HandleCount);
515 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
518 DPRINT("Finished ObDeleteHandle()\n");
523 NTSTATUS ObCreateHandle(PEPROCESS Process,
525 ACCESS_MASK GrantedAccess,
527 PHANDLE HandleReturn)
529 * FUNCTION: Add a handle referencing an object
531 * obj = Object body that the handle should refer to
532 * RETURNS: The created handle
533 * NOTE: The handle is valid only in the context of the current process
537 unsigned int handle=1;
539 HANDLE_BLOCK* new_blk = NULL;
540 PHANDLE_TABLE HandleTable;
543 DPRINT("ObCreateHandle(Process %x, obj %x)\n",Process,ObjectBody);
547 if (ObjectBody != NULL)
549 InterlockedIncrement(&(BODY_TO_HEADER(ObjectBody)->HandleCount));
551 HandleTable = &Process->HandleTable;
552 KeAcquireSpinLock(&HandleTable->ListLock, &oldlvl);
553 current = HandleTable->ListHead.Flink;
555 * Scan through the currently allocated handle blocks looking for a free
558 while (current != (&HandleTable->ListHead))
560 HANDLE_BLOCK* blk = CONTAINING_RECORD(current,HANDLE_BLOCK,entry);
562 DPRINT("Current %x\n",current);
564 for (i=0;i<HANDLE_BLOCK_ENTRIES;i++)
566 DPRINT("Considering slot %d containing %x\n",i,blk->handles[i]);
567 if (blk->handles[i].ObjectBody==NULL)
569 blk->handles[i].ObjectBody = ObjectBody;
570 blk->handles[i].GrantedAccess = GrantedAccess;
571 blk->handles[i].Inherit = Inherit;
572 KeReleaseSpinLock(&HandleTable->ListLock, oldlvl);
573 *HandleReturn = (HANDLE)((handle + i) << 2);
574 return(STATUS_SUCCESS);
578 handle = handle + HANDLE_BLOCK_ENTRIES;
579 current = current->Flink;
583 * Add a new handle block to the end of the list
586 (HANDLE_BLOCK *)ExAllocatePoolWithTag(NonPagedPool,sizeof(HANDLE_BLOCK),
590 *HandleReturn = (PHANDLE)NULL;
591 return(STATUS_INSUFFICIENT_RESOURCES);
593 RtlZeroMemory(new_blk,sizeof(HANDLE_BLOCK));
594 InsertTailList(&(Process->HandleTable.ListHead),
596 new_blk->handles[0].ObjectBody = ObjectBody;
597 new_blk->handles[0].GrantedAccess = GrantedAccess;
598 new_blk->handles[0].Inherit = Inherit;
599 KeReleaseSpinLock(&HandleTable->ListLock, oldlvl);
600 *HandleReturn = (HANDLE)(handle << 2);
601 return(STATUS_SUCCESS);
606 ObReferenceObjectByHandle(HANDLE Handle,
607 ACCESS_MASK DesiredAccess,
608 POBJECT_TYPE ObjectType,
609 KPROCESSOR_MODE AccessMode,
611 POBJECT_HANDLE_INFORMATION HandleInformationPtr)
613 * FUNCTION: Increments the reference count for an object and returns a
614 * pointer to its body
616 * Handle = Handle for the object
617 * DesiredAccess = Desired access to the object
620 * Object (OUT) = Points to the object body on return
621 * HandleInformation (OUT) = Contains information about the handle
626 PHANDLE_REP HandleRep;
627 POBJECT_HEADER ObjectHeader;
630 ACCESS_MASK GrantedAccess;
632 ASSERT_IRQL(PASSIVE_LEVEL);
634 DPRINT("ObReferenceObjectByHandle(Handle %x, DesiredAccess %x, "
635 "ObjectType %x, AccessMode %d, Object %x)\n",Handle,DesiredAccess,
636 ObjectType,AccessMode,Object);
640 * Handle special handle names
642 if (Handle == NtCurrentProcess() &&
643 (ObjectType == PsProcessType || ObjectType == NULL))
645 DPRINT("Reference from %x\n", ((PULONG)&Handle)[-1]);
647 ObReferenceObjectByPointer(PsGetCurrentProcess(),
651 *Object = PsGetCurrentProcess();
652 DPRINT("Referencing current process %x\n", PsGetCurrentProcess());
653 return(STATUS_SUCCESS);
655 else if (Handle == NtCurrentProcess())
658 return(STATUS_OBJECT_TYPE_MISMATCH);
660 if (Handle == NtCurrentThread() &&
661 (ObjectType == PsThreadType || ObjectType == NULL))
663 ObReferenceObjectByPointer(PsGetCurrentThread(),
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);
731 /**********************************************************************
736 * Closes a handle reference to an object.
745 NTSTATUS STDCALL NtClose(HANDLE Handle)
748 POBJECT_HEADER Header;
750 assert_irql(PASSIVE_LEVEL);
752 DPRINT("NtClose(Handle %x)\n",Handle);
754 ObjectBody = ObDeleteHandle(PsGetCurrentProcess(), Handle);
755 if (ObjectBody == NULL)
757 return(STATUS_INVALID_HANDLE);
760 Header = BODY_TO_HEADER(ObjectBody);
762 DPRINT("Dereferencing %x\n", ObjectBody);
763 ObDereferenceObject(ObjectBody);
765 return(STATUS_SUCCESS);
771 ObInsertObject(PVOID Object,
772 PACCESS_STATE PassedAccessState,
773 ACCESS_MASK DesiredAccess,
774 ULONG AdditionalReferences,
775 PVOID* ReferencedObject,
778 return(ObCreateHandle(PsGetCurrentProcess(),
785 #endif /* LIBCAPTIVE */