Copy riched20
[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$
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 <ntoskrnl.h>
33 #define NDEBUG
34 #include <internal/debug.h>
35
36 /* TYPES *******************************************************************/
37
38 /*
39 * PURPOSE: Defines a handle
40 */
41 typedef struct _HANDLE_ENTRY
42 {
43 PVOID ObjectBody;
44 ACCESS_MASK GrantedAccess;
45 } HANDLE_ENTRY, *PHANDLE_ENTRY;
46
47 #define HANDLE_BLOCK_ENTRIES \
48 (((4 * PAGE_SIZE) - \
49 (sizeof(LIST_ENTRY) + sizeof(ULONG))) / sizeof(HANDLE_ENTRY))
50
51 #define OB_HANDLE_FLAG_MASK 0x00000007
52 #define OB_HANDLE_FLAG_AUDIT 0x00000004
53 #define OB_HANDLE_FLAG_PROTECT 0x00000002
54 #define OB_HANDLE_FLAG_INHERIT 0x00000001
55
56 #define OB_POINTER_TO_ENTRY(Pointer) \
57 (PVOID)((ULONG_PTR)(Pointer) & ~OB_HANDLE_FLAG_MASK)
58
59 #define OB_ENTRY_TO_POINTER(Entry) \
60 (PVOID)((ULONG_PTR)(Entry) & ~OB_HANDLE_FLAG_MASK)
61
62 /*
63 * PURPOSE: Defines a 4 page's worth of handles
64 */
65 typedef struct
66 {
67 LIST_ENTRY entry;
68 ULONG allocation_hint;
69 ULONG allocation_count;
70 HANDLE_ENTRY handles[HANDLE_BLOCK_ENTRIES];
71 } HANDLE_BLOCK, *PHANDLE_BLOCK;
72
73
74 /* GLOBALS *******************************************************************/
75
76 #define TAG_HANDLE_TABLE TAG('H', 'T', 'B', 'L')
77
78 /* FUNCTIONS ***************************************************************/
79
80
81 /*
82 * FUNCTION: Get the data structure for a handle
83 * ARGUMENTS:
84 * Process = Process to get the handle for
85 * h = Handle
86 * ARGUMENTS: A pointer to the information about the handle on success,
87 * NULL on failure
88 */
89 static PHANDLE_ENTRY
90 ObpGetObjectByHandle(PHANDLE_TABLE HandleTable,
91 HANDLE h,
92 HANDLE_BLOCK **Block)
93 {
94 PLIST_ENTRY current;
95 unsigned int handle = (((unsigned int)h) >> 2) - 1;
96 unsigned int count = handle / HANDLE_BLOCK_ENTRIES;
97 HANDLE_BLOCK* blk = NULL;
98 unsigned int i;
99
100 DPRINT("ObpGetObjectByHandle(HandleTable %x, h %x)\n",HandleTable,h);
101
102 current = HandleTable->ListHead.Flink;
103 DPRINT("current %x\n",current);
104
105 for (i = 0; i < count; i++)
106 {
107 current = current->Flink;
108 if (current == (&(HandleTable->ListHead)))
109 {
110 return(NULL);
111 }
112 }
113
114 blk = CONTAINING_RECORD(current,HANDLE_BLOCK,entry);
115 if (Block)
116 *Block = blk;
117 DPRINT("object: %p\n",&(blk->handles[handle%HANDLE_BLOCK_ENTRIES]));
118 return(&(blk->handles[handle%HANDLE_BLOCK_ENTRIES]));
119 }
120
121
122 NTSTATUS
123 ObpQueryHandleAttributes(HANDLE Handle,
124 POBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleInfo)
125 {
126 PEPROCESS Process;
127 KIRQL oldIrql;
128 PHANDLE_ENTRY HandleEntry;
129
130 DPRINT("ObpQueryHandleAttributes(Handle %x)\n", Handle);
131
132 Process = PsGetCurrentProcess();
133
134 KeAcquireSpinLock(&Process->HandleTable.ListLock, &oldIrql);
135 HandleEntry = ObpGetObjectByHandle(&Process->HandleTable,
136 Handle,
137 NULL);
138 if (HandleEntry == NULL)
139 {
140 KeReleaseSpinLock(&Process->HandleTable.ListLock, oldIrql);
141 return STATUS_INVALID_HANDLE;
142 }
143
144 HandleInfo->Inherit =
145 ((ULONG_PTR)HandleEntry->ObjectBody & OB_HANDLE_FLAG_INHERIT);
146 HandleInfo->ProtectFromClose =
147 ((ULONG_PTR)HandleEntry->ObjectBody & OB_HANDLE_FLAG_PROTECT);
148
149 KeReleaseSpinLock(&Process->HandleTable.ListLock, oldIrql);
150
151 return STATUS_SUCCESS;
152 }
153
154
155 NTSTATUS
156 ObpSetHandleAttributes(HANDLE Handle,
157 POBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleInfo)
158 {
159 PHANDLE_ENTRY HandleEntry;
160 PEPROCESS Process;
161 KIRQL oldIrql;
162
163 DPRINT("ObpQueryHandleAttributes(Handle %x)\n", Handle);
164
165 Process = PsGetCurrentProcess();
166
167 KeAcquireSpinLock(&Process->HandleTable.ListLock, &oldIrql);
168 HandleEntry = ObpGetObjectByHandle(&Process->HandleTable,
169 Handle,
170 NULL);
171 if (HandleEntry == NULL)
172 {
173 KeReleaseSpinLock(&Process->HandleTable.ListLock, oldIrql);
174 return STATUS_INVALID_HANDLE;
175 }
176
177 if (HandleInfo->Inherit)
178 HandleEntry->ObjectBody = (PVOID)((ULONG_PTR)HandleEntry->ObjectBody | OB_HANDLE_FLAG_INHERIT);
179 else
180 HandleEntry->ObjectBody = (PVOID)((ULONG_PTR)HandleEntry->ObjectBody & ~OB_HANDLE_FLAG_INHERIT);
181
182 if (HandleInfo->ProtectFromClose)
183 HandleEntry->ObjectBody = (PVOID)((ULONG_PTR)HandleEntry->ObjectBody | OB_HANDLE_FLAG_PROTECT);
184 else
185 HandleEntry->ObjectBody = (PVOID)((ULONG_PTR)HandleEntry->ObjectBody & ~OB_HANDLE_FLAG_PROTECT);
186
187 /* FIXME: Do we need to set anything in the object header??? */
188
189 KeReleaseSpinLock(&Process->HandleTable.ListLock, oldIrql);
190
191 return STATUS_SUCCESS;
192 }
193
194
195 NTSTATUS
196 ObDuplicateObject(PEPROCESS SourceProcess,
197 PEPROCESS TargetProcess,
198 HANDLE SourceHandle,
199 PHANDLE TargetHandle,
200 ACCESS_MASK DesiredAccess,
201 BOOLEAN InheritHandle,
202 ULONG Options)
203 {
204 KIRQL oldIrql;
205 PHANDLE_ENTRY SourceHandleEntry;
206 PVOID ObjectBody;
207
208 KeAcquireSpinLock(&SourceProcess->HandleTable.ListLock, &oldIrql);
209 SourceHandleEntry = ObpGetObjectByHandle(&SourceProcess->HandleTable,
210 SourceHandle,
211 NULL);
212 if (SourceHandleEntry == NULL)
213 {
214 KeReleaseSpinLock(&SourceProcess->HandleTable.ListLock, oldIrql);
215 return STATUS_INVALID_HANDLE;
216 }
217
218 ObjectBody = OB_ENTRY_TO_POINTER(SourceHandleEntry->ObjectBody);
219 ObReferenceObjectByPointer(ObjectBody,
220 0,
221 NULL,
222 UserMode);
223
224 if (Options & DUPLICATE_SAME_ACCESS)
225 {
226 DesiredAccess = SourceHandleEntry->GrantedAccess;
227 }
228
229 KeReleaseSpinLock(&SourceProcess->HandleTable.ListLock, oldIrql);
230 ObCreateHandle(TargetProcess,
231 ObjectBody,
232 DesiredAccess,
233 InheritHandle,
234 TargetHandle);
235
236 if (Options & DUPLICATE_CLOSE_SOURCE)
237 {
238 ZwClose(SourceHandle);
239 }
240
241 ObDereferenceObject(ObjectBody);
242
243 return STATUS_SUCCESS;
244 }
245
246 /*
247 * @implemented
248 */
249 NTSTATUS STDCALL
250 NtDuplicateObject (IN HANDLE SourceProcessHandle,
251 IN HANDLE SourceHandle,
252 IN HANDLE TargetProcessHandle,
253 OUT PHANDLE UnsafeTargetHandle,
254 IN ACCESS_MASK DesiredAccess,
255 IN BOOLEAN InheritHandle,
256 ULONG Options)
257 /*
258 * FUNCTION: Copies a handle from one process space to another
259 * ARGUMENTS:
260 * SourceProcessHandle = The source process owning the handle. The
261 * source process should have opened
262 * the SourceHandle with PROCESS_DUP_HANDLE
263 * access.
264 * SourceHandle = The handle to the object.
265 * TargetProcessHandle = The destination process owning the handle
266 * TargetHandle (OUT) = Caller should supply storage for the
267 * duplicated handle.
268 * DesiredAccess = The desired access to the handle.
269 * InheritHandle = Indicates wheter the new handle will be inheritable
270 * or not.
271 * Options = Specifies special actions upon duplicating the handle.
272 * Can be one of the values DUPLICATE_CLOSE_SOURCE |
273 * DUPLICATE_SAME_ACCESS. DUPLICATE_CLOSE_SOURCE specifies
274 * that the source handle should be closed after duplicating.
275 * DUPLICATE_SAME_ACCESS specifies to ignore the
276 * DesiredAccess paramter and just grant the same access to
277 * the new handle.
278 * RETURNS: Status
279 * REMARKS: This function maps to the win32 DuplicateHandle.
280 */
281 {
282 PEPROCESS SourceProcess;
283 PEPROCESS TargetProcess;
284 PHANDLE_ENTRY SourceHandleEntry;
285 KIRQL oldIrql;
286 PVOID ObjectBody;
287 HANDLE TargetHandle;
288 NTSTATUS Status;
289
290 PAGED_CODE();
291
292 Status = ObReferenceObjectByHandle(SourceProcessHandle,
293 PROCESS_DUP_HANDLE,
294 NULL,
295 UserMode,
296 (PVOID*)&SourceProcess,
297 NULL);
298 if (!NT_SUCCESS(Status))
299 {
300 return(Status);
301 }
302
303 Status = ObReferenceObjectByHandle(TargetProcessHandle,
304 PROCESS_DUP_HANDLE,
305 NULL,
306 UserMode,
307 (PVOID*)&TargetProcess,
308 NULL);
309 if (!NT_SUCCESS(Status))
310 {
311 ObDereferenceObject(SourceProcess);
312 return(Status);
313 }
314
315 /* Check for magic handle first */
316 if (SourceHandle == NtCurrentThread())
317 {
318 ObReferenceObjectByHandle(SourceHandle,
319 PROCESS_DUP_HANDLE,
320 NULL,
321 UserMode,
322 &ObjectBody,
323 NULL);
324
325 ObCreateHandle(TargetProcess,
326 ObjectBody,
327 THREAD_ALL_ACCESS,
328 InheritHandle,
329 &TargetHandle);
330 }
331 else
332 {
333 KeAcquireSpinLock(&SourceProcess->HandleTable.ListLock, &oldIrql);
334 SourceHandleEntry = ObpGetObjectByHandle(&SourceProcess->HandleTable,
335 SourceHandle,
336 NULL);
337 if (SourceHandleEntry == NULL)
338 {
339 KeReleaseSpinLock(&SourceProcess->HandleTable.ListLock, oldIrql);
340 ObDereferenceObject(SourceProcess);
341 ObDereferenceObject(TargetProcess);
342 return(STATUS_INVALID_HANDLE);
343 }
344 ObjectBody = OB_ENTRY_TO_POINTER(SourceHandleEntry->ObjectBody);
345 ObReferenceObjectByPointer(ObjectBody,
346 0,
347 NULL,
348 UserMode);
349
350 if (Options & DUPLICATE_SAME_ACCESS)
351 {
352 DesiredAccess = SourceHandleEntry->GrantedAccess;
353 }
354
355 KeReleaseSpinLock(&SourceProcess->HandleTable.ListLock, oldIrql);
356
357 ObCreateHandle(TargetProcess,
358 ObjectBody,
359 DesiredAccess,
360 InheritHandle,
361 &TargetHandle);
362 }
363
364 if (Options & DUPLICATE_CLOSE_SOURCE)
365 {
366 ZwClose(SourceHandle);
367 }
368
369 ObDereferenceObject(TargetProcess);
370 ObDereferenceObject(SourceProcess);
371 ObDereferenceObject(ObjectBody);
372
373 Status = MmCopyToCaller(UnsafeTargetHandle, &TargetHandle, sizeof(HANDLE));
374 if (!NT_SUCCESS(Status))
375 {
376 return(Status);
377 }
378
379 return(STATUS_SUCCESS);
380 }
381
382 VOID ObCloseAllHandles(PEPROCESS Process)
383 {
384 KIRQL oldIrql;
385 PHANDLE_TABLE HandleTable;
386 PLIST_ENTRY current_entry;
387 PHANDLE_BLOCK current;
388 ULONG i;
389 PVOID ObjectBody;
390
391 DPRINT("ObCloseAllHandles(Process %x)\n", Process);
392
393 HandleTable = &Process->HandleTable;
394
395 KeAcquireSpinLock(&HandleTable->ListLock, &oldIrql);
396
397 current_entry = HandleTable->ListHead.Flink;
398
399 while (current_entry != &HandleTable->ListHead)
400 {
401 current = CONTAINING_RECORD(current_entry, HANDLE_BLOCK, entry);
402
403 for (i = 0; i < HANDLE_BLOCK_ENTRIES; i++)
404 {
405 ObjectBody = OB_ENTRY_TO_POINTER(current->handles[i].ObjectBody);
406
407 if (ObjectBody != NULL)
408 {
409 POBJECT_HEADER Header = BODY_TO_HEADER(ObjectBody);
410
411 #if 0
412 if (Header->ObjectType == PsProcessType ||
413 Header->ObjectType == PsThreadType)
414 {
415 DPRINT("Deleting handle to %x\n", ObjectBody);
416 }
417 #endif
418
419 ObReferenceObjectByPointer(ObjectBody,
420 0,
421 NULL,
422 UserMode);
423 InterlockedDecrement(&Header->HandleCount);
424 current->handles[i].ObjectBody = NULL;
425
426 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
427 if ((Header->ObjectType != NULL) &&
428 (Header->ObjectType->Close != NULL))
429 {
430 Header->ObjectType->Close(ObjectBody,
431 Header->HandleCount);
432 }
433
434 ObDereferenceObject(ObjectBody);
435 KeAcquireSpinLock(&HandleTable->ListLock, &oldIrql);
436 current_entry = &HandleTable->ListHead;
437 break;
438 }
439 }
440
441 current_entry = current_entry->Flink;
442 }
443 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
444 DPRINT("ObCloseAllHandles() finished\n");
445 DPRINT("Type %x\n", BODY_TO_HEADER(Process)->ObjectType);
446 }
447
448 VOID ObDeleteHandleTable(PEPROCESS Process)
449 /*
450 * FUNCTION: Deletes the handle table associated with a process
451 */
452 {
453 PLIST_ENTRY current = NULL;
454 PHANDLE_TABLE HandleTable = NULL;
455
456 ObCloseAllHandles(Process);
457
458 HandleTable = &Process->HandleTable;
459 current = RemoveHeadList(&HandleTable->ListHead);
460
461 while (current != &HandleTable->ListHead)
462 {
463 HANDLE_BLOCK* HandleBlock = CONTAINING_RECORD(current,
464 HANDLE_BLOCK,
465 entry);
466 DPRINT("Freeing %x\n", HandleBlock);
467 ExFreePool(HandleBlock);
468
469 current = RemoveHeadList(&HandleTable->ListHead);
470 }
471 }
472
473
474 VOID ObCreateHandleTable(PEPROCESS Parent,
475 BOOLEAN Inherit,
476 PEPROCESS Process)
477 /*
478 * FUNCTION: Creates a handle table for a process
479 * ARGUMENTS:
480 * Parent = Parent process (or NULL if this is the first process)
481 * Inherit = True if the process should inherit its parent's handles
482 * Process = Process whose handle table is to be created
483 */
484 {
485 PHANDLE_TABLE ParentHandleTable, HandleTable;
486 KIRQL oldIrql;
487 PLIST_ENTRY parent_current;
488 ULONG i;
489 PHANDLE_BLOCK current_block, new_block;
490
491 DPRINT("ObCreateHandleTable(Parent %x, Inherit %d, Process %x)\n",
492 Parent,Inherit,Process);
493
494 InitializeListHead(&(Process->HandleTable.ListHead));
495 KeInitializeSpinLock(&(Process->HandleTable.ListLock));
496
497 if (Parent != NULL)
498 {
499 ParentHandleTable = &Parent->HandleTable;
500 HandleTable = &Process->HandleTable;
501
502 KeAcquireSpinLock(&Parent->HandleTable.ListLock, &oldIrql);
503 KeAcquireSpinLockAtDpcLevel(&Process->HandleTable.ListLock);
504
505 parent_current = ParentHandleTable->ListHead.Flink;
506
507 while (parent_current != &ParentHandleTable->ListHead)
508 {
509 current_block = CONTAINING_RECORD(parent_current,
510 HANDLE_BLOCK,
511 entry);
512 new_block = ExAllocatePoolWithTag(NonPagedPool,
513 sizeof(HANDLE_BLOCK),
514 TAG_HANDLE_TABLE);
515 if (new_block == NULL)
516 {
517 break;
518 }
519 RtlZeroMemory(new_block, sizeof(HANDLE_BLOCK));
520
521 for (i=0; i<HANDLE_BLOCK_ENTRIES; i++)
522 {
523 if (current_block->handles[i].ObjectBody)
524 {
525 if ((ULONG_PTR)current_block->handles[i].ObjectBody & OB_HANDLE_FLAG_INHERIT)
526 {
527 new_block->handles[i].ObjectBody =
528 current_block->handles[i].ObjectBody;
529 new_block->handles[i].GrantedAccess =
530 current_block->handles[i].GrantedAccess;
531 InterlockedIncrement(&(BODY_TO_HEADER(OB_ENTRY_TO_POINTER(current_block->handles[i].ObjectBody))->HandleCount));
532 }
533 }
534 }
535 InsertTailList(&Process->HandleTable.ListHead, &new_block->entry);
536 parent_current = parent_current->Flink;
537 }
538 KeReleaseSpinLockFromDpcLevel(&Process->HandleTable.ListLock);
539 KeReleaseSpinLock(&Parent->HandleTable.ListLock, oldIrql);
540 }
541 }
542
543
544 NTSTATUS
545 ObDeleteHandle(PEPROCESS Process,
546 HANDLE Handle,
547 PVOID *ObjectBody)
548 {
549 PHANDLE_ENTRY HandleEntry;
550 PVOID Body;
551 KIRQL oldIrql;
552 PHANDLE_TABLE HandleTable;
553 POBJECT_HEADER Header;
554 HANDLE_BLOCK *Block;
555
556 PAGED_CODE();
557
558 DPRINT("ObDeleteHandle(Handle %x)\n",Handle);
559
560 HandleTable = &Process->HandleTable;
561
562 KeAcquireSpinLock(&HandleTable->ListLock, &oldIrql);
563
564 HandleEntry = ObpGetObjectByHandle(HandleTable, Handle, &Block);
565 if (HandleEntry == NULL)
566 {
567 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
568 *ObjectBody = NULL;
569 return STATUS_INVALID_HANDLE;
570 }
571
572 if ((ULONG_PTR)HandleEntry->ObjectBody & OB_HANDLE_FLAG_PROTECT)
573 {
574 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
575 *ObjectBody = NULL;
576 return STATUS_HANDLE_NOT_CLOSABLE;
577 }
578
579 Body = OB_ENTRY_TO_POINTER(HandleEntry->ObjectBody);
580 DPRINT("ObjectBody %x\n", Body);
581 if (Body == NULL)
582 {
583 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
584 *ObjectBody = NULL;
585 return STATUS_UNSUCCESSFUL;
586 }
587
588 Header = BODY_TO_HEADER(Body);
589 ObReferenceObjectByPointer(Body,
590 0,
591 NULL,
592 UserMode);
593 InterlockedDecrement(&Header->HandleCount);
594 HandleEntry->ObjectBody = NULL;
595
596 Block->allocation_count--;
597 Block->allocation_hint = (ULONG_PTR)Handle % HANDLE_BLOCK_ENTRIES;
598
599 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
600
601 if ((Header->ObjectType != NULL) &&
602 (Header->ObjectType->Close != NULL))
603 {
604 Header->ObjectType->Close(Body, Header->HandleCount);
605 }
606
607 *ObjectBody = Body;
608
609 DPRINT("Finished ObDeleteHandle()\n");
610
611 return STATUS_SUCCESS;
612 }
613
614
615 NTSTATUS
616 ObCreateHandle(PEPROCESS Process,
617 PVOID ObjectBody,
618 ACCESS_MASK GrantedAccess,
619 BOOLEAN Inherit,
620 PHANDLE HandleReturn)
621 /*
622 * FUNCTION: Add a handle referencing an object
623 * ARGUMENTS:
624 * obj = Object body that the handle should refer to
625 * RETURNS: The created handle
626 * NOTE: The handle is valid only in the context of the current process
627 */
628 {
629 LIST_ENTRY* current;
630 unsigned int handle=1;
631 unsigned int Loop, Index, MaxIndex;
632 HANDLE_BLOCK* new_blk = NULL;
633 PHANDLE_TABLE HandleTable;
634 KIRQL oldlvl;
635
636 PAGED_CODE();
637
638 DPRINT("ObCreateHandle(Process %x, obj %x)\n",Process,ObjectBody);
639
640 ASSERT(Process);
641
642 if (ObjectBody != NULL)
643 {
644 InterlockedIncrement(&(BODY_TO_HEADER(ObjectBody)->HandleCount));
645 }
646 HandleTable = &Process->HandleTable;
647 KeAcquireSpinLock(&HandleTable->ListLock, &oldlvl);
648 current = HandleTable->ListHead.Flink;
649 /*
650 * Scan through the currently allocated handle blocks looking for a free
651 * slot
652 */
653 while (current != (&HandleTable->ListHead))
654 {
655 HANDLE_BLOCK* blk = CONTAINING_RECORD(current,HANDLE_BLOCK,entry);
656
657 DPRINT("Current %x\n",current);
658
659 if (blk->allocation_count == HANDLE_BLOCK_ENTRIES)
660 {
661 handle = handle + HANDLE_BLOCK_ENTRIES;
662 current = current->Flink;
663 continue;
664 }
665
666 Index = blk->allocation_hint;
667 MaxIndex = HANDLE_BLOCK_ENTRIES;
668 for (Loop = 0; Loop < 2; Loop++)
669 {
670 for (Index = 0; Index < MaxIndex; Index++)
671 {
672 DPRINT("Considering slot %d containing %x\n", Index, blk->handles[Index]);
673 if (blk->handles[Index].ObjectBody == NULL)
674 {
675 blk->handles[Index].ObjectBody = OB_POINTER_TO_ENTRY(ObjectBody);
676 if (Inherit)
677 blk->handles[Index].ObjectBody = (PVOID)((ULONG_PTR)blk->handles[Index].ObjectBody | OB_HANDLE_FLAG_INHERIT);
678 blk->handles[Index].GrantedAccess = GrantedAccess;
679 blk->allocation_hint = Index + 1;
680 blk->allocation_count++;
681 KeReleaseSpinLock(&HandleTable->ListLock, oldlvl);
682 *HandleReturn = (HANDLE)((handle + Index) << 2);
683 return(STATUS_SUCCESS);
684 }
685 }
686 Index = 0;
687 MaxIndex = blk->allocation_hint;
688 }
689
690 handle = handle + HANDLE_BLOCK_ENTRIES;
691 current = current->Flink;
692 }
693
694 /*
695 * Add a new handle block to the end of the list
696 */
697 new_blk =
698 (HANDLE_BLOCK *)ExAllocatePoolWithTag(NonPagedPool,sizeof(HANDLE_BLOCK),
699 TAG_HANDLE_TABLE);
700 if (!new_blk)
701 {
702 *HandleReturn = (PHANDLE)NULL;
703 return(STATUS_INSUFFICIENT_RESOURCES);
704 }
705 RtlZeroMemory(new_blk,sizeof(HANDLE_BLOCK));
706 InsertTailList(&(Process->HandleTable.ListHead),
707 &new_blk->entry);
708 new_blk->handles[0].ObjectBody = OB_POINTER_TO_ENTRY(ObjectBody);
709 if (Inherit)
710 new_blk->handles[0].ObjectBody = (PVOID)((ULONG_PTR)new_blk->handles[0].ObjectBody | OB_HANDLE_FLAG_INHERIT);
711 new_blk->handles[0].GrantedAccess = GrantedAccess;
712 new_blk->allocation_hint = 1;
713 new_blk->allocation_count++;
714 KeReleaseSpinLock(&HandleTable->ListLock, oldlvl);
715 *HandleReturn = (HANDLE)(handle << 2);
716 return(STATUS_SUCCESS);
717 }
718
719
720 /*
721 * @implemented
722 */
723 NTSTATUS STDCALL
724 ObQueryObjectAuditingByHandle(IN HANDLE Handle,
725 OUT PBOOLEAN GenerateOnClose)
726 {
727 PEPROCESS Process;
728 KIRQL oldIrql;
729 PHANDLE_ENTRY HandleEntry;
730
731 PAGED_CODE();
732
733 DPRINT("ObQueryObjectAuditingByHandle(Handle %x)\n", Handle);
734
735 Process = PsGetCurrentProcess();
736
737 KeAcquireSpinLock(&Process->HandleTable.ListLock, &oldIrql);
738 HandleEntry = ObpGetObjectByHandle(&Process->HandleTable,
739 Handle,
740 NULL);
741 if (HandleEntry == NULL)
742 {
743 KeReleaseSpinLock(&Process->HandleTable.ListLock, oldIrql);
744 return STATUS_INVALID_HANDLE;
745 }
746
747 *GenerateOnClose = (BOOLEAN)((ULONG_PTR)HandleEntry->ObjectBody | OB_HANDLE_FLAG_AUDIT);
748
749 KeReleaseSpinLock(&Process->HandleTable.ListLock, oldIrql);
750
751 return STATUS_SUCCESS;
752 }
753
754
755 /*
756 * FUNCTION: Increments the reference count for an object and returns a
757 * pointer to its body
758 * ARGUMENTS:
759 * Handle = Handle for the object
760 * DesiredAccess = Desired access to the object
761 * ObjectType
762 * AccessMode
763 * Object (OUT) = Points to the object body on return
764 * HandleInformation (OUT) = Contains information about the handle
765 * on return
766 * RETURNS: Status
767 *
768 * @implemented
769 */
770 NTSTATUS STDCALL
771 ObReferenceObjectByHandle(HANDLE Handle,
772 ACCESS_MASK DesiredAccess,
773 POBJECT_TYPE ObjectType,
774 KPROCESSOR_MODE AccessMode,
775 PVOID* Object,
776 POBJECT_HANDLE_INFORMATION HandleInformation)
777 {
778 PHANDLE_ENTRY HandleEntry;
779 POBJECT_HEADER ObjectHeader;
780 KIRQL oldIrql;
781 PVOID ObjectBody;
782 ACCESS_MASK GrantedAccess;
783 ULONG Attributes;
784 NTSTATUS Status;
785
786 PAGED_CODE();
787
788 DPRINT("ObReferenceObjectByHandle(Handle %x, DesiredAccess %x, "
789 "ObjectType %x, AccessMode %d, Object %x)\n",Handle,DesiredAccess,
790 ObjectType,AccessMode,Object);
791
792 /*
793 * Handle special handle names
794 */
795 if (Handle == NtCurrentProcess() &&
796 (ObjectType == PsProcessType || ObjectType == NULL))
797 {
798 DPRINT("Reference from %x\n", ((PULONG)&Handle)[-1]);
799
800 Status = ObReferenceObjectByPointer(PsGetCurrentProcess(),
801 PROCESS_ALL_ACCESS,
802 PsProcessType,
803 UserMode);
804 if (! NT_SUCCESS(Status))
805 {
806 return Status;
807 }
808
809 if (HandleInformation != NULL)
810 {
811 HandleInformation->HandleAttributes = 0; /* FIXME? */
812 HandleInformation->GrantedAccess = PROCESS_ALL_ACCESS;
813 }
814
815 *Object = PsGetCurrentProcess();
816 DPRINT("Referencing current process %x\n", PsGetCurrentProcess());
817 return STATUS_SUCCESS;
818 }
819 else if (Handle == NtCurrentProcess())
820 {
821 CHECKPOINT;
822 return(STATUS_OBJECT_TYPE_MISMATCH);
823 }
824
825 if (Handle == NtCurrentThread() &&
826 (ObjectType == PsThreadType || ObjectType == NULL))
827 {
828 Status = ObReferenceObjectByPointer(PsGetCurrentThread(),
829 THREAD_ALL_ACCESS,
830 PsThreadType,
831 UserMode);
832 if (! NT_SUCCESS(Status))
833 {
834 return Status;
835 }
836
837 if (HandleInformation != NULL)
838 {
839 HandleInformation->HandleAttributes = 0; /* FIXME? */
840 HandleInformation->GrantedAccess = THREAD_ALL_ACCESS;
841 }
842
843 *Object = PsGetCurrentThread();
844 CHECKPOINT;
845 return STATUS_SUCCESS;
846 }
847 else if (Handle == NtCurrentThread())
848 {
849 CHECKPOINT;
850 return(STATUS_OBJECT_TYPE_MISMATCH);
851 }
852
853 KeAcquireSpinLock(&PsGetCurrentProcess()->HandleTable.ListLock,
854 &oldIrql);
855 HandleEntry = ObpGetObjectByHandle(&PsGetCurrentProcess()->HandleTable,
856 Handle,
857 NULL);
858 if (HandleEntry == NULL || HandleEntry->ObjectBody == 0)
859 {
860 KeReleaseSpinLock(&PsGetCurrentProcess()->HandleTable.ListLock,
861 oldIrql);
862 return(STATUS_INVALID_HANDLE);
863 }
864 ObjectBody = OB_ENTRY_TO_POINTER(HandleEntry->ObjectBody);
865 DPRINT("ObjectBody %p\n",ObjectBody);
866 ObjectHeader = BODY_TO_HEADER(ObjectBody);
867 DPRINT("ObjectHeader->RefCount %lu\n",ObjectHeader->RefCount);
868 ObReferenceObjectByPointer(ObjectBody,
869 0,
870 NULL,
871 UserMode);
872 Attributes = (ULONG_PTR)HandleEntry->ObjectBody & OB_HANDLE_FLAG_MASK;
873 GrantedAccess = HandleEntry->GrantedAccess;
874 KeReleaseSpinLock(&PsGetCurrentProcess()->HandleTable.ListLock,
875 oldIrql);
876
877 ObjectHeader = BODY_TO_HEADER(ObjectBody);
878 DPRINT("ObjectHeader->RefCount %lu\n",ObjectHeader->RefCount);
879
880 if (ObjectType != NULL && ObjectType != ObjectHeader->ObjectType)
881 {
882 CHECKPOINT;
883 return(STATUS_OBJECT_TYPE_MISMATCH);
884 }
885
886 if (ObjectHeader->ObjectType == PsProcessType)
887 {
888 DPRINT("Reference from %x\n", ((PULONG)&Handle)[-1]);
889 }
890
891 if (DesiredAccess && AccessMode == UserMode)
892 {
893 RtlMapGenericMask(&DesiredAccess, ObjectHeader->ObjectType->Mapping);
894
895 if (!(GrantedAccess & DesiredAccess) &&
896 !((~GrantedAccess) & DesiredAccess))
897 {
898 CHECKPOINT;
899 return(STATUS_ACCESS_DENIED);
900 }
901 }
902
903 if (HandleInformation != NULL)
904 {
905 HandleInformation->HandleAttributes = Attributes;
906 HandleInformation->GrantedAccess = GrantedAccess;
907 }
908
909 *Object = ObjectBody;
910
911 CHECKPOINT;
912 return(STATUS_SUCCESS);
913 }
914
915
916 /**********************************************************************
917 * NAME EXPORTED
918 * NtClose
919 *
920 * DESCRIPTION
921 * Closes a handle reference to an object.
922 *
923 * ARGUMENTS
924 * Handle
925 * Handle to close.
926 *
927 * RETURN VALUE
928 * Status.
929 *
930 * @implemented
931 */
932 NTSTATUS STDCALL
933 NtClose(IN HANDLE Handle)
934 {
935 PVOID ObjectBody;
936 POBJECT_HEADER Header;
937 NTSTATUS Status;
938
939 PAGED_CODE();
940
941 DPRINT("NtClose(Handle %x)\n",Handle);
942
943 Status = ObDeleteHandle(PsGetCurrentProcess(),
944 Handle,
945 &ObjectBody);
946 if (!NT_SUCCESS(Status))
947 {
948 if(((PEPROCESS)(KeGetCurrentThread()->ApcState.Process))->ExceptionPort)
949 KeRaiseUserException(Status);
950 return Status;
951 }
952
953 Header = BODY_TO_HEADER(ObjectBody);
954
955 DPRINT("Dereferencing %x\n", ObjectBody);
956 ObDereferenceObject(ObjectBody);
957
958 return(STATUS_SUCCESS);
959 }
960
961
962 /*
963 * @implemented
964 */
965 NTSTATUS STDCALL
966 ObInsertObject(IN PVOID Object,
967 IN PACCESS_STATE PassedAccessState OPTIONAL,
968 IN ACCESS_MASK DesiredAccess,
969 IN ULONG AdditionalReferences,
970 OUT PVOID* ReferencedObject OPTIONAL,
971 OUT PHANDLE Handle)
972 {
973 POBJECT_HEADER ObjectHeader;
974 ACCESS_MASK Access;
975
976 PAGED_CODE();
977
978 Access = DesiredAccess;
979 ObjectHeader = BODY_TO_HEADER(Object);
980
981 RtlMapGenericMask(&Access,
982 ObjectHeader->ObjectType->Mapping);
983
984 return(ObCreateHandle(PsGetCurrentProcess(),
985 Object,
986 Access,
987 ObjectHeader->Inherit,
988 Handle));
989 }
990
991
992 ULONG
993 ObpGetHandleCountByHandleTable(PHANDLE_TABLE HandleTable)
994 {
995 PHANDLE_BLOCK blk;
996 POBJECT_HEADER Header;
997 PVOID ObjectBody;
998 KIRQL OldIrql;
999 PLIST_ENTRY current;
1000 ULONG i;
1001 ULONG Count=0;
1002
1003 KeAcquireSpinLock(&HandleTable->ListLock, &OldIrql);
1004
1005 current = HandleTable->ListHead.Flink;
1006 while (current != &HandleTable->ListHead)
1007 {
1008 blk = CONTAINING_RECORD(current, HANDLE_BLOCK, entry);
1009
1010 for (i = 0; i < HANDLE_BLOCK_ENTRIES; i++)
1011 {
1012 ObjectBody = OB_ENTRY_TO_POINTER(blk->handles[i].ObjectBody);
1013 if (ObjectBody != NULL)
1014 {
1015 Header = BODY_TO_HEADER(ObjectBody);
1016
1017 /* Make sure this is real. Okay! For real!*/
1018 if ((Header->ObjectType != NULL) &&
1019 (Header->ObjectType->Close != NULL))
1020 Count++;
1021 }
1022 }
1023
1024 current = current->Flink;
1025 }
1026
1027 KeReleaseSpinLock(&HandleTable->ListLock,
1028 OldIrql);
1029
1030 return Count;
1031 }
1032
1033 /*
1034 * FUNCTION: Searches the handle table of a specified process whether it contains a
1035 * valid handle to the Object we're looking for. If not, it'll create one.
1036 *
1037 * NOTES:
1038 * The parameters of this function is basically a mixture of some of the parameters
1039 * of ObReferenceObjectByHandle() and ObReferenceObjectByPointer(). A little thinking
1040 * about what this function does (by it's name) makes clear what parameters it requires.
1041 * For example the AccessMode parameter of ObReferenceObjectByHandle/Pointer() is not
1042 * required at all as it only has influence on the object security. This function doesn't
1043 * want to get access to an object, it just looks for a valid handle and if it can't find
1044 * one, it'll just create one. It wouldn't make sense to check for security again as the
1045 * caller already has a pointer to the object.
1046 *
1047 * A test on an XP machine shows that this prototype appears to be correct.
1048 *
1049 * ARGUMENTS:
1050 * Process = This parameter simply describes in which handle table we're looking
1051 * for a handle to the object.
1052 * Object = The object pointer that we're looking for
1053 * ObjectType = Just a sanity check as ObReferenceObjectByHandle() and
1054 * ObReferenceObjectByPointer() provides.
1055 * HandleInformation = This one has to be the opposite meaning of the usage in
1056 * ObReferenceObjectByHandle(). If we actually found a valid
1057 * handle in the table, we need to check against the information
1058 * provided so we make sure this handle has all access rights
1059 * (and attributes?!) we need. If they don't match, we can't
1060 * use this handle and keep looking because the caller is likely
1061 * to depend on these access rights.
1062 * HandleReturn = The last parameter is the same as in ObCreateHandle(). If we could
1063 * find a suitable handle in the handle table, return this handle, if
1064 * not, we'll just create one using ObCreateHandle() with all access
1065 * rights the caller needs.
1066 *
1067 * RETURNS: Status
1068 *
1069 * @unimplemented
1070 */
1071 NTSTATUS STDCALL
1072 ObFindHandleForObject(IN PEPROCESS Process,
1073 IN PVOID Object,
1074 IN POBJECT_TYPE ObjectType,
1075 IN POBJECT_HANDLE_INFORMATION HandleInformation,
1076 OUT PHANDLE HandleReturn)
1077 {
1078 UNIMPLEMENTED;
1079 return STATUS_UNSUCCESSFUL;
1080 }
1081
1082 VOID
1083 ObpGetNextHandleByProcessCount(PSYSTEM_HANDLE_TABLE_ENTRY_INFO pshi,
1084 PEPROCESS Process,
1085 int Count)
1086 {
1087 ULONG P;
1088 KIRQL oldIrql;
1089
1090 // pshi->HandleValue;
1091
1092 /*
1093 This will never work with ROS! M$, I guess uses 0 -> 65535.
1094 Ros uses 0 -> 4294967295!
1095 */
1096
1097 P = (ULONG) Process->UniqueProcessId;
1098 pshi->UniqueProcessId = (USHORT) P;
1099
1100 KeAcquireSpinLock( &Process->HandleTable.ListLock, &oldIrql );
1101
1102 // pshi->GrantedAccess;
1103 // pshi->Object;
1104 // pshi->ObjectTypeIndex;
1105 // pshi->HandleAttributes;
1106
1107 KeReleaseSpinLock( &Process->HandleTable.ListLock, oldIrql );
1108
1109 return;
1110 }
1111
1112
1113
1114 /* EOF */