xref: /reactos/ntoskrnl/ob/obref.c (revision f9c603db)
1 /*
2  * PROJECT:         ReactOS Kernel
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            ntoskrnl/ob/obref.c
5  * PURPOSE:         Manages the referencing and de-referencing of all Objects,
6  *                  as well as the Object Fast Reference implementation.
7  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
8  *                  Eric Kohl
9  *                  Thomas Weidenmueller (w3seek@reactos.org)
10  */
11 
12 /* INCLUDES ******************************************************************/
13 
14 #include <ntoskrnl.h>
15 #define NDEBUG
16 #include <debug.h>
17 
18 /* PRIVATE FUNCTIONS *********************************************************/
19 
20 BOOLEAN
21 FASTCALL
ObReferenceObjectSafe(IN PVOID Object)22 ObReferenceObjectSafe(IN PVOID Object)
23 {
24     POBJECT_HEADER ObjectHeader;
25     LONG_PTR OldValue, NewValue;
26 
27     /* Get the object header */
28     ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
29 
30     /* Get the current reference count and fail if it's zero */
31     OldValue = ObjectHeader->PointerCount;
32     if (!OldValue) return FALSE;
33 
34     /* Start reference loop */
35     do
36     {
37         /* Increase the reference count */
38         NewValue = InterlockedCompareExchangeSizeT(&ObjectHeader->PointerCount,
39                                                    OldValue + 1,
40                                                    OldValue);
41         if (OldValue == NewValue) return TRUE;
42 
43         /* Keep looping */
44         OldValue = NewValue;
45     } while (OldValue);
46 
47     /* If we got here, then the reference count is now 0 */
48     return FALSE;
49 }
50 
51 VOID
52 NTAPI
ObpDeferObjectDeletion(IN POBJECT_HEADER Header)53 ObpDeferObjectDeletion(IN POBJECT_HEADER Header)
54 {
55     PVOID Entry;
56 
57     /* Loop while trying to update the list */
58     do
59     {
60         /* Get the current entry */
61         Entry = ObpReaperList;
62 
63         /* Link our object to the list */
64         Header->NextToFree = Entry;
65 
66         /* Update the list */
67     } while (InterlockedCompareExchangePointer(&ObpReaperList,
68                                                Header,
69                                                Entry) != Entry);
70 
71     /* Queue the work item if needed */
72     if (!Entry) ExQueueWorkItem(&ObpReaperWorkItem, CriticalWorkQueue);
73 }
74 
75 LONG
76 FASTCALL
ObReferenceObjectEx(IN PVOID Object,IN LONG Count)77 ObReferenceObjectEx(IN PVOID Object,
78                     IN LONG Count)
79 {
80     /* Increment the reference count and return the count now */
81     return InterlockedExchangeAddSizeT(&OBJECT_TO_OBJECT_HEADER(Object)->
82                                        PointerCount,
83                                        Count) + Count;
84 }
85 
86 LONG
87 FASTCALL
ObDereferenceObjectEx(IN PVOID Object,IN LONG Count)88 ObDereferenceObjectEx(IN PVOID Object,
89                       IN LONG Count)
90 {
91     POBJECT_HEADER Header;
92     LONG_PTR NewCount;
93 
94     /* Extract the object header */
95     Header = OBJECT_TO_OBJECT_HEADER(Object);
96 
97     /* Check whether the object can now be deleted. */
98     NewCount = InterlockedExchangeAddSizeT(&Header->PointerCount, -Count) - Count;
99     if (!NewCount) ObpDeferObjectDeletion(Header);
100 
101     /* Return the current count */
102     return NewCount;
103 }
104 
105 VOID
106 FASTCALL
ObInitializeFastReference(IN PEX_FAST_REF FastRef,IN PVOID Object OPTIONAL)107 ObInitializeFastReference(IN PEX_FAST_REF FastRef,
108                           IN PVOID Object OPTIONAL)
109 {
110     /* Check if we were given an object and reference it 7 times */
111     if (Object) ObReferenceObjectEx(Object, MAX_FAST_REFS);
112 
113     /* Setup the fast reference */
114     ExInitializeFastReference(FastRef, Object);
115 }
116 
117 PVOID
118 FASTCALL
ObFastReferenceObjectLocked(IN PEX_FAST_REF FastRef)119 ObFastReferenceObjectLocked(IN PEX_FAST_REF FastRef)
120 {
121     PVOID Object;
122     EX_FAST_REF OldValue = *FastRef;
123 
124     /* Get the object and reference it slowly */
125     Object = ExGetObjectFastReference(OldValue);
126     if (Object) ObReferenceObject(Object);
127     return Object;
128 }
129 
130 PVOID
131 FASTCALL
ObFastReferenceObject(IN PEX_FAST_REF FastRef)132 ObFastReferenceObject(IN PEX_FAST_REF FastRef)
133 {
134     EX_FAST_REF OldValue;
135     ULONG_PTR Count;
136     PVOID Object;
137 
138     /* Reference the object and get it pointer */
139     OldValue = ExAcquireFastReference(FastRef);
140     Object = ExGetObjectFastReference(OldValue);
141 
142     /* Check how many references are left */
143     Count = ExGetCountFastReference(OldValue);
144 
145     /* Check if the reference count is over 1 */
146     if (Count > 1) return Object;
147 
148     /* Check if the reference count has reached 0 */
149     if (!Count) return NULL;
150 
151     /* Otherwise, reference the object 7 times */
152     ObReferenceObjectEx(Object, MAX_FAST_REFS);
153 
154     /* Now update the reference count */
155     if (!ExInsertFastReference(FastRef, Object))
156     {
157         /* We failed: completely dereference the object */
158         ObDereferenceObjectEx(Object, MAX_FAST_REFS);
159     }
160 
161     /* Return the Object */
162     return Object;
163 }
164 
165 VOID
166 FASTCALL
ObFastDereferenceObject(IN PEX_FAST_REF FastRef,IN PVOID Object)167 ObFastDereferenceObject(IN PEX_FAST_REF FastRef,
168                         IN PVOID Object)
169 {
170     /* Release a fast reference. If this failed, use the slow path */
171     if (!ExReleaseFastReference(FastRef, Object)) ObDereferenceObject(Object);
172 }
173 
174 PVOID
175 FASTCALL
ObFastReplaceObject(IN PEX_FAST_REF FastRef,PVOID Object)176 ObFastReplaceObject(IN PEX_FAST_REF FastRef,
177                     PVOID Object)
178 {
179     EX_FAST_REF OldValue;
180     PVOID OldObject;
181     ULONG Count;
182 
183     /* Check if we were given an object and reference it 7 times */
184     if (Object) ObReferenceObjectEx(Object, MAX_FAST_REFS);
185 
186     /* Do the swap */
187     OldValue = ExSwapFastReference(FastRef, Object);
188     OldObject = ExGetObjectFastReference(OldValue);
189 
190     /* Check if we had an active object and dereference it */
191     Count = ExGetCountFastReference(OldValue);
192     if ((OldObject) && (Count)) ObDereferenceObjectEx(OldObject, Count);
193 
194     /* Return the old object */
195     return OldObject;
196 }
197 
198 NTSTATUS
199 NTAPI
ObReferenceFileObjectForWrite(IN HANDLE Handle,IN KPROCESSOR_MODE AccessMode,OUT PFILE_OBJECT * FileObject,OUT POBJECT_HANDLE_INFORMATION HandleInformation)200 ObReferenceFileObjectForWrite(IN HANDLE Handle,
201                               IN KPROCESSOR_MODE AccessMode,
202                               OUT PFILE_OBJECT *FileObject,
203                               OUT POBJECT_HANDLE_INFORMATION HandleInformation)
204 {
205     NTSTATUS Status;
206     PHANDLE_TABLE HandleTable;
207     POBJECT_HEADER ObjectHeader;
208     PHANDLE_TABLE_ENTRY HandleEntry;
209     ACCESS_MASK GrantedAccess, DesiredAccess;
210 
211     /* Assume failure */
212     *FileObject = NULL;
213 
214     /* Check if this is a special handle */
215     if (HandleToLong(Handle) < 0)
216     {
217         /* Make sure we have a valid kernel handle */
218         if (AccessMode != KernelMode || Handle == NtCurrentProcess() || Handle == NtCurrentThread())
219         {
220             return STATUS_INVALID_HANDLE;
221         }
222 
223         /* Use the kernel handle table and get the actual handle value */
224         Handle = ObKernelHandleToHandle(Handle);
225         HandleTable = ObpKernelHandleTable;
226     }
227     else
228     {
229         /* Otherwise use this process's handle table */
230         HandleTable = PsGetCurrentProcess()->ObjectTable;
231     }
232 
233     ASSERT(HandleTable != NULL);
234     KeEnterCriticalRegion();
235 
236     /* Get the handle entry */
237     HandleEntry = ExMapHandleToPointer(HandleTable, Handle);
238     if (HandleEntry)
239     {
240         /* Get the object header and validate the type*/
241         ObjectHeader = ObpGetHandleObject(HandleEntry);
242 
243         /* Get the desired access from the file object */
244         if (!NT_SUCCESS(IoComputeDesiredAccessFileObject((PFILE_OBJECT)&ObjectHeader->Body,
245                         &DesiredAccess)))
246         {
247             Status = STATUS_OBJECT_TYPE_MISMATCH;
248         }
249         else
250         {
251             /* Extract the granted access from the handle entry */
252             if (BooleanFlagOn(NtGlobalFlag, FLG_KERNEL_STACK_TRACE_DB))
253             {
254                 /* FIXME: Translate granted access */
255                 GrantedAccess = HandleEntry->GrantedAccess;
256             }
257             else
258             {
259                 GrantedAccess = HandleEntry->GrantedAccess & ~ObpAccessProtectCloseBit;
260             }
261 
262             /* FIXME: Get handle information for audit */
263 
264             HandleInformation->GrantedAccess = GrantedAccess;
265 
266             /* FIXME: Get handle attributes */
267             HandleInformation->HandleAttributes = 0;
268 
269             /* Do granted and desired access match? */
270             if (GrantedAccess & DesiredAccess)
271             {
272                 /* FIXME: Audit access if required */
273 
274                 /* Reference the object directly since we have its header */
275                 InterlockedIncrementSizeT(&ObjectHeader->PointerCount);
276 
277                 /* Unlock the handle */
278                 ExUnlockHandleTableEntry(HandleTable, HandleEntry);
279                 KeLeaveCriticalRegion();
280 
281                 *FileObject = (PFILE_OBJECT)&ObjectHeader->Body;
282 
283                 /* Return success */
284                 ASSERT(*FileObject != NULL);
285                 return STATUS_SUCCESS;
286             }
287 
288             /* No match, deny write access */
289             Status = STATUS_ACCESS_DENIED;
290 
291             ExUnlockHandleTableEntry(HandleTable, HandleEntry);
292         }
293     }
294     else
295     {
296         Status = STATUS_INVALID_HANDLE;
297     }
298 
299     /* Return failure status */
300     KeLeaveCriticalRegion();
301     return Status;
302 }
303 
304 /* PUBLIC FUNCTIONS *********************************************************/
305 
306 LONG_PTR
307 FASTCALL
ObfReferenceObject(IN PVOID Object)308 ObfReferenceObject(IN PVOID Object)
309 {
310     ASSERT(Object);
311 
312     /* Get the header and increment the reference count */
313     return InterlockedIncrementSizeT(&OBJECT_TO_OBJECT_HEADER(Object)->PointerCount);
314 }
315 
316 LONG_PTR
317 FASTCALL
ObfDereferenceObject(IN PVOID Object)318 ObfDereferenceObject(IN PVOID Object)
319 {
320     POBJECT_HEADER Header;
321     LONG_PTR NewCount;
322 
323     /* Extract the object header */
324     Header = OBJECT_TO_OBJECT_HEADER(Object);
325 
326     if (Header->PointerCount < Header->HandleCount)
327     {
328         DPRINT1("Misbehaving object: %wZ\n", &Header->Type->Name);
329         return Header->PointerCount;
330     }
331 
332     /* Check whether the object can now be deleted. */
333     NewCount = InterlockedDecrementSizeT(&Header->PointerCount);
334     if (!NewCount)
335     {
336         /* Sanity check */
337         ASSERT(Header->HandleCount == 0);
338 
339         /* Check if APCs are still active */
340         if (!KeAreAllApcsDisabled())
341         {
342             /* Remove the object */
343             ObpDeleteObject(Object, FALSE);
344         }
345         else
346         {
347             /* Add us to the deferred deletion list */
348             ObpDeferObjectDeletion(Header);
349         }
350     }
351 
352     /* Return the new count */
353     return NewCount;
354 }
355 
356 VOID
357 NTAPI
ObDereferenceObjectDeferDelete(IN PVOID Object)358 ObDereferenceObjectDeferDelete(IN PVOID Object)
359 {
360     POBJECT_HEADER Header = OBJECT_TO_OBJECT_HEADER(Object);
361 
362     /* Check whether the object can now be deleted. */
363     if (!InterlockedDecrementSizeT(&Header->PointerCount))
364     {
365         /* Add us to the deferred deletion list */
366         ObpDeferObjectDeletion(Header);
367     }
368 }
369 
370 #undef ObDereferenceObject
371 VOID
372 NTAPI
ObDereferenceObject(IN PVOID Object)373 ObDereferenceObject(IN PVOID Object)
374 {
375     /* Call the fastcall function */
376     ObfDereferenceObject(Object);
377 }
378 
379 NTSTATUS
380 NTAPI
ObReferenceObjectByPointer(IN PVOID Object,IN ACCESS_MASK DesiredAccess,IN POBJECT_TYPE ObjectType,IN KPROCESSOR_MODE AccessMode)381 ObReferenceObjectByPointer(IN PVOID Object,
382                            IN ACCESS_MASK DesiredAccess,
383                            IN POBJECT_TYPE ObjectType,
384                            IN KPROCESSOR_MODE AccessMode)
385 {
386     POBJECT_HEADER Header;
387 
388     /* Get the header */
389     Header = OBJECT_TO_OBJECT_HEADER(Object);
390 
391     /*
392      * Validate object type if the call is for UserMode.
393      * NOTE: Unless it's a symbolic link (Caz Yokoyama [MSFT])
394      */
395     if ((Header->Type != ObjectType) && ((AccessMode != KernelMode) ||
396         (ObjectType == ObpSymbolicLinkObjectType)))
397     {
398         /* Invalid type */
399         return STATUS_OBJECT_TYPE_MISMATCH;
400     }
401 
402     /* Increment the reference count and return success */
403     InterlockedIncrementSizeT(&Header->PointerCount);
404     return STATUS_SUCCESS;
405 }
406 
407 NTSTATUS
408 NTAPI
ObReferenceObjectByName(IN PUNICODE_STRING ObjectPath,IN ULONG Attributes,IN PACCESS_STATE PassedAccessState,IN ACCESS_MASK DesiredAccess,IN POBJECT_TYPE ObjectType,IN KPROCESSOR_MODE AccessMode,IN OUT PVOID ParseContext,OUT PVOID * ObjectPtr)409 ObReferenceObjectByName(IN PUNICODE_STRING ObjectPath,
410                         IN ULONG Attributes,
411                         IN PACCESS_STATE PassedAccessState,
412                         IN ACCESS_MASK DesiredAccess,
413                         IN POBJECT_TYPE ObjectType,
414                         IN KPROCESSOR_MODE AccessMode,
415                         IN OUT PVOID ParseContext,
416                         OUT PVOID* ObjectPtr)
417 {
418     PVOID Object = NULL;
419     UNICODE_STRING ObjectName;
420     NTSTATUS Status;
421     OBP_LOOKUP_CONTEXT Context;
422     AUX_ACCESS_DATA AuxData;
423     ACCESS_STATE AccessState;
424     PAGED_CODE();
425 
426     /* Fail quickly */
427     if (!ObjectPath) return STATUS_OBJECT_NAME_INVALID;
428 
429     /* Capture the name */
430     Status = ObpCaptureObjectName(&ObjectName, ObjectPath, AccessMode, TRUE);
431     if (!NT_SUCCESS(Status)) return Status;
432 
433     /* We also need a valid name after capture */
434     if (!ObjectName.Length) return STATUS_OBJECT_NAME_INVALID;
435 
436     /* Check if we didn't get an access state */
437     if (!PassedAccessState)
438     {
439         /* Use our built-in access state */
440         PassedAccessState = &AccessState;
441         Status = SeCreateAccessState(&AccessState,
442                                      &AuxData,
443                                      DesiredAccess,
444                                      &ObjectType->TypeInfo.GenericMapping);
445         if (!NT_SUCCESS(Status)) goto Quickie;
446     }
447 
448     /* Find the object */
449     *ObjectPtr = NULL;
450     Status = ObpLookupObjectName(NULL,
451                                  &ObjectName,
452                                  Attributes,
453                                  ObjectType,
454                                  AccessMode,
455                                  ParseContext,
456                                  NULL,
457                                  NULL,
458                                  PassedAccessState,
459                                  &Context,
460                                  &Object);
461 
462     /* Cleanup after lookup */
463     ObpReleaseLookupContext(&Context);
464 
465     /* Check if the lookup succeeded */
466     if (NT_SUCCESS(Status))
467     {
468         /* Check if access is allowed */
469         if (ObpCheckObjectReference(Object,
470                                     PassedAccessState,
471                                     FALSE,
472                                     AccessMode,
473                                     &Status))
474         {
475             /* Return the object */
476             *ObjectPtr = Object;
477         }
478     }
479 
480     /* Free the access state */
481     if (PassedAccessState == &AccessState)
482     {
483         SeDeleteAccessState(PassedAccessState);
484     }
485 
486 Quickie:
487     /* Free the captured name if we had one, and return status */
488     ObpFreeObjectNameBuffer(&ObjectName);
489     return Status;
490 }
491 
492 NTSTATUS
493 NTAPI
ObReferenceObjectByHandle(IN HANDLE Handle,IN ACCESS_MASK DesiredAccess,IN POBJECT_TYPE ObjectType,IN KPROCESSOR_MODE AccessMode,OUT PVOID * Object,OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL)494 ObReferenceObjectByHandle(IN HANDLE Handle,
495                           IN ACCESS_MASK DesiredAccess,
496                           IN POBJECT_TYPE ObjectType,
497                           IN KPROCESSOR_MODE AccessMode,
498                           OUT PVOID* Object,
499                           OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL)
500 {
501     PHANDLE_TABLE_ENTRY HandleEntry;
502     POBJECT_HEADER ObjectHeader;
503     ACCESS_MASK GrantedAccess;
504     ULONG Attributes;
505     PEPROCESS CurrentProcess;
506     PVOID HandleTable;
507     PETHREAD CurrentThread;
508     NTSTATUS Status;
509     PAGED_CODE();
510 
511     /* Assume failure */
512     *Object = NULL;
513 
514     /* Check if this is a special handle */
515     if (HandleToLong(Handle) < 0)
516     {
517         /* Check if this is the current process */
518         if (Handle == NtCurrentProcess())
519         {
520             /* Check if this is the right object type */
521             if ((ObjectType == PsProcessType) || !(ObjectType))
522             {
523                 /* Get the current process and granted access */
524                 CurrentProcess = PsGetCurrentProcess();
525                 GrantedAccess = CurrentProcess->GrantedAccess;
526 
527                 /* Validate access */
528                 /* ~GrantedAccess = RefusedAccess.*/
529                 /* ~GrantedAccess & DesiredAccess = list of refused bits. */
530                 /* !(~GrantedAccess & DesiredAccess) == TRUE means ALL requested rights are granted */
531                 if ((AccessMode == KernelMode) ||
532                     !(~GrantedAccess & DesiredAccess))
533                 {
534                     /* Check if the caller wanted handle information */
535                     if (HandleInformation)
536                     {
537                         /* Return it */
538                         HandleInformation->HandleAttributes = 0;
539                         HandleInformation->GrantedAccess = GrantedAccess;
540                     }
541 
542                     /* Reference ourselves */
543                     ObjectHeader = OBJECT_TO_OBJECT_HEADER(CurrentProcess);
544                     InterlockedExchangeAddSizeT(&ObjectHeader->PointerCount, 1);
545 
546                     /* Return the pointer */
547                     *Object = CurrentProcess;
548                     ASSERT(*Object != NULL);
549                     Status = STATUS_SUCCESS;
550                 }
551                 else
552                 {
553                     /* Access denied */
554                     Status = STATUS_ACCESS_DENIED;
555                 }
556             }
557             else
558             {
559                 /* The caller used this special handle value with a non-process type */
560                 Status = STATUS_OBJECT_TYPE_MISMATCH;
561             }
562 
563             /* Return the status */
564             return Status;
565         }
566         else if (Handle == NtCurrentThread())
567         {
568             /* Check if this is the right object type */
569             if ((ObjectType == PsThreadType) || !(ObjectType))
570             {
571                 /* Get the current process and granted access */
572                 CurrentThread = PsGetCurrentThread();
573                 GrantedAccess = CurrentThread->GrantedAccess;
574 
575                 /* Validate access */
576                 /* ~GrantedAccess = RefusedAccess.*/
577                 /* ~GrantedAccess & DesiredAccess = list of refused bits. */
578                 /* !(~GrantedAccess & DesiredAccess) == TRUE means ALL requested rights are granted */
579                 if ((AccessMode == KernelMode) ||
580                     !(~GrantedAccess & DesiredAccess))
581                 {
582                     /* Check if the caller wanted handle information */
583                     if (HandleInformation)
584                     {
585                         /* Return it */
586                         HandleInformation->HandleAttributes = 0;
587                         HandleInformation->GrantedAccess = GrantedAccess;
588                     }
589 
590                     /* Reference ourselves */
591                     ObjectHeader = OBJECT_TO_OBJECT_HEADER(CurrentThread);
592                     InterlockedExchangeAddSizeT(&ObjectHeader->PointerCount, 1);
593 
594                     /* Return the pointer */
595                     *Object = CurrentThread;
596                     ASSERT(*Object != NULL);
597                     Status = STATUS_SUCCESS;
598                 }
599                 else
600                 {
601                     /* Access denied */
602                     Status = STATUS_ACCESS_DENIED;
603                 }
604             }
605             else
606             {
607                 /* The caller used this special handle value with a non-process type */
608                 Status = STATUS_OBJECT_TYPE_MISMATCH;
609             }
610 
611             /* Return the status */
612             return Status;
613         }
614         else if (AccessMode == KernelMode)
615         {
616             /* Use the kernel handle table and get the actual handle value */
617             Handle = ObKernelHandleToHandle(Handle);
618             HandleTable = ObpKernelHandleTable;
619         }
620         else
621         {
622             /* Invalid access, fail */
623             return STATUS_INVALID_HANDLE;
624         }
625     }
626     else
627     {
628         /* Otherwise use this process's handle table */
629         HandleTable = PsGetCurrentProcess()->ObjectTable;
630     }
631 
632     /* Enter a critical region while we touch the handle table */
633     ASSERT(HandleTable != NULL);
634     KeEnterCriticalRegion();
635 
636     /* Get the handle entry */
637     HandleEntry = ExMapHandleToPointer(HandleTable, Handle);
638     if (HandleEntry)
639     {
640         /* Get the object header and validate the type*/
641         ObjectHeader = ObpGetHandleObject(HandleEntry);
642         if (!(ObjectType) || (ObjectType == ObjectHeader->Type))
643         {
644             /* Get the granted access and validate it */
645             GrantedAccess = HandleEntry->GrantedAccess;
646 
647             /* Validate access */
648             /* ~GrantedAccess = RefusedAccess.*/
649             /* ~GrantedAccess & DesiredAccess = list of refused bits. */
650             /* !(~GrantedAccess & DesiredAccess) == TRUE means ALL requested rights are granted */
651             if ((AccessMode == KernelMode) ||
652                 !(~GrantedAccess & DesiredAccess))
653             {
654                 /* Reference the object directly since we have its header */
655                 InterlockedIncrementSizeT(&ObjectHeader->PointerCount);
656 
657                 /* Mask out the internal attributes */
658                 Attributes = HandleEntry->ObAttributes & OBJ_HANDLE_ATTRIBUTES;
659 
660                 /* Check if the caller wants handle information */
661                 if (HandleInformation)
662                 {
663                     /* Fill out the information */
664                     HandleInformation->HandleAttributes = Attributes;
665                     HandleInformation->GrantedAccess = GrantedAccess;
666                 }
667 
668                 /* Return the pointer */
669                 *Object = &ObjectHeader->Body;
670 
671                 /* Unlock the handle */
672                 ExUnlockHandleTableEntry(HandleTable, HandleEntry);
673                 KeLeaveCriticalRegion();
674 
675                 /* Return success */
676                 ASSERT(*Object != NULL);
677                 return STATUS_SUCCESS;
678             }
679             else
680             {
681                 /* Requested access failed */
682                 DPRINT("Rights not granted: %x\n", ~GrantedAccess & DesiredAccess);
683                 Status = STATUS_ACCESS_DENIED;
684             }
685         }
686         else
687         {
688             /* Invalid object type */
689             Status = STATUS_OBJECT_TYPE_MISMATCH;
690         }
691 
692         /* Unlock the entry */
693         ExUnlockHandleTableEntry(HandleTable, HandleEntry);
694     }
695     else
696     {
697         /* Invalid handle */
698         Status = STATUS_INVALID_HANDLE;
699     }
700 
701     /* Return failure status */
702     KeLeaveCriticalRegion();
703     *Object = NULL;
704     return Status;
705 }
706 
707 /* EOF */
708