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