Added testing for inheritable objects in NtDuplicateObject/ObCreateHandleTable.
[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.37 2002/05/07 22:38:29 hbirr 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) >> 2) - 1;
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 if (!SourceHandleRep->Inherit)
196 {
197 ObDereferenceObject(TargetProcess);
198 ObDereferenceObject(SourceProcess);
199 ObDereferenceObject(ObjectBody);
200 return STATUS_INVALID_HANDLE;
201 }
202
203 ObCreateHandle(TargetProcess,
204 ObjectBody,
205 DesiredAccess,
206 InheritHandle,
207 &TargetHandle);
208
209 if (Options & DUPLICATE_CLOSE_SOURCE)
210 {
211 ZwClose(SourceHandle);
212 }
213
214 ObDereferenceObject(TargetProcess);
215 ObDereferenceObject(SourceProcess);
216 ObDereferenceObject(ObjectBody);
217
218 Status = MmCopyToCaller(UnsafeTargetHandle, &TargetHandle, sizeof(HANDLE));
219 if (!NT_SUCCESS(Status))
220 {
221 return(Status);
222 }
223
224 return(STATUS_SUCCESS);
225 }
226
227 VOID ObCloseAllHandles(PEPROCESS Process)
228 {
229 KIRQL oldIrql;
230 PHANDLE_TABLE HandleTable;
231 PLIST_ENTRY current_entry;
232 PHANDLE_BLOCK current;
233 ULONG i;
234 PVOID ObjectBody;
235
236 DPRINT("ObCloseAllHandles(Process %x)\n", Process);
237
238 HandleTable = &Process->HandleTable;
239
240 KeAcquireSpinLock(&HandleTable->ListLock, &oldIrql);
241
242 current_entry = HandleTable->ListHead.Flink;
243
244 while (current_entry != &HandleTable->ListHead)
245 {
246 current = CONTAINING_RECORD(current_entry, HANDLE_BLOCK, entry);
247
248 for (i = 0; i < HANDLE_BLOCK_ENTRIES; i++)
249 {
250 ObjectBody = current->handles[i].ObjectBody;
251
252 if (ObjectBody != NULL)
253 {
254 POBJECT_HEADER Header = BODY_TO_HEADER(ObjectBody);
255
256 if (Header->ObjectType == PsProcessType ||
257 Header->ObjectType == PsThreadType)
258 {
259 DPRINT("Deleting handle to %x\n", ObjectBody);
260 }
261
262 ObReferenceObjectByPointer(ObjectBody,
263 0,
264 NULL,
265 UserMode);
266 InterlockedDecrement(&Header->HandleCount);
267 current->handles[i].ObjectBody = NULL;
268
269 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
270 KeDetachProcess();
271
272 if ((Header->ObjectType != NULL) &&
273 (Header->ObjectType->Close != NULL))
274 {
275 Header->ObjectType->Close(ObjectBody,
276 Header->HandleCount);
277 }
278
279 ObDereferenceObject(ObjectBody);
280 KeAttachProcess( Process );
281 KeAcquireSpinLock(&HandleTable->ListLock, &oldIrql);
282 current_entry = &HandleTable->ListHead;
283 break;
284 }
285 }
286
287 current_entry = current_entry->Flink;
288 }
289 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
290 DPRINT("ObCloseAllHandles() finished\n");
291 DPRINT("Type %x\n", BODY_TO_HEADER(Process)->ObjectType);
292 }
293
294 VOID ObDeleteHandleTable(PEPROCESS Process)
295 /*
296 * FUNCTION: Deletes the handle table associated with a process
297 */
298 {
299 PLIST_ENTRY current = NULL;
300 PHANDLE_TABLE HandleTable = NULL;
301
302 ObCloseAllHandles(Process);
303
304 HandleTable = &Process->HandleTable;
305 current = RemoveHeadList(&HandleTable->ListHead);
306
307 while (current != &HandleTable->ListHead)
308 {
309 HANDLE_BLOCK* HandleBlock = CONTAINING_RECORD(current,
310 HANDLE_BLOCK,
311 entry);
312 DPRINT("Freeing %x\n", HandleBlock);
313 ExFreePool(HandleBlock);
314
315 current = RemoveHeadList(&HandleTable->ListHead);
316 }
317 }
318
319
320 VOID ObCreateHandleTable(PEPROCESS Parent,
321 BOOLEAN Inherit,
322 PEPROCESS Process)
323 /*
324 * FUNCTION: Creates a handle table for a process
325 * ARGUMENTS:
326 * Parent = Parent process (or NULL if this is the first process)
327 * Inherit = True if the process should inherit its parent's handles
328 * Process = Process whose handle table is to be created
329 */
330 {
331 PHANDLE_TABLE ParentHandleTable, HandleTable;
332 KIRQL oldIrql;
333 PLIST_ENTRY parent_current;
334 ULONG i;
335 PHANDLE_BLOCK current_block, new_block;
336
337 DPRINT("ObCreateHandleTable(Parent %x, Inherit %d, Process %x)\n",
338 Parent,Inherit,Process);
339
340 InitializeListHead(&(Process->HandleTable.ListHead));
341 KeInitializeSpinLock(&(Process->HandleTable.ListLock));
342
343 if (Parent != NULL)
344 {
345 ParentHandleTable = &Parent->HandleTable;
346 HandleTable = &Process->HandleTable;
347
348 KeAcquireSpinLock(&Parent->HandleTable.ListLock, &oldIrql);
349 KeAcquireSpinLockAtDpcLevel(&Process->HandleTable.ListLock);
350
351 parent_current = ParentHandleTable->ListHead.Flink;
352
353 while (parent_current != &ParentHandleTable->ListHead)
354 {
355 current_block = CONTAINING_RECORD(parent_current,
356 HANDLE_BLOCK,
357 entry);
358 new_block = ExAllocatePoolWithTag(NonPagedPool,
359 sizeof(HANDLE_BLOCK),
360 TAG_HANDLE_TABLE);
361 if (new_block == NULL)
362 {
363 break;
364 }
365 RtlZeroMemory(new_block, sizeof(HANDLE_BLOCK));
366
367 for (i=0; i<HANDLE_BLOCK_ENTRIES; i++)
368 {
369 if (current_block->handles[i].ObjectBody)
370 {
371 if (current_block->handles[i].Inherit && Inherit)
372 {
373 new_block->handles[i].ObjectBody = current_block->handles[i].ObjectBody;
374 new_block->handles[i].GrantedAccess = current_block->handles[i].GrantedAccess;
375 new_block->handles[i].Inherit = TRUE;
376 InterlockedIncrement(&(BODY_TO_HEADER(current_block->handles[i].ObjectBody)->HandleCount));
377 }
378 }
379 }
380 InsertTailList(&(Process->HandleTable.ListHead), &new_block->entry);
381 parent_current = parent_current->Flink;
382 }
383 KeReleaseSpinLockFromDpcLevel(&Process->HandleTable.ListLock);
384 KeReleaseSpinLock(&Parent->HandleTable.ListLock, oldIrql);
385 }
386 }
387
388
389 PVOID ObDeleteHandle(PEPROCESS Process, HANDLE Handle)
390 {
391 PHANDLE_REP Rep;
392 PVOID ObjectBody;
393 KIRQL oldIrql;
394 PHANDLE_TABLE HandleTable;
395 POBJECT_HEADER Header;
396
397 DPRINT("ObDeleteHandle(Handle %x)\n",Handle);
398
399 HandleTable = &Process->HandleTable;
400
401 KeAcquireSpinLock(&HandleTable->ListLock, &oldIrql);
402
403 Rep = ObpGetObjectByHandle(HandleTable, Handle);
404 if (Rep == NULL)
405 {
406 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
407 return(NULL);
408 }
409
410 ObjectBody = Rep->ObjectBody;
411 DPRINT("ObjectBody %x\n", ObjectBody);
412 if (ObjectBody != NULL)
413 {
414 Header = BODY_TO_HEADER(ObjectBody);
415 InterlockedDecrement(&(BODY_TO_HEADER(ObjectBody)->HandleCount));
416 ObReferenceObjectByPointer(ObjectBody,
417 0,
418 NULL,
419 UserMode);
420 Rep->ObjectBody = NULL;
421
422 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
423
424 if ((Header->ObjectType != NULL) &&
425 (Header->ObjectType->Close != NULL))
426 {
427 Header->ObjectType->Close(ObjectBody, Header->HandleCount);
428 }
429 }
430 else
431 {
432 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
433 }
434
435 DPRINT("Finished ObDeleteHandle()\n");
436 return(ObjectBody);
437 }
438
439
440 NTSTATUS ObCreateHandle(PEPROCESS Process,
441 PVOID ObjectBody,
442 ACCESS_MASK GrantedAccess,
443 BOOLEAN Inherit,
444 PHANDLE HandleReturn)
445 /*
446 * FUNCTION: Add a handle referencing an object
447 * ARGUMENTS:
448 * obj = Object body that the handle should refer to
449 * RETURNS: The created handle
450 * NOTE: The handle is valid only in the context of the current process
451 */
452 {
453 LIST_ENTRY* current;
454 unsigned int handle=1;
455 unsigned int i;
456 HANDLE_BLOCK* new_blk = NULL;
457 PHANDLE_TABLE HandleTable;
458 KIRQL oldlvl;
459
460 DPRINT("ObCreateHandle(Process %x, obj %x)\n",Process,ObjectBody);
461
462 assert(Process);
463
464 if (ObjectBody != NULL)
465 {
466 InterlockedIncrement(&(BODY_TO_HEADER(ObjectBody)->HandleCount));
467 }
468 HandleTable = &Process->HandleTable;
469 KeAcquireSpinLock(&HandleTable->ListLock, &oldlvl);
470 current = HandleTable->ListHead.Flink;
471 /*
472 * Scan through the currently allocated handle blocks looking for a free
473 * slot
474 */
475 while (current != (&HandleTable->ListHead))
476 {
477 HANDLE_BLOCK* blk = CONTAINING_RECORD(current,HANDLE_BLOCK,entry);
478
479 DPRINT("Current %x\n",current);
480
481 for (i=0;i<HANDLE_BLOCK_ENTRIES;i++)
482 {
483 DPRINT("Considering slot %d containing %x\n",i,blk->handles[i]);
484 if (blk->handles[i].ObjectBody==NULL)
485 {
486 blk->handles[i].ObjectBody = ObjectBody;
487 blk->handles[i].GrantedAccess = GrantedAccess;
488 blk->handles[i].Inherit = Inherit;
489 KeReleaseSpinLock(&HandleTable->ListLock, oldlvl);
490 *HandleReturn = (HANDLE)((handle + i) << 2);
491 return(STATUS_SUCCESS);
492 }
493 }
494
495 handle = handle + HANDLE_BLOCK_ENTRIES;
496 current = current->Flink;
497 }
498
499 /*
500 * Add a new handle block to the end of the list
501 */
502 new_blk =
503 (HANDLE_BLOCK *)ExAllocatePoolWithTag(NonPagedPool,sizeof(HANDLE_BLOCK),
504 TAG_HANDLE_TABLE);
505 if (!new_blk)
506 {
507 *HandleReturn = (PHANDLE)NULL;
508 return(STATUS_INSUFFICIENT_RESOURCES);
509 }
510 RtlZeroMemory(new_blk,sizeof(HANDLE_BLOCK));
511 InsertTailList(&(Process->HandleTable.ListHead),
512 &new_blk->entry);
513 new_blk->handles[0].ObjectBody = ObjectBody;
514 new_blk->handles[0].GrantedAccess = GrantedAccess;
515 new_blk->handles[0].Inherit = Inherit;
516 KeReleaseSpinLock(&HandleTable->ListLock, oldlvl);
517 *HandleReturn = (HANDLE)(handle << 2);
518 return(STATUS_SUCCESS);
519 }
520
521
522 NTSTATUS STDCALL
523 ObReferenceObjectByHandle(HANDLE Handle,
524 ACCESS_MASK DesiredAccess,
525 POBJECT_TYPE ObjectType,
526 KPROCESSOR_MODE AccessMode,
527 PVOID* Object,
528 POBJECT_HANDLE_INFORMATION HandleInformationPtr)
529 /*
530 * FUNCTION: Increments the reference count for an object and returns a
531 * pointer to its body
532 * ARGUMENTS:
533 * Handle = Handle for the object
534 * DesiredAccess = Desired access to the object
535 * ObjectType
536 * AccessMode
537 * Object (OUT) = Points to the object body on return
538 * HandleInformation (OUT) = Contains information about the handle
539 * on return
540 * RETURNS: Status
541 */
542 {
543 PHANDLE_REP HandleRep;
544 POBJECT_HEADER ObjectHeader;
545 KIRQL oldIrql;
546 PVOID ObjectBody;
547 ACCESS_MASK GrantedAccess;
548
549 ASSERT_IRQL(PASSIVE_LEVEL);
550
551 DPRINT("ObReferenceObjectByHandle(Handle %x, DesiredAccess %x, "
552 "ObjectType %x, AccessMode %d, Object %x)\n",Handle,DesiredAccess,
553 ObjectType,AccessMode,Object);
554
555
556 /*
557 * Handle special handle names
558 */
559 if (Handle == NtCurrentProcess() &&
560 (ObjectType == PsProcessType || ObjectType == NULL))
561 {
562 DPRINT("Reference from %x\n", ((PULONG)&Handle)[-1]);
563
564 ObReferenceObjectByPointer(PsGetCurrentProcess(),
565 PROCESS_ALL_ACCESS,
566 PsProcessType,
567 UserMode);
568 *Object = PsGetCurrentProcess();
569 DPRINT("Referencing current process %x\n", PsGetCurrentProcess());
570 return(STATUS_SUCCESS);
571 }
572 else if (Handle == NtCurrentProcess())
573 {
574 CHECKPOINT;
575 return(STATUS_OBJECT_TYPE_MISMATCH);
576 }
577 if (Handle == NtCurrentThread() &&
578 (ObjectType == PsThreadType || ObjectType == NULL))
579 {
580 ObReferenceObjectByPointer(PsGetCurrentThread(),
581 THREAD_ALL_ACCESS,
582 PsThreadType,
583 UserMode);
584 *Object = PsGetCurrentThread();
585 CHECKPOINT;
586 return(STATUS_SUCCESS);
587 }
588 else if (Handle == NtCurrentThread())
589 {
590 CHECKPOINT;
591 return(STATUS_OBJECT_TYPE_MISMATCH);
592 }
593
594 KeAcquireSpinLock(&PsGetCurrentProcess()->HandleTable.ListLock,
595 &oldIrql);
596 HandleRep = ObpGetObjectByHandle(&PsGetCurrentProcess()->HandleTable,
597 Handle);
598 if (HandleRep == NULL || HandleRep->ObjectBody == NULL)
599 {
600 KeReleaseSpinLock(&PsGetCurrentProcess()->HandleTable.ListLock,
601 oldIrql);
602 return(STATUS_INVALID_HANDLE);
603 }
604 ObjectBody = HandleRep->ObjectBody;
605 DPRINT("ObjectBody %p\n",ObjectBody);
606 ObjectHeader = BODY_TO_HEADER(ObjectBody);
607 DPRINT("ObjectHeader->RefCount %lu\n",ObjectHeader->RefCount);
608 ObReferenceObjectByPointer(ObjectBody,
609 0,
610 NULL,
611 UserMode);
612 GrantedAccess = HandleRep->GrantedAccess;
613 KeReleaseSpinLock(&PsGetCurrentProcess()->HandleTable.ListLock,
614 oldIrql);
615
616 ObjectHeader = BODY_TO_HEADER(ObjectBody);
617 DPRINT("ObjectHeader->RefCount %lu\n",ObjectHeader->RefCount);
618
619 if (ObjectType != NULL && ObjectType != ObjectHeader->ObjectType)
620 {
621 CHECKPOINT;
622 return(STATUS_OBJECT_TYPE_MISMATCH);
623 }
624
625 if (ObjectHeader->ObjectType == PsProcessType)
626 {
627 DPRINT("Reference from %x\n", ((PULONG)&Handle)[-1]);
628 }
629
630 if (AccessMode == UserMode)
631 {
632 RtlMapGenericMask(&DesiredAccess, ObjectHeader->ObjectType->Mapping);
633
634 if (!(GrantedAccess & DesiredAccess) &&
635 !((~GrantedAccess) & DesiredAccess))
636 {
637 CHECKPOINT;
638 return(STATUS_ACCESS_DENIED);
639 }
640 }
641
642 *Object = ObjectBody;
643
644 CHECKPOINT;
645 return(STATUS_SUCCESS);
646 }
647
648
649 /**********************************************************************
650 * NAME EXPORTED
651 * NtClose
652 *
653 * DESCRIPTION
654 * Closes a handle reference to an object.
655 *
656 * ARGUMENTS
657 * Handle
658 * Handle to close.
659 *
660 * RETURN VALUE
661 * Status.
662 */
663 NTSTATUS STDCALL NtClose(HANDLE Handle)
664 {
665 PVOID ObjectBody;
666 POBJECT_HEADER Header;
667
668 assert_irql(PASSIVE_LEVEL);
669
670 DPRINT("NtClose(Handle %x)\n",Handle);
671
672 ObjectBody = ObDeleteHandle(PsGetCurrentProcess(), Handle);
673 if (ObjectBody == NULL)
674 {
675 return(STATUS_INVALID_HANDLE);
676 }
677
678 Header = BODY_TO_HEADER(ObjectBody);
679
680 DPRINT("Dereferencing %x\n", ObjectBody);
681 ObDereferenceObject(ObjectBody);
682
683 return(STATUS_SUCCESS);
684 }
685
686 NTSTATUS STDCALL
687 ObInsertObject(PVOID Object,
688 PACCESS_STATE PassedAccessState,
689 ACCESS_MASK DesiredAccess,
690 ULONG AdditionalReferences,
691 PVOID* ReferencedObject,
692 PHANDLE Handle)
693 {
694 return(ObCreateHandle(PsGetCurrentProcess(),
695 Object,
696 DesiredAccess,
697 FALSE,
698 Handle));
699 }
700
701 /* EOF */