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