Swapping to disk
[reactos.git] / reactos / ntoskrnl / ob / handle.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4 *
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.
9 *
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.
14 *
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.
18 */
19 /* $Id: handle.c,v 1.34 2001/12/31 19:06:48 dwelch Exp $
20 *
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)
26 * REVISION HISTORY:
27 * 17/06/98: Created
28 */
29
30 /* INCLUDES ****************************************************************/
31
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>
37
38 #define NDEBUG
39 #include <internal/debug.h>
40
41 /* TYPES *******************************************************************/
42
43 #define HANDLE_BLOCK_ENTRIES ((PAGESIZE-sizeof(LIST_ENTRY))/sizeof(HANDLE_REP))
44
45 /*
46 * PURPOSE: Defines a page's worth of handles
47 */
48 typedef struct
49 {
50 LIST_ENTRY entry;
51 HANDLE_REP handles[HANDLE_BLOCK_ENTRIES];
52 } HANDLE_BLOCK, *PHANDLE_BLOCK;
53
54 /* GLOBALS *******************************************************************/
55
56 #define TAG_HANDLE_TABLE TAG('H', 'T', 'B', 'L')
57
58 /* FUNCTIONS ***************************************************************/
59
60
61 static PHANDLE_REP ObpGetObjectByHandle(PHANDLE_TABLE HandleTable, HANDLE h)
62 /*
63 * FUNCTION: Get the data structure for a handle
64 * ARGUMENTS:
65 * Process = Process to get the handle for
66 * h = Handle
67 * ARGUMENTS: A pointer to the information about the handle on success,
68 * NULL on failure
69 */
70 {
71 PLIST_ENTRY current;
72 unsigned int handle = (((unsigned int)h) - 1) >> 2;
73 unsigned int count=handle/HANDLE_BLOCK_ENTRIES;
74 HANDLE_BLOCK* blk = NULL;
75 unsigned int i;
76
77 DPRINT("ObpGetObjectByHandle(HandleTable %x, h %x)\n",HandleTable,h);
78
79 current = HandleTable->ListHead.Flink;
80 DPRINT("current %x\n",current);
81
82 for (i=0;i<count;i++)
83 {
84 current = current->Flink;
85 if (current == (&(HandleTable->ListHead)))
86 {
87 return(NULL);
88 }
89 }
90
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]));
94 }
95
96
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,
103 ULONG Options)
104 /*
105 * FUNCTION: Copies a handle from one process space to another
106 * ARGUMENTS:
107 * SourceProcessHandle = The source process owning the handle. The
108 * source process should have opened
109 * the SourceHandle with PROCESS_DUP_HANDLE
110 * access.
111 * SourceHandle = The handle to the object.
112 * TargetProcessHandle = The destination process owning the handle
113 * TargetHandle (OUT) = Caller should supply storage for the
114 * duplicated handle.
115 * DesiredAccess = The desired access to the handle.
116 * InheritHandle = Indicates wheter the new handle will be inheritable
117 * or not.
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
124 * the new handle.
125 * RETURNS: Status
126 * REMARKS: This function maps to the win32 DuplicateHandle.
127 */
128 {
129 PEPROCESS SourceProcess;
130 PEPROCESS TargetProcess;
131 PHANDLE_REP SourceHandleRep;
132 KIRQL oldIrql;
133 PVOID ObjectBody;
134 HANDLE TargetHandle;
135 NTSTATUS Status;
136
137 ASSERT_IRQL(PASSIVE_LEVEL);
138
139 Status = ObReferenceObjectByHandle(SourceProcessHandle,
140 PROCESS_DUP_HANDLE,
141 NULL,
142 UserMode,
143 (PVOID*)&SourceProcess,
144 NULL);
145 if (!NT_SUCCESS(Status))
146 {
147 return(Status);
148 }
149 Status = ObReferenceObjectByHandle(TargetProcessHandle,
150 PROCESS_DUP_HANDLE,
151 NULL,
152 UserMode,
153 (PVOID*)&TargetProcess,
154 NULL);
155 if (!NT_SUCCESS(Status))
156 {
157 ObDereferenceObject(SourceProcess);
158 return(Status);
159 }
160 KeAcquireSpinLock(&SourceProcess->HandleTable.ListLock, &oldIrql);
161 SourceHandleRep = ObpGetObjectByHandle(&SourceProcess->HandleTable,
162 SourceHandle);
163 if (SourceHandleRep == NULL)
164 {
165 KeReleaseSpinLock(&SourceProcess->HandleTable.ListLock, oldIrql);
166 ObDereferenceObject(SourceProcess);
167 ObDereferenceObject(TargetProcess);
168 return(STATUS_INVALID_HANDLE);
169 }
170 ObjectBody = SourceHandleRep->ObjectBody;
171 ObReferenceObjectByPointer(ObjectBody,
172 0,
173 NULL,
174 UserMode);
175
176 if (Options & DUPLICATE_SAME_ACCESS)
177 {
178 DesiredAccess = SourceHandleRep->GrantedAccess;
179 }
180
181 KeReleaseSpinLock(&SourceProcess->HandleTable.ListLock, oldIrql);
182
183 ObCreateHandle(TargetProcess,
184 ObjectBody,
185 DesiredAccess,
186 InheritHandle,
187 &TargetHandle);
188
189 if (Options & DUPLICATE_CLOSE_SOURCE)
190 {
191 ZwClose(SourceHandle);
192 }
193
194 ObDereferenceObject(TargetProcess);
195 ObDereferenceObject(SourceProcess);
196 ObDereferenceObject(ObjectBody);
197
198 Status = MmCopyToCaller(UnsafeTargetHandle, &TargetHandle, sizeof(HANDLE));
199 if (!NT_SUCCESS(Status))
200 {
201 return(Status);
202 }
203
204 return(STATUS_SUCCESS);
205 }
206
207 VOID ObCloseAllHandles(PEPROCESS Process)
208 {
209 KIRQL oldIrql;
210 PHANDLE_TABLE HandleTable;
211 PLIST_ENTRY current_entry;
212 PHANDLE_BLOCK current;
213 ULONG i;
214 PVOID ObjectBody;
215
216 DPRINT("ObCloseAllHandles(Process %x)\n", Process);
217
218 HandleTable = &Process->HandleTable;
219
220 KeAcquireSpinLock(&HandleTable->ListLock, &oldIrql);
221
222 current_entry = HandleTable->ListHead.Flink;
223
224 while (current_entry != &HandleTable->ListHead)
225 {
226 current = CONTAINING_RECORD(current_entry, HANDLE_BLOCK, entry);
227
228 for (i = 0; i < HANDLE_BLOCK_ENTRIES; i++)
229 {
230 ObjectBody = current->handles[i].ObjectBody;
231
232 if (ObjectBody != NULL)
233 {
234 POBJECT_HEADER Header = BODY_TO_HEADER(ObjectBody);
235
236 if (Header->ObjectType == PsProcessType ||
237 Header->ObjectType == PsThreadType)
238 {
239 DPRINT("Deleting handle to %x\n", ObjectBody);
240 }
241
242 ObReferenceObjectByPointer(ObjectBody,
243 0,
244 NULL,
245 UserMode);
246 Header->HandleCount--;
247 current->handles[i].ObjectBody = NULL;
248
249 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
250
251 if ((Header->ObjectType != NULL) &&
252 (Header->ObjectType->Close != NULL))
253 {
254 Header->ObjectType->Close(ObjectBody,
255 Header->HandleCount);
256 }
257
258 ObDereferenceObject(ObjectBody);
259 KeAcquireSpinLock(&HandleTable->ListLock, &oldIrql);
260 current_entry = &HandleTable->ListHead;
261 break;
262 }
263 }
264
265 current_entry = current_entry->Flink;
266 }
267 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
268 DPRINT("ObCloseAllHandles() finished\n");
269 DPRINT("Type %x\n", BODY_TO_HEADER(Process)->ObjectType);
270 }
271
272 VOID ObDeleteHandleTable(PEPROCESS Process)
273 /*
274 * FUNCTION: Deletes the handle table associated with a process
275 */
276 {
277 PLIST_ENTRY current = NULL;
278 PHANDLE_TABLE HandleTable = NULL;
279
280 ObCloseAllHandles(Process);
281
282 HandleTable = &Process->HandleTable;
283 current = RemoveHeadList(&HandleTable->ListHead);
284
285 while (current != &HandleTable->ListHead)
286 {
287 HANDLE_BLOCK* HandleBlock = CONTAINING_RECORD(current,
288 HANDLE_BLOCK,
289 entry);
290 DPRINT("Freeing %x\n", HandleBlock);
291 ExFreePool(HandleBlock);
292
293 current = RemoveHeadList(&HandleTable->ListHead);
294 }
295 }
296
297
298 VOID ObCreateHandleTable(PEPROCESS Parent,
299 BOOLEAN Inherit,
300 PEPROCESS Process)
301 /*
302 * FUNCTION: Creates a handle table for a process
303 * ARGUMENTS:
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
307 */
308 {
309 PHANDLE_TABLE ParentHandleTable;
310 KIRQL oldIrql;
311 PLIST_ENTRY parent_current;
312 ULONG i;
313
314 DPRINT("ObCreateHandleTable(Parent %x, Inherit %d, Process %x)\n",
315 Parent,Inherit,Process);
316
317 InitializeListHead(&(Process->HandleTable.ListHead));
318 KeInitializeSpinLock(&(Process->HandleTable.ListLock));
319
320 if (Parent != NULL)
321 {
322 ParentHandleTable = &Parent->HandleTable;
323
324 KeAcquireSpinLock(&Parent->HandleTable.ListLock, &oldIrql);
325
326 parent_current = ParentHandleTable->ListHead.Flink;
327
328 while (parent_current != &ParentHandleTable->ListHead)
329 {
330 HANDLE_BLOCK* current_block = CONTAINING_RECORD(parent_current,
331 HANDLE_BLOCK,
332 entry);
333 HANDLE NewHandle;
334
335 for (i=0; i<HANDLE_BLOCK_ENTRIES; i++)
336 {
337 if (Inherit || current_block->handles[i].Inherit)
338 {
339 ObCreateHandle(Process,
340 current_block->handles[i].ObjectBody,
341 current_block->handles[i].GrantedAccess,
342 current_block->handles[i].Inherit,
343 &NewHandle);
344 }
345 else
346 {
347 ObCreateHandle(Process,
348 NULL,
349 0,
350 current_block->handles[i].Inherit,
351 &NewHandle);
352 }
353 }
354
355 parent_current = parent_current->Flink;
356 }
357
358 KeReleaseSpinLock(&Parent->HandleTable.ListLock, oldIrql);
359 }
360 }
361
362
363 PVOID ObDeleteHandle(PEPROCESS Process, HANDLE Handle)
364 {
365 PHANDLE_REP Rep;
366 PVOID ObjectBody;
367 KIRQL oldIrql;
368 PHANDLE_TABLE HandleTable;
369 POBJECT_HEADER Header;
370
371 DPRINT("ObDeleteHandle(Handle %x)\n",Handle);
372
373 HandleTable = &Process->HandleTable;
374
375 KeAcquireSpinLock(&HandleTable->ListLock, &oldIrql);
376
377 Rep = ObpGetObjectByHandle(HandleTable, Handle);
378 if (Rep == NULL)
379 {
380 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
381 return(NULL);
382 }
383
384 ObjectBody = Rep->ObjectBody;
385 DPRINT("ObjectBody %x\n", ObjectBody);
386 if (ObjectBody != NULL)
387 {
388 Header = BODY_TO_HEADER(ObjectBody);
389 BODY_TO_HEADER(ObjectBody)->HandleCount--;
390 ObReferenceObjectByPointer(ObjectBody,
391 0,
392 NULL,
393 UserMode);
394 Rep->ObjectBody = NULL;
395
396 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
397
398 if ((Header->ObjectType != NULL) &&
399 (Header->ObjectType->Close != NULL))
400 {
401 Header->ObjectType->Close(ObjectBody, Header->HandleCount);
402 }
403 }
404 else
405 {
406 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
407 }
408
409 DPRINT("Finished ObDeleteHandle()\n");
410 return(ObjectBody);
411 }
412
413
414 NTSTATUS ObCreateHandle(PEPROCESS Process,
415 PVOID ObjectBody,
416 ACCESS_MASK GrantedAccess,
417 BOOLEAN Inherit,
418 PHANDLE HandleReturn)
419 /*
420 * FUNCTION: Add a handle referencing an object
421 * ARGUMENTS:
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
425 */
426 {
427 LIST_ENTRY* current;
428 unsigned int handle=1;
429 unsigned int i;
430 HANDLE_BLOCK* new_blk = NULL;
431 PHANDLE_TABLE HandleTable;
432 KIRQL oldlvl;
433
434 DPRINT("ObCreateHandle(Process %x, obj %x)\n",Process,ObjectBody);
435
436 assert(Process);
437
438 if (ObjectBody != NULL)
439 {
440 BODY_TO_HEADER(ObjectBody)->HandleCount++;
441 }
442 HandleTable = &Process->HandleTable;
443 KeAcquireSpinLock(&HandleTable->ListLock, &oldlvl);
444 current = HandleTable->ListHead.Flink;
445 /*
446 * Scan through the currently allocated handle blocks looking for a free
447 * slot
448 */
449 while (current != (&HandleTable->ListHead))
450 {
451 HANDLE_BLOCK* blk = CONTAINING_RECORD(current,HANDLE_BLOCK,entry);
452
453 DPRINT("Current %x\n",current);
454
455 for (i=0;i<HANDLE_BLOCK_ENTRIES;i++)
456 {
457 DPRINT("Considering slot %d containing %x\n",i,blk->handles[i]);
458 if (blk->handles[i].ObjectBody==NULL)
459 {
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);
466 }
467 }
468
469 handle = handle + HANDLE_BLOCK_ENTRIES;
470 current = current->Flink;
471 }
472
473 /*
474 * Add a new handle block to the end of the list
475 */
476 new_blk =
477 (HANDLE_BLOCK *)ExAllocatePoolWithTag(NonPagedPool,sizeof(HANDLE_BLOCK),
478 TAG_HANDLE_TABLE);
479 if (!new_blk)
480 {
481 *HandleReturn = (PHANDLE)NULL;
482 return(STATUS_INSUFFICIENT_RESOURCES);
483 }
484 RtlZeroMemory(new_blk,sizeof(HANDLE_BLOCK));
485 InsertTailList(&(Process->HandleTable.ListHead),
486 &new_blk->entry);
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);
493 }
494
495
496 NTSTATUS STDCALL
497 ObReferenceObjectByHandle(HANDLE Handle,
498 ACCESS_MASK DesiredAccess,
499 POBJECT_TYPE ObjectType,
500 KPROCESSOR_MODE AccessMode,
501 PVOID* Object,
502 POBJECT_HANDLE_INFORMATION HandleInformationPtr)
503 /*
504 * FUNCTION: Increments the reference count for an object and returns a
505 * pointer to its body
506 * ARGUMENTS:
507 * Handle = Handle for the object
508 * DesiredAccess = Desired access to the object
509 * ObjectType
510 * AccessMode
511 * Object (OUT) = Points to the object body on return
512 * HandleInformation (OUT) = Contains information about the handle
513 * on return
514 * RETURNS: Status
515 */
516 {
517 PHANDLE_REP HandleRep;
518 POBJECT_HEADER ObjectHeader;
519 KIRQL oldIrql;
520 PVOID ObjectBody;
521 ACCESS_MASK GrantedAccess;
522
523 ASSERT_IRQL(PASSIVE_LEVEL);
524
525 DPRINT("ObReferenceObjectByHandle(Handle %x, DesiredAccess %x, "
526 "ObjectType %x, AccessMode %d, Object %x)\n",Handle,DesiredAccess,
527 ObjectType,AccessMode,Object);
528
529
530 /*
531 * Handle special handle names
532 */
533 if (Handle == NtCurrentProcess() &&
534 (ObjectType == PsProcessType || ObjectType == NULL))
535 {
536 DPRINT("Reference from %x\n", ((PULONG)&Handle)[-1]);
537
538 ObReferenceObjectByPointer(PsGetCurrentProcess(),
539 PROCESS_ALL_ACCESS,
540 PsProcessType,
541 UserMode);
542 *Object = PsGetCurrentProcess();
543 DPRINT("Referencing current process %x\n", PsGetCurrentProcess());
544 return(STATUS_SUCCESS);
545 }
546 else if (Handle == NtCurrentProcess())
547 {
548 CHECKPOINT;
549 return(STATUS_OBJECT_TYPE_MISMATCH);
550 }
551 if (Handle == NtCurrentThread() &&
552 (ObjectType == PsThreadType || ObjectType == NULL))
553 {
554 ObReferenceObjectByPointer(PsGetCurrentThread(),
555 THREAD_ALL_ACCESS,
556 PsThreadType,
557 UserMode);
558 *Object = PsGetCurrentThread();
559 CHECKPOINT;
560 return(STATUS_SUCCESS);
561 }
562 else if (Handle == NtCurrentThread())
563 {
564 CHECKPOINT;
565 return(STATUS_OBJECT_TYPE_MISMATCH);
566 }
567
568 KeAcquireSpinLock(&PsGetCurrentProcess()->HandleTable.ListLock,
569 &oldIrql);
570 HandleRep = ObpGetObjectByHandle(&PsGetCurrentProcess()->HandleTable,
571 Handle);
572 if (HandleRep == NULL || HandleRep->ObjectBody == NULL)
573 {
574 KeReleaseSpinLock(&PsGetCurrentProcess()->HandleTable.ListLock,
575 oldIrql);
576 return(STATUS_INVALID_HANDLE);
577 }
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,
583 0,
584 NULL,
585 UserMode);
586 GrantedAccess = HandleRep->GrantedAccess;
587 KeReleaseSpinLock(&PsGetCurrentProcess()->HandleTable.ListLock,
588 oldIrql);
589
590 ObjectHeader = BODY_TO_HEADER(ObjectBody);
591 DPRINT("ObjectHeader->RefCount %lu\n",ObjectHeader->RefCount);
592
593 if (ObjectType != NULL && ObjectType != ObjectHeader->ObjectType)
594 {
595 CHECKPOINT;
596 return(STATUS_OBJECT_TYPE_MISMATCH);
597 }
598
599 if (ObjectHeader->ObjectType == PsProcessType)
600 {
601 DPRINT("Reference from %x\n", ((PULONG)&Handle)[-1]);
602 }
603
604 if (AccessMode == UserMode)
605 {
606 RtlMapGenericMask(&DesiredAccess, ObjectHeader->ObjectType->Mapping);
607
608 if (!(GrantedAccess & DesiredAccess) &&
609 !((~GrantedAccess) & DesiredAccess))
610 {
611 CHECKPOINT;
612 return(STATUS_ACCESS_DENIED);
613 }
614 }
615
616 *Object = ObjectBody;
617
618 CHECKPOINT;
619 return(STATUS_SUCCESS);
620 }
621
622
623 /**********************************************************************
624 * NAME EXPORTED
625 * NtClose
626 *
627 * DESCRIPTION
628 * Closes a handle reference to an object.
629 *
630 * ARGUMENTS
631 * Handle
632 * Handle to close.
633 *
634 * RETURN VALUE
635 * Status.
636 */
637 NTSTATUS STDCALL NtClose(HANDLE Handle)
638 {
639 PVOID ObjectBody;
640 POBJECT_HEADER Header;
641
642 assert_irql(PASSIVE_LEVEL);
643
644 DPRINT("NtClose(Handle %x)\n",Handle);
645
646 ObjectBody = ObDeleteHandle(PsGetCurrentProcess(), Handle);
647 if (ObjectBody == NULL)
648 {
649 return(STATUS_INVALID_HANDLE);
650 }
651
652 Header = BODY_TO_HEADER(ObjectBody);
653
654 DPRINT("Dereferencing %x\n", ObjectBody);
655 ObDereferenceObject(ObjectBody);
656
657 return(STATUS_SUCCESS);
658 }
659
660 NTSTATUS STDCALL
661 ObInsertObject(PVOID Object,
662 PACCESS_STATE PassedAccessState,
663 ACCESS_MASK DesiredAccess,
664 ULONG AdditionalReferences,
665 PVOID* ReferencedObject,
666 PHANDLE Handle)
667 {
668 return(ObCreateHandle(PsGetCurrentProcess(),
669 Object,
670 DesiredAccess,
671 FALSE,
672 Handle));
673 }
674
675
676 /* EOF */