Branch setupapi
[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 ASSERT_IRQL(PASSIVE_LEVEL);
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 if (!((ULONG_PTR)SourceHandleEntry->ObjectBody & OB_HANDLE_FLAG_INHERIT))
357 {
358 ObDereferenceObject(TargetProcess);
359 ObDereferenceObject(SourceProcess);
360 ObDereferenceObject(ObjectBody);
361 return STATUS_INVALID_HANDLE;
362 }
363 ObCreateHandle(TargetProcess,
364 ObjectBody,
365 DesiredAccess,
366 InheritHandle,
367 &TargetHandle);
368 }
369
370 if (Options & DUPLICATE_CLOSE_SOURCE)
371 {
372 ZwClose(SourceHandle);
373 }
374
375 ObDereferenceObject(TargetProcess);
376 ObDereferenceObject(SourceProcess);
377 ObDereferenceObject(ObjectBody);
378
379 Status = MmCopyToCaller(UnsafeTargetHandle, &TargetHandle, sizeof(HANDLE));
380 if (!NT_SUCCESS(Status))
381 {
382 return(Status);
383 }
384
385 return(STATUS_SUCCESS);
386 }
387
388 VOID ObCloseAllHandles(PEPROCESS Process)
389 {
390 KIRQL oldIrql;
391 PHANDLE_TABLE HandleTable;
392 PLIST_ENTRY current_entry;
393 PHANDLE_BLOCK current;
394 ULONG i;
395 PVOID ObjectBody;
396
397 DPRINT("ObCloseAllHandles(Process %x)\n", Process);
398
399 HandleTable = &Process->HandleTable;
400
401 KeAcquireSpinLock(&HandleTable->ListLock, &oldIrql);
402
403 current_entry = HandleTable->ListHead.Flink;
404
405 while (current_entry != &HandleTable->ListHead)
406 {
407 current = CONTAINING_RECORD(current_entry, HANDLE_BLOCK, entry);
408
409 for (i = 0; i < HANDLE_BLOCK_ENTRIES; i++)
410 {
411 ObjectBody = OB_ENTRY_TO_POINTER(current->handles[i].ObjectBody);
412
413 if (ObjectBody != NULL)
414 {
415 POBJECT_HEADER Header = BODY_TO_HEADER(ObjectBody);
416
417 #if 0
418 if (Header->ObjectType == PsProcessType ||
419 Header->ObjectType == PsThreadType)
420 {
421 DPRINT("Deleting handle to %x\n", ObjectBody);
422 }
423 #endif
424
425 ObReferenceObjectByPointer(ObjectBody,
426 0,
427 NULL,
428 UserMode);
429 InterlockedDecrement(&Header->HandleCount);
430 current->handles[i].ObjectBody = NULL;
431
432 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
433 if ((Header->ObjectType != NULL) &&
434 (Header->ObjectType->Close != NULL))
435 {
436 Header->ObjectType->Close(ObjectBody,
437 Header->HandleCount);
438 }
439
440 ObDereferenceObject(ObjectBody);
441 KeAcquireSpinLock(&HandleTable->ListLock, &oldIrql);
442 current_entry = &HandleTable->ListHead;
443 break;
444 }
445 }
446
447 current_entry = current_entry->Flink;
448 }
449 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
450 DPRINT("ObCloseAllHandles() finished\n");
451 DPRINT("Type %x\n", BODY_TO_HEADER(Process)->ObjectType);
452 }
453
454 VOID ObDeleteHandleTable(PEPROCESS Process)
455 /*
456 * FUNCTION: Deletes the handle table associated with a process
457 */
458 {
459 PLIST_ENTRY current = NULL;
460 PHANDLE_TABLE HandleTable = NULL;
461
462 ObCloseAllHandles(Process);
463
464 HandleTable = &Process->HandleTable;
465 current = RemoveHeadList(&HandleTable->ListHead);
466
467 while (current != &HandleTable->ListHead)
468 {
469 HANDLE_BLOCK* HandleBlock = CONTAINING_RECORD(current,
470 HANDLE_BLOCK,
471 entry);
472 DPRINT("Freeing %x\n", HandleBlock);
473 ExFreePool(HandleBlock);
474
475 current = RemoveHeadList(&HandleTable->ListHead);
476 }
477 }
478
479
480 VOID ObCreateHandleTable(PEPROCESS Parent,
481 BOOLEAN Inherit,
482 PEPROCESS Process)
483 /*
484 * FUNCTION: Creates a handle table for a process
485 * ARGUMENTS:
486 * Parent = Parent process (or NULL if this is the first process)
487 * Inherit = True if the process should inherit its parent's handles
488 * Process = Process whose handle table is to be created
489 */
490 {
491 PHANDLE_TABLE ParentHandleTable, HandleTable;
492 KIRQL oldIrql;
493 PLIST_ENTRY parent_current;
494 ULONG i;
495 PHANDLE_BLOCK current_block, new_block;
496
497 DPRINT("ObCreateHandleTable(Parent %x, Inherit %d, Process %x)\n",
498 Parent,Inherit,Process);
499
500 InitializeListHead(&(Process->HandleTable.ListHead));
501 KeInitializeSpinLock(&(Process->HandleTable.ListLock));
502
503 if (Parent != NULL)
504 {
505 ParentHandleTable = &Parent->HandleTable;
506 HandleTable = &Process->HandleTable;
507
508 KeAcquireSpinLock(&Parent->HandleTable.ListLock, &oldIrql);
509 KeAcquireSpinLockAtDpcLevel(&Process->HandleTable.ListLock);
510
511 parent_current = ParentHandleTable->ListHead.Flink;
512
513 while (parent_current != &ParentHandleTable->ListHead)
514 {
515 current_block = CONTAINING_RECORD(parent_current,
516 HANDLE_BLOCK,
517 entry);
518 new_block = ExAllocatePoolWithTag(NonPagedPool,
519 sizeof(HANDLE_BLOCK),
520 TAG_HANDLE_TABLE);
521 if (new_block == NULL)
522 {
523 break;
524 }
525 RtlZeroMemory(new_block, sizeof(HANDLE_BLOCK));
526
527 for (i=0; i<HANDLE_BLOCK_ENTRIES; i++)
528 {
529 if (current_block->handles[i].ObjectBody)
530 {
531 if ((ULONG_PTR)current_block->handles[i].ObjectBody & OB_HANDLE_FLAG_INHERIT)
532 {
533 new_block->handles[i].ObjectBody =
534 current_block->handles[i].ObjectBody;
535 new_block->handles[i].GrantedAccess =
536 current_block->handles[i].GrantedAccess;
537 InterlockedIncrement(&(BODY_TO_HEADER(OB_ENTRY_TO_POINTER(current_block->handles[i].ObjectBody))->HandleCount));
538 }
539 }
540 }
541 InsertTailList(&Process->HandleTable.ListHead, &new_block->entry);
542 parent_current = parent_current->Flink;
543 }
544 KeReleaseSpinLockFromDpcLevel(&Process->HandleTable.ListLock);
545 KeReleaseSpinLock(&Parent->HandleTable.ListLock, oldIrql);
546 }
547 }
548
549
550 NTSTATUS
551 ObDeleteHandle(PEPROCESS Process,
552 HANDLE Handle,
553 PVOID *ObjectBody)
554 {
555 PHANDLE_ENTRY HandleEntry;
556 PVOID Body;
557 KIRQL oldIrql;
558 PHANDLE_TABLE HandleTable;
559 POBJECT_HEADER Header;
560 HANDLE_BLOCK *Block;
561
562 DPRINT("ObDeleteHandle(Handle %x)\n",Handle);
563
564 HandleTable = &Process->HandleTable;
565
566 KeAcquireSpinLock(&HandleTable->ListLock, &oldIrql);
567
568 HandleEntry = ObpGetObjectByHandle(HandleTable, Handle, &Block);
569 if (HandleEntry == NULL)
570 {
571 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
572 *ObjectBody = NULL;
573 return STATUS_INVALID_HANDLE;
574 }
575
576 if ((ULONG_PTR)HandleEntry->ObjectBody & OB_HANDLE_FLAG_PROTECT)
577 {
578 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
579 *ObjectBody = NULL;
580 return STATUS_HANDLE_NOT_CLOSABLE;
581 }
582
583 Body = OB_ENTRY_TO_POINTER(HandleEntry->ObjectBody);
584 DPRINT("ObjectBody %x\n", Body);
585 if (Body == NULL)
586 {
587 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
588 *ObjectBody = NULL;
589 return STATUS_UNSUCCESSFUL;
590 }
591
592 Header = BODY_TO_HEADER(Body);
593 ObReferenceObjectByPointer(Body,
594 0,
595 NULL,
596 UserMode);
597 InterlockedDecrement(&Header->HandleCount);
598 HandleEntry->ObjectBody = NULL;
599
600 Block->allocation_count--;
601 Block->allocation_hint = (ULONG_PTR)Handle % HANDLE_BLOCK_ENTRIES;
602
603 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
604
605 if ((Header->ObjectType != NULL) &&
606 (Header->ObjectType->Close != NULL))
607 {
608 Header->ObjectType->Close(Body, Header->HandleCount);
609 }
610
611 *ObjectBody = Body;
612
613 DPRINT("Finished ObDeleteHandle()\n");
614
615 return STATUS_SUCCESS;
616 }
617
618
619 NTSTATUS
620 ObCreateHandle(PEPROCESS Process,
621 PVOID ObjectBody,
622 ACCESS_MASK GrantedAccess,
623 BOOLEAN Inherit,
624 PHANDLE HandleReturn)
625 /*
626 * FUNCTION: Add a handle referencing an object
627 * ARGUMENTS:
628 * obj = Object body that the handle should refer to
629 * RETURNS: The created handle
630 * NOTE: The handle is valid only in the context of the current process
631 */
632 {
633 LIST_ENTRY* current;
634 unsigned int handle=1;
635 unsigned int Loop, Index, MaxIndex;
636 HANDLE_BLOCK* new_blk = NULL;
637 PHANDLE_TABLE HandleTable;
638 KIRQL oldlvl;
639
640 DPRINT("ObCreateHandle(Process %x, obj %x)\n",Process,ObjectBody);
641
642 ASSERT(Process);
643
644 if (ObjectBody != NULL)
645 {
646 InterlockedIncrement(&(BODY_TO_HEADER(ObjectBody)->HandleCount));
647 }
648 HandleTable = &Process->HandleTable;
649 KeAcquireSpinLock(&HandleTable->ListLock, &oldlvl);
650 current = HandleTable->ListHead.Flink;
651 /*
652 * Scan through the currently allocated handle blocks looking for a free
653 * slot
654 */
655 while (current != (&HandleTable->ListHead))
656 {
657 HANDLE_BLOCK* blk = CONTAINING_RECORD(current,HANDLE_BLOCK,entry);
658
659 DPRINT("Current %x\n",current);
660
661 if (blk->allocation_count == HANDLE_BLOCK_ENTRIES)
662 {
663 handle = handle + HANDLE_BLOCK_ENTRIES;
664 current = current->Flink;
665 continue;
666 }
667
668 Index = blk->allocation_hint;
669 MaxIndex = HANDLE_BLOCK_ENTRIES;
670 for (Loop = 0; Loop < 2; Loop++)
671 {
672 for (Index = 0; Index < MaxIndex; Index++)
673 {
674 DPRINT("Considering slot %d containing %x\n", Index, blk->handles[Index]);
675 if (blk->handles[Index].ObjectBody == NULL)
676 {
677 blk->handles[Index].ObjectBody = OB_POINTER_TO_ENTRY(ObjectBody);
678 if (Inherit)
679 blk->handles[Index].ObjectBody = (PVOID)((ULONG_PTR)blk->handles[Index].ObjectBody | OB_HANDLE_FLAG_INHERIT);
680 blk->handles[Index].GrantedAccess = GrantedAccess;
681 blk->allocation_hint = Index + 1;
682 blk->allocation_count++;
683 KeReleaseSpinLock(&HandleTable->ListLock, oldlvl);
684 *HandleReturn = (HANDLE)((handle + Index) << 2);
685 return(STATUS_SUCCESS);
686 }
687 }
688 Index = 0;
689 MaxIndex = blk->allocation_hint;
690 }
691
692 handle = handle + HANDLE_BLOCK_ENTRIES;
693 current = current->Flink;
694 }
695
696 /*
697 * Add a new handle block to the end of the list
698 */
699 new_blk =
700 (HANDLE_BLOCK *)ExAllocatePoolWithTag(NonPagedPool,sizeof(HANDLE_BLOCK),
701 TAG_HANDLE_TABLE);
702 if (!new_blk)
703 {
704 *HandleReturn = (PHANDLE)NULL;
705 return(STATUS_INSUFFICIENT_RESOURCES);
706 }
707 RtlZeroMemory(new_blk,sizeof(HANDLE_BLOCK));
708 InsertTailList(&(Process->HandleTable.ListHead),
709 &new_blk->entry);
710 new_blk->handles[0].ObjectBody = OB_POINTER_TO_ENTRY(ObjectBody);
711 if (Inherit)
712 new_blk->handles[0].ObjectBody = (PVOID)((ULONG_PTR)new_blk->handles[0].ObjectBody | OB_HANDLE_FLAG_INHERIT);
713 new_blk->handles[0].GrantedAccess = GrantedAccess;
714 new_blk->allocation_hint = 1;
715 new_blk->allocation_count++;
716 KeReleaseSpinLock(&HandleTable->ListLock, oldlvl);
717 *HandleReturn = (HANDLE)(handle << 2);
718 return(STATUS_SUCCESS);
719 }
720
721
722 /*
723 * @implemented
724 */
725 NTSTATUS STDCALL
726 ObQueryObjectAuditingByHandle(IN HANDLE Handle,
727 OUT PBOOLEAN GenerateOnClose)
728 {
729 PEPROCESS Process;
730 KIRQL oldIrql;
731 PHANDLE_ENTRY HandleEntry;
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 ASSERT_IRQL(PASSIVE_LEVEL);
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 ASSERT_IRQL(PASSIVE_LEVEL);
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 Access = DesiredAccess;
977 ObjectHeader = BODY_TO_HEADER(Object);
978
979 RtlMapGenericMask(&Access,
980 ObjectHeader->ObjectType->Mapping);
981
982 return(ObCreateHandle(PsGetCurrentProcess(),
983 Object,
984 Access,
985 ObjectHeader->Inherit,
986 Handle));
987 }
988
989
990 ULONG
991 ObpGetHandleCountByHandleTable(PHANDLE_TABLE HandleTable)
992 {
993 PHANDLE_BLOCK blk;
994 POBJECT_HEADER Header;
995 PVOID ObjectBody;
996 KIRQL OldIrql;
997 PLIST_ENTRY current;
998 ULONG i;
999 ULONG Count=0;
1000
1001 KeAcquireSpinLock(&HandleTable->ListLock, &OldIrql);
1002
1003 current = HandleTable->ListHead.Flink;
1004 while (current != &HandleTable->ListHead)
1005 {
1006 blk = CONTAINING_RECORD(current, HANDLE_BLOCK, entry);
1007
1008 for (i = 0; i < HANDLE_BLOCK_ENTRIES; i++)
1009 {
1010 ObjectBody = OB_ENTRY_TO_POINTER(blk->handles[i].ObjectBody);
1011 if (ObjectBody != NULL)
1012 {
1013 Header = BODY_TO_HEADER(ObjectBody);
1014
1015 /* Make sure this is real. */
1016 if (Header->ObjectType != NULL)
1017 Count++;
1018 }
1019 }
1020
1021 current = current->Flink;
1022 }
1023
1024 KeReleaseSpinLock(&HandleTable->ListLock,
1025 OldIrql);
1026
1027 return Count;
1028 }
1029
1030 /*
1031 * FUNCTION: Searches the handle table of a specified process whether it contains a
1032 * valid handle to the Object we're looking for. If not, it'll create one.
1033 *
1034 * NOTES:
1035 * The parameters of this function is basically a mixture of some of the parameters
1036 * of ObReferenceObjectByHandle() and ObReferenceObjectByPointer(). A little thinking
1037 * about what this function does (by it's name) makes clear what parameters it requires.
1038 * For example the AccessMode parameter of ObReferenceObjectByHandle/Pointer() is not
1039 * required at all as it only has influence on the object security. This function doesn't
1040 * want to get access to an object, it just looks for a valid handle and if it can't find
1041 * one, it'll just create one. It wouldn't make sense to check for security again as the
1042 * caller already has a pointer to the object.
1043 *
1044 * A test on an XP machine shows that this prototype appears to be correct.
1045 *
1046 * ARGUMENTS:
1047 * Process = This parameter simply describes in which handle table we're looking
1048 * for a handle to the object.
1049 * Object = The object pointer that we're looking for
1050 * ObjectType = Just a sanity check as ObReferenceObjectByHandle() and
1051 * ObReferenceObjectByPointer() provides.
1052 * HandleInformation = This one has to be the opposite meaning of the usage in
1053 * ObReferenceObjectByHandle(). If we actually found a valid
1054 * handle in the table, we need to check against the information
1055 * provided so we make sure this handle has all access rights
1056 * (and attributes?!) we need. If they don't match, we can't
1057 * use this handle and keep looking because the caller is likely
1058 * to depend on these access rights.
1059 * HandleReturn = The last parameter is the same as in ObCreateHandle(). If we could
1060 * find a suitable handle in the handle table, return this handle, if
1061 * not, we'll just create one using ObCreateHandle() with all access
1062 * rights the caller needs.
1063 *
1064 * RETURNS: Status
1065 *
1066 * @unimplemented
1067 */
1068 NTSTATUS STDCALL
1069 ObFindHandleForObject(IN PEPROCESS Process,
1070 IN PVOID Object,
1071 IN POBJECT_TYPE ObjectType,
1072 IN POBJECT_HANDLE_INFORMATION HandleInformation,
1073 OUT PHANDLE HandleReturn)
1074 {
1075 UNIMPLEMENTED;
1076 return STATUS_UNSUCCESSFUL;
1077 }
1078
1079 /* EOF */