test: obhandle.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# obhandle.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1989  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     obhandle.c
    00008
    00009 Abstract:
    00010
    00011     Object handle routines
    00012
    00013 Author:
    00014
    00015     Steve Wood (stevewo) 31-Mar-1989
    00016
    00017 Revision History:
    00018
    00019 --*/
    00020
    00021 #include "obp.h"
    00022
    00023 //
    00024 //  Define logical sum of all generic accesses.
    00025 //
    00026
    00027 #define GENERIC_ACCESS (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL)
    00028
    00029 //
    00030 //  The following variable is declared in obinit.c and is used to protect the
    00031 //  process object table
    00032 //
    00033
    00034 extern KMUTANT ObpInitKillMutant;
    00035
    00036 //
    00037 // Define local prototypes
    00038 //
    00039
    00040 NTSTATUS
    00041 ObpIncrementHandleDataBase (
    00042     IN POBJECT_HEADER ObjectHeader,
    00043     IN PEPROCESS Process,
    00044     OUT PULONG NewProcessHandleCount
    00045     );
    00046
    00047 NTSTATUS
    00048 ObpCaptureHandleInformation (
    00049     IN OUT PSYSTEM_HANDLE_TABLE_ENTRY_INFO *HandleEntryInfo,
    00050     IN HANDLE UniqueProcessId,
    00051     IN PVOID HandleTableEntry,
    00052     IN HANDLE HandleIndex,
    00053     IN ULONG Length,
    00054     IN OUT PULONG RequiredLength
    00055     );
    00056
    00057 #ifdef ALLOC_PRAGMA
    00058 #pragma alloc_text(PAGE,NtDuplicateObject)
    00059 #pragma alloc_text(PAGE,ObGetHandleInformation)
    00060 #pragma alloc_text(PAGE,ObpInsertHandleCount)
    00061 #pragma alloc_text(PAGE,ObpIncrementHandleCount)
    00062 #pragma alloc_text(PAGE,ObpIncrementUnnamedHandleCount)
    00063 #pragma alloc_text(PAGE,ObpDecrementHandleCount)
    00064 #pragma alloc_text(PAGE,ObpCreateHandle)
    00065 #pragma alloc_text(PAGE,ObpCreateUnnamedHandle)
    00066 #pragma alloc_text(PAGE,ObpIncrementHandleDataBase)
    00067 #endif
    00068
    00069
    00070 //
    00071 //  Define routines for incrementing and decrementing the object header
    00072 //  counters.  These routines are only used if MPSAFE handle count check
    00073 //  is defined
    00074 //
    00075
    00076 #ifdef MPSAFE_HANDLE_COUNT_CHECK
    00077
    00078 VOID
    00079 FASTCALL
    00080 ObpIncrPointerCount (
    00081     IN POBJECT_HEADER ObjectHeader
    00082     )
    00083 {
    00084     KIRQL OldIrql;
    00085
    00086     ExAcquireFastLock( &ObpLock, &OldIrql );
    00087     ObjectHeader->PointerCount += 1;
    00088     ExReleaseFastLock( &ObpLock, OldIrql );
    00089 }
    00090
    00091 VOID
    00092 FASTCALL
    00093 ObpDecrPointerCount (
    00094     IN POBJECT_HEADER ObjectHeader
    00095     )
    00096 {
    00097     KIRQL OldIrql;
    00098
    00099     ExAcquireFastLock( &ObpLock, &OldIrql );
    00100     ObjectHeader->PointerCount -= 1;
    00101     ExReleaseFastLock( &ObpLock, OldIrql );
    00102 }
    00103
    00104 BOOLEAN
    00105 FASTCALL
    00106 ObpDecrPointerCountWithResult (
    00107     IN POBJECT_HEADER ObjectHeader
    00108     )
    00109 {
    00110     KIRQL OldIrql;
    00111     LONG Result;
    00112
    00113     ExAcquireFastLock( &ObpLock, &OldIrql );
    00114
    00115     if (ObjectHeader->PointerCount <= ObjectHeader->HandleCount) {
    00116
    00117         DbgPrint( "OB: About to over-dereference object %x (ObjectHeader at %x)\n",
    00118                   ObjectHeader->Object, ObjectHeader );
    00119
    00120         DbgBreakPoint();
    00121     }
    00122
    00123     ObjectHeader->PointerCount -= 1;
    00124     Result = ObjectHeader->PointerCount;
    00125     ExReleaseFastLock( &ObpLock, OldIrql );
    00126     return Result == 0;
    00127 }
    00128
    00129 VOID
    00130 FASTCALL
    00131 ObpIncrHandleCount (
    00132     IN POBJECT_HEADER ObjectHeader
    00133     )
    00134 {
    00135     KIRQL OldIrql;
    00136
    00137     ExAcquireFastLock( &ObpLock, &OldIrql );
    00138     ObjectHeader->HandleCount += 1;
    00139     ExReleaseFastLock( &ObpLock, OldIrql );
    00140     }
    00141
    00142 BOOLEAN
    00143 FASTCALL
    00144 ObpDecrHandleCount (
    00145     IN POBJECT_HEADER ObjectHeader
    00146     )
    00147 {
    00148     KIRQL OldIrql;
    00149     LONG Old;
    00150
    00151     ExAcquireFastLock( &ObpLock, &OldIrql );
    00152     Old = ObjectHeader->HandleCount;
    00153     ObjectHeader->HandleCount -= 1;
    00154     ExReleaseFastLock( &ObpLock, OldIrql );
    00155
    00156     return Old == 1;
    00157 }
    00158
    00159 #endif // MPSAFE_HANDLE_COUNT_CHECK
    00160
    00161
    00162 NTSTATUS
    00163 NtDuplicateObject (
    00164     IN HANDLE SourceProcessHandle,
    00165     IN HANDLE SourceHandle,
    00166     IN HANDLE TargetProcessHandle OPTIONAL,
    00167     OUT PHANDLE TargetHandle OPTIONAL,
    00168     IN ACCESS_MASK DesiredAccess,
    00169     IN ULONG HandleAttributes,
    00170     IN ULONG Options
    00171     )
    00172
    00173 /*++
    00174
    00175 Routine Description:
    00176
    00177     This function creates a handle that is a duplicate of the specified
    00178     source handle.  The source handle is evaluated in the context of the
    00179     specified source process.  The calling process must have
    00180     PROCESS_DUP_HANDLE access to the source process.  The duplicate
    00181     handle is created with the specified attributes and desired access.
    00182     The duplicate handle is created in the handle table of the specified
    00183     target process.  The calling process must have PROCESS_DUP_HANDLE
    00184     access to the target process.
    00185
    00186 Arguments:
    00187
    00188     SourceProcessHandle - Supplies a handle to the source process for the
    00189         handle being duplicated
    00190
    00191     SourceHandle - Supplies the handle being duplicated
    00192
    00193     TargetProcessHandle - Optionally supplies a handle to the target process
    00194         that is to receive the new handle
    00195
    00196     TargetHandle - Optionally returns a the new duplicated handle
    00197
    00198     DesiredAccess - Desired access for the new handle
    00199
    00200     HandleAttributes - Desired attributes for the new handle
    00201
    00202     Options - Duplication options that control things like close source,
    00203         same access, and same attributes.
    00204
    00205 Return Value:
    00206
    00207     TBS
    00208
    00209 --*/
    00210
    00211 {
    00212     KPROCESSOR_MODE PreviousMode;
    00213     NTSTATUS Status;
    00214     PVOID SourceObject;
    00215     POBJECT_HEADER ObjectHeader;
    00216     POBJECT_TYPE ObjectType;
    00217     PEPROCESS SourceProcess;
    00218     PEPROCESS TargetProcess;
    00219     BOOLEAN Attached;
    00220     PVOID ObjectTable;
    00221     HANDLE_TABLE_ENTRY ObjectTableEntry;
    00222     OBJECT_HANDLE_INFORMATION HandleInformation;
    00223     HANDLE NewHandle;
    00224     ACCESS_STATE AccessState;
    00225     AUX_ACCESS_DATA AuxData;
    00226     ACCESS_MASK SourceAccess;
    00227     ACCESS_MASK TargetAccess;
    00228     PACCESS_STATE PassedAccessState = NULL;
    00229
    00230     //
    00231     //  Get previous processor mode and probe output arguments if necessary.
    00232     //
    00233
    00234     PreviousMode = KeGetPreviousMode();
    00235
    00236     if (ARGUMENT_PRESENT( TargetHandle ) && (PreviousMode != KernelMode)) {
    00237
    00238         try {
    00239
    00240             ProbeForWriteHandle( TargetHandle );
    00241
    00242         } except( EXCEPTION_EXECUTE_HANDLER ) {
    00243
    00244             return( GetExceptionCode() );
    00245         }
    00246     }
    00247
    00248     //
    00249     //  If the caller is not asking for the same access then
    00250     //  validate the access they are requesting doesn't contain
    00251     //  any bad bits
    00252     //
    00253
    00254     if (!(Options & DUPLICATE_SAME_ACCESS)) {
    00255
    00256         Status = ObpValidateDesiredAccess( DesiredAccess );
    00257
    00258         if (!NT_SUCCESS( Status )) {
    00259
    00260             return( Status );
    00261         }
    00262     }
    00263
    00264     //
    00265     //  The Attached variable indicates if we needed to
    00266     //  attach to the source process because it was not the
    00267     //  current process.
    00268     //
    00269
    00270     Attached = FALSE;
    00271
    00272     //
    00273     //  Given the input source process handle get a pointer
    00274     //  to the source process object
    00275     //
    00276
    00277     Status = ObReferenceObjectByHandle( SourceProcessHandle,
    00278                                         PROCESS_DUP_HANDLE,
    00279                                         PsProcessType,
    00280                                         PreviousMode,
    00281                                         (PVOID *)&SourceProcess,
    00282                                         NULL );
    00283
    00284     if (!NT_SUCCESS( Status )) {
    00285
    00286         return Status;
    00287     }
    00288
    00289     //
    00290     //  Lock down access to the process object tables
    00291     //
    00292
    00293     KeEnterCriticalRegion();
    00294
    00295     KeWaitForSingleObject( &ObpInitKillMutant,
    00296                            Executive,
    00297                            KernelMode,
    00298                            FALSE,
    00299                            NULL );
    00300
    00301     //
    00302     //  Make sure the source process has an object table still
    00303     //
    00304
    00305     if ( SourceProcess->ObjectTable == NULL ) {
    00306
    00307         KeReleaseMutant( &ObpInitKillMutant, 0, FALSE, FALSE );
    00308
    00309         KeLeaveCriticalRegion();
    00310
    00311         ObDereferenceObject( SourceProcess );
    00312
    00313         return STATUS_PROCESS_IS_TERMINATING;
    00314     }
    00315
    00316     //
    00317     //  If the specified source process is not the current process, attach
    00318     //  to the specified source process.  Then after we reference the object
    00319     //  we can detach from the process.
    00320     //
    00321
    00322     if (PsGetCurrentProcess() != SourceProcess) {
    00323
    00324         KeAttachProcess( &SourceProcess->Pcb );
    00325
    00326         Attached = TRUE;
    00327     }
    00328
    00329     //
    00330     //  The the input source handle get a pointer to the
    00331     //  source object itself, then detach from the process
    00332     //  if necessary and check if we were given a good
    00333     //  source handle.
    00334     //
    00335
    00336     Status = ObReferenceObjectByHandle( SourceHandle,
    00337                                         0,
    00338                                         (POBJECT_TYPE)NULL,
    00339                                         PreviousMode,
    00340                                         &SourceObject,
    00341                                         &HandleInformation );
    00342
    00343     if (Attached) {
    00344
    00345         KeDetachProcess();
    00346
    00347         Attached = FALSE;
    00348     }
    00349
    00350     if (!NT_SUCCESS( Status )) {
    00351
    00352         KeReleaseMutant( &ObpInitKillMutant, 0, FALSE, FALSE );
    00353
    00354         KeLeaveCriticalRegion();
    00355
    00356         ObDereferenceObject( SourceProcess );
    00357
    00358         return( Status );
    00359     }
    00360
    00361     //
    00362     //  We are all done if no target process handle was specified.
    00363     //  This is practially a noop because the only really end result
    00364     //  could be that we've closed the source handle.
    00365     //
    00366
    00367     if (!ARGUMENT_PRESENT( TargetProcessHandle )) {
    00368
    00369         //
    00370         //  If no TargetProcessHandle, then only possible option is to close
    00371         //  the source handle in the context of the source process.
    00372         //
    00373
    00374         if (!(Options & DUPLICATE_CLOSE_SOURCE)) {
    00375
    00376             Status = STATUS_INVALID_PARAMETER;
    00377         }
    00378
    00379         if (Options & DUPLICATE_CLOSE_SOURCE) {
    00380
    00381             KeAttachProcess( &SourceProcess->Pcb );
    00382
    00383             NtClose( SourceHandle );
    00384
    00385             KeDetachProcess();
    00386         }
    00387
    00388         KeReleaseMutant( &ObpInitKillMutant, 0, FALSE, FALSE );
    00389
    00390         KeLeaveCriticalRegion();
    00391
    00392         ObDereferenceObject( SourceObject );
    00393         ObDereferenceObject( SourceProcess );
    00394
    00395         return( Status );
    00396     }
    00397
    00398     SourceAccess = HandleInformation.GrantedAccess;
    00399
    00400     //
    00401     //  At this point the caller did specify for a target process
    00402     //  So from the target process handle get a pointer to the
    00403     //  target process object.
    00404     //
    00405
    00406     Status = ObReferenceObjectByHandle( TargetProcessHandle,
    00407                                         PROCESS_DUP_HANDLE,
    00408                                         PsProcessType,
    00409                                         PreviousMode,
    00410                                         (PVOID *)&TargetProcess,
    00411                                         NULL );
    00412
    00413     //
    00414     //  If we cannot get the traget process object then close the
    00415     //  source down if requsted, cleanup and return to our caller
    00416     //
    00417
    00418     if (!NT_SUCCESS( Status )) {
    00419
    00420         if (Options & DUPLICATE_CLOSE_SOURCE) {
    00421
    00422             KeAttachProcess( &SourceProcess->Pcb );
    00423
    00424             NtClose( SourceHandle );
    00425
    00426             KeDetachProcess();
    00427         }
    00428
    00429         KeReleaseMutant( &ObpInitKillMutant, 0, FALSE, FALSE );
    00430
    00431         KeLeaveCriticalRegion();
    00432
    00433         ObDereferenceObject( SourceObject );
    00434         ObDereferenceObject( SourceProcess );
    00435
    00436         return( Status );
    00437     }
    00438
    00439     //
    00440     //  Make sure the target process has not exited
    00441     //
    00442
    00443     if ( TargetProcess->ObjectTable == NULL ) {
    00444
    00445         if (Options & DUPLICATE_CLOSE_SOURCE) {
    00446
    00447             KeAttachProcess( &SourceProcess->Pcb );
    00448
    00449             NtClose( SourceHandle );
    00450
    00451             KeDetachProcess();
    00452         }
    00453
    00454         KeReleaseMutant( &ObpInitKillMutant, 0, FALSE, FALSE );
    00455
    00456         KeLeaveCriticalRegion();
    00457
    00458         ObDereferenceObject( SourceObject );
    00459         ObDereferenceObject( SourceProcess );
    00460         ObDereferenceObject( TargetProcess );
    00461
    00462         return STATUS_PROCESS_IS_TERMINATING;
    00463     }
    00464
    00465     //
    00466     //  If the specified target process is not the current process, attach
    00467     //  to the specified target process.
    00468     //
    00469
    00470     if (PsGetCurrentProcess() != TargetProcess) {
    00471
    00472         KeAttachProcess( &TargetProcess->Pcb );
    00473
    00474         Attached = TRUE;
    00475     }
    00476
    00477     //
    00478     //  Construct the proper desired access and attributes for the new handle
    00479     //
    00480
    00481     if (Options & DUPLICATE_SAME_ACCESS) {
    00482
    00483         DesiredAccess = SourceAccess;
    00484     }
    00485
    00486     if (Options & DUPLICATE_SAME_ATTRIBUTES) {
    00487
    00488         HandleAttributes = HandleInformation.HandleAttributes;
    00489
    00490     } else {
    00491
    00492         //
    00493         //  Always propogate auditing information.
    00494         //
    00495
    00496         HandleAttributes |= HandleInformation.HandleAttributes & OBJ_AUDIT_OBJECT_CLOSE;
    00497     }
    00498
    00499     //
    00500     //  Get the object header for the source object
    00501     //
    00502
    00503     ObjectHeader = OBJECT_TO_OBJECT_HEADER( SourceObject );
    00504     ObjectType = ObjectHeader->Type;
    00505
    00506     ObjectTableEntry.Object = ObjectHeader;
    00507     ObjectTableEntry.ObAttributes |= (HandleAttributes & OBJ_HANDLE_ATTRIBUTES);
    00508
    00509     //
    00510     //  If any of the generic access bits are specified then map those to more
    00511     //  specific access bits
    00512     //
    00513
    00514     if ((DesiredAccess & GENERIC_ACCESS) != 0) {
    00515
    00516         RtlMapGenericMask( &DesiredAccess,
    00517                            &ObjectType->TypeInfo.GenericMapping );
    00518     }
    00519
    00520     //
    00521     //  Make sure to preserve ACCESS_SYSTEM_SECURITY, which most likely is not
    00522     //  found in the ValidAccessMask
    00523     //
    00524
    00525     TargetAccess = DesiredAccess &
    00526                    (ObjectType->TypeInfo.ValidAccessMask | ACCESS_SYSTEM_SECURITY);
    00527
    00528     //
    00529     //  If the access requested for the target is a superset of the
    00530     //  access allowed in the source, perform full AVR.  If it is a
    00531     //  subset or equal, do not perform any access validation.
    00532     //
    00533     //  Do not allow superset access if object type has a private security
    00534     //  method, as there is no means to call them in this case to do the
    00535     //  access check.
    00536     //
    00537     //  If the AccessState is not passed to ObpIncrementHandleCount
    00538     //  there will be no AVR.
    00539     //
    00540
    00541     if (TargetAccess & ~SourceAccess) {
    00542
    00543         if (ObjectType->TypeInfo.SecurityProcedure == SeDefaultObjectMethod) {
    00544
    00545             Status = SeCreateAccessState( &AccessState,
    00546                                           &AuxData,
    00547                                           TargetAccess,       // DesiredAccess
    00548                                           &ObjectType->TypeInfo.GenericMapping );
    00549
    00550             PassedAccessState = &AccessState;
    00551
    00552         } else {
    00553
    00554             Status = STATUS_ACCESS_DENIED;
    00555         }
    00556
    00557     } else {
    00558
    00559         //
    00560         //  Do not perform AVR
    00561         //
    00562
    00563         PassedAccessState = NULL;
    00564
    00565         Status = STATUS_SUCCESS;
    00566     }
    00567
    00568     //
    00569     //  Increment the new handle count and get a pointer to
    00570     //  the target processes object table
    00571     //
    00572
    00573     if ( NT_SUCCESS( Status )) {
    00574
    00575         Status = ObpIncrementHandleCount( ObDuplicateHandle,
    00576                                           PsGetCurrentProcess(), // this is already the target process
    00577                                           SourceObject,
    00578                                           ObjectType,
    00579                                           PassedAccessState,
    00580                                           PreviousMode,
    00581                                           HandleAttributes );
    00582
    00583         ObjectTable = ObpGetObjectTable();
    00584
    00585         ASSERT(ObjectTable);
    00586     }
    00587
    00588     if (Attached) {
    00589
    00590         KeDetachProcess();
    00591
    00592         Attached = FALSE;
    00593     }
    00594
    00595     if (Options & DUPLICATE_CLOSE_SOURCE) {
    00596
    00597         KeAttachProcess( &SourceProcess->Pcb );
    00598
    00599         NtClose( SourceHandle );
    00600
    00601         KeDetachProcess();
    00602     }
    00603
    00604     if (!NT_SUCCESS( Status )) {
    00605
    00606         if (PassedAccessState != NULL) {
    00607
    00608             SeDeleteAccessState( PassedAccessState );
    00609         }
    00610
    00611         KeReleaseMutant( &ObpInitKillMutant, 0, FALSE, FALSE );
    00612
    00613         KeLeaveCriticalRegion();
    00614
    00615         ObDereferenceObject( SourceObject );
    00616         ObDereferenceObject( SourceProcess );
    00617         ObDereferenceObject( TargetProcess );
    00618
    00619         return( Status );
    00620     }
    00621
    00622     if ((PassedAccessState != NULL) && (PassedAccessState->GenerateOnClose == TRUE)) {
    00623
    00624         //
    00625         //  If we performed AVR opening the handle, then mark the handle as needing
    00626         //  auditing when it's closed.
    00627         //
    00628
    00629         ObjectTableEntry.ObAttributes |= OBJ_AUDIT_OBJECT_CLOSE;
    00630     }
    00631
    00632 #if i386 && !FPO
    00633
    00634     if (NtGlobalFlag & FLG_KERNEL_STACK_TRACE_DB) {
    00635
    00636         ObjectTableEntry.GrantedAccessIndex = ObpComputeGrantedAccessIndex( TargetAccess );
    00637         ObjectTableEntry.CreatorBackTraceIndex = RtlLogStackBackTrace();
    00638
    00639     } else {
    00640
    00641         ObjectTableEntry.GrantedAccess = TargetAccess;
    00642     }
    00643
    00644 #else
    00645
    00646     ObjectTableEntry.GrantedAccess = TargetAccess;
    00647
    00648 #endif // i386 && !FPO
    00649
    00650     //
    00651     //  Now that we've constructed a new object table entry for the duplicated handle
    00652     //  we need to add it to the object table of the target process
    00653
    00654
    00655     NewHandle = ExCreateHandle( ObjectTable, &ObjectTableEntry );
    00656
    00657     if (NewHandle) {
    00658
    00659         //
    00660         //  We have a new handle to audit the creation of the new handle if
    00661         //  AVR was done.  And set the optional output handle variable.  Note
    00662         //  that if we reach here the status variable is already a success
    00663         //
    00664
    00665         if (PassedAccessState != NULL) {
    00666
    00667             SeAuditHandleCreation( PassedAccessState, NewHandle );
    00668         }
    00669
    00670         if (SeDetailedAuditing && (ObjectTableEntry.ObAttributes & OBJ_AUDIT_OBJECT_CLOSE)) {
    00671
    00672             SeAuditHandleDuplication( SourceHandle,
    00673                                       NewHandle,
    00674                                       SourceProcess,
    00675                                       TargetProcess );
    00676         }
    00677
    00678         if (ARGUMENT_PRESENT( TargetHandle )) {
    00679
    00680             try {
    00681
    00682                 *TargetHandle = NewHandle;
    00683
    00684             } except( EXCEPTION_EXECUTE_HANDLER ) {
    00685
    00686                 //
    00687                 //  Fall through, since we cannot undo what we have done.
    00688                 //
    00689             }
    00690         }
    00691
    00692     } else {
    00693
    00694         //
    00695         //  We didn't get a new handle to decrement the handle count dereference
    00696         //  the necessary objects, set the optional output variable and indicate
    00697         //  why we're failing
    00698         //
    00699
    00700         ObpDecrementHandleCount( TargetProcess,
    00701                                  ObjectHeader,
    00702                                  ObjectType,
    00703                                  TargetAccess );
    00704
    00705         ObDereferenceObject( SourceObject );
    00706
    00707         if (ARGUMENT_PRESENT( TargetHandle )) {
    00708
    00709             try {
    00710
    00711                 *TargetHandle = (HANDLE)NULL;
    00712
    00713             } except( EXCEPTION_EXECUTE_HANDLER ) {
    00714
    00715                 //
    00716                 //  Fall through so we can return the correct status.
    00717                 //
    00718             }
    00719         }
    00720
    00721         Status = STATUS_INSUFFICIENT_RESOURCES;
    00722     }
    00723
    00724     //
    00725     //  Cleanup from our selfs and then return to our caller
    00726     //
    00727
    00728     if (PassedAccessState != NULL) {
    00729
    00730         SeDeleteAccessState( PassedAccessState );
    00731     }
    00732
    00733     KeReleaseMutant( &ObpInitKillMutant, 0, FALSE, FALSE );
    00734
    00735     KeLeaveCriticalRegion();
    00736
    00737     ObDereferenceObject( SourceProcess );
    00738     ObDereferenceObject( TargetProcess );
    00739
    00740     return( Status );
    00741 }
    00742
    00743
    00744 NTSTATUS
    00745 ObGetHandleInformation (
    00746     OUT PSYSTEM_HANDLE_INFORMATION HandleInformation,
    00747     IN ULONG Length,
    00748     OUT PULONG ReturnLength OPTIONAL
    00749     )
    00750
    00751 /*++
    00752
    00753 Routine Description:
    00754
    00755     This routine returns information about the specified handle.
    00756
    00757 Arguments:
    00758
    00759     HandleInformation - Supplies an array of handle information
    00760         structures to fill in
    00761
    00762     Length - Supplies the length the handle information array in bytes
    00763
    00764     ReturnLength - Receives the number of bytes used by this call
    00765
    00766 Return Value:
    00767
    00768     An appropriate status value
    00769
    00770 --*/
    00771
    00772 {
    00773     NTSTATUS Status;
    00774     ULONG RequiredLength;
    00775
    00776     PAGED_CODE();
    00777
    00778     RequiredLength = FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION, Handles );
    00779
    00780     if (Length < RequiredLength) {
    00781
    00782         return( STATUS_INFO_LENGTH_MISMATCH );
    00783     }
    00784
    00785     HandleInformation->NumberOfHandles = 0;
    00786
    00787     //
    00788     //  For every handle in every handle table we'll be calling
    00789     //  our callback routine
    00790     //
    00791
    00792     Status = ExSnapShotHandleTables( ObpCaptureHandleInformation,
    00793                                      HandleInformation,
    00794                                      Length,
    00795                                      &RequiredLength );
    00796
    00797     if (ARGUMENT_PRESENT( ReturnLength )) {
    00798
    00799         *ReturnLength = RequiredLength;
    00800     }
    00801
    00802     return( Status );
    00803 }
    00804
    00805
    00806 NTSTATUS
    00807 ObpCaptureHandleInformation (
    00808     IN OUT PSYSTEM_HANDLE_TABLE_ENTRY_INFO *HandleEntryInfo,
    00809     IN HANDLE UniqueProcessId,
    00810     IN PHANDLE_TABLE_ENTRY ObjectTableEntry,
    00811     IN HANDLE HandleIndex,
    00812     IN ULONG Length,
    00813     IN OUT PULONG RequiredLength
    00814     )
    00815
    00816 /*++
    00817
    00818 Routine Description:
    00819
    00820     This is the callback routine of ObGetHandleInformation
    00821
    00822 Arguments:
    00823
    00824     HandleEntryInfo - Supplies a pointer to the output buffer to receive
    00825         the handle information
    00826
    00827     UniqueProcessId - Supplies the process id of the caller
    00828
    00829     ObjectTableEntry - Supplies the handle table entry that is being
    00830         captured
    00831
    00832     HandleIndex - Supplies the index for the preceding handle table entry
    00833
    00834     Length - Specifies the length, in bytes, of the original user buffer
    00835
    00836     RequiredLength - Specifies the length, in bytes, that has already been
    00837         used in the buffer to store information.  On return this receives
    00838         the updated number of bytes being used.
    00839
    00840         Note that the HandleEntryInfo does not necessarily point to the
    00841         start of the original user buffer.  It will have been offset by
    00842         the feed-in RequiredLength value.
    00843
    00844 Return Value:
    00845
    00846     An appropriate status value
    00847
    00848 --*/
    00849
    00850 {
    00851     NTSTATUS Status;
    00852     POBJECT_HEADER ObjectHeader;
    00853
    00854     //
    00855     //  Figure out who much size we really need to contain this extra record
    00856     //  and then check that it fits.
    00857     //
    00858
    00859     *RequiredLength += sizeof( SYSTEM_HANDLE_TABLE_ENTRY_INFO );
    00860
    00861     if (Length < *RequiredLength) {
    00862
    00863         Status = STATUS_INFO_LENGTH_MISMATCH;
    00864
    00865     } else {
    00866
    00867         //
    00868         //  Get the object header from the table entry and then copy over the information
    00869         //
    00870
    00871         ObjectHeader = (POBJECT_HEADER)(((ULONG_PTR)(ObjectTableEntry->Object)) & ~OBJ_HANDLE_ATTRIBUTES);
    00872
    00873         (*HandleEntryInfo)->UniqueProcessId       = (USHORT)((ULONG_PTR)UniqueProcessId);
    00874         (*HandleEntryInfo)->HandleAttributes      = (UCHAR)(ObjectTableEntry->ObAttributes & OBJ_HANDLE_ATTRIBUTES);
    00875         (*HandleEntryInfo)->ObjectTypeIndex       = (UCHAR)(ObjectHeader->Type->Index);
    00876         (*HandleEntryInfo)->HandleValue           = (USHORT)((ULONG_PTR)(HandleIndex));
    00877         (*HandleEntryInfo)->Object                = &ObjectHeader->Body;
    00878         (*HandleEntryInfo)->CreatorBackTraceIndex = 0;
    00879
    00880 #if i386 && !FPO
    00881
    00882         if (NtGlobalFlag & FLG_KERNEL_STACK_TRACE_DB) {
    00883
    00884             (*HandleEntryInfo)->CreatorBackTraceIndex = ObjectTableEntry->CreatorBackTraceIndex;
    00885             (*HandleEntryInfo)->GrantedAccess = ObpTranslateGrantedAccessIndex( ObjectTableEntry->GrantedAccessIndex );
    00886
    00887         } else {
    00888
    00889             (*HandleEntryInfo)->GrantedAccess = ObjectTableEntry->GrantedAccess;
    00890         }
    00891
    00892 #else
    00893
    00894         (*HandleEntryInfo)->GrantedAccess = ObjectTableEntry->GrantedAccess;
    00895
    00896 #endif // i386 && !FPO
    00897
    00898         (*HandleEntryInfo)++;
    00899
    00900         Status = STATUS_SUCCESS;
    00901     }
    00902
    00903     return( Status );
    00904 }
    00905
    00906
    00907 POBJECT_HANDLE_COUNT_ENTRY
    00908 ObpInsertHandleCount (
    00909     POBJECT_HEADER ObjectHeader
    00910     )
    00911
    00912 /*++
    00913
    00914 Routine Description:
    00915
    00916     This function will increase the size of the handle database
    00917     stored in the handle information of an object header.  If
    00918     necessary it will allocate new and free old handle databases.
    00919
    00920     This routine should not be called if there is already free
    00921     space in the handle table.
    00922
    00923 Arguments:
    00924
    00925     ObjectHeader - The object whose handle count is being incremented
    00926
    00927 Return Value:
    00928
    00929     The pointer to the next free handle count entry within the
    00930     handle database.
    00931
    00932 --*/
    00933
    00934 {
    00935     POBJECT_HEADER_HANDLE_INFO HandleInfo;
    00936     POBJECT_HANDLE_COUNT_DATABASE OldHandleCountDataBase;
    00937     POBJECT_HANDLE_COUNT_DATABASE NewHandleCountDataBase;
    00938     POBJECT_HANDLE_COUNT_ENTRY FreeHandleCountEntry;
    00939     ULONG CountEntries;
    00940     ULONG OldSize;
    00941     ULONG NewSize;
    00942     OBJECT_HANDLE_COUNT_DATABASE SingleEntryDataBase;
    00943
    00944     PAGED_CODE();
    00945
    00946     //
    00947     //  Check if the object has any handle information
    00948     //
    00949
    00950     HandleInfo = OBJECT_HEADER_TO_HANDLE_INFO(ObjectHeader);
    00951
    00952     if (HandleInfo == NULL) {
    00953
    00954         return NULL;
    00955     }
    00956
    00957     //
    00958     //  The object does have some handle information.  If it has
    00959     //  a single handle entry then we'll construct a local dummy
    00960     //  handle count database and come up with a new data base for
    00961     //  storing two entries.
    00962     //
    00963
    00964     if (ObjectHeader->Flags & OB_FLAG_SINGLE_HANDLE_ENTRY) {
    00965
    00966         SingleEntryDataBase.CountEntries = 1;
    00967         SingleEntryDataBase.HandleCountEntries[0] = HandleInfo->SingleEntry;
    00968
    00969         OldHandleCountDataBase = &SingleEntryDataBase;
    00970
    00971         OldSize = sizeof( SingleEntryDataBase );
    00972
    00973         CountEntries = 2;
    00974
    00975         NewSize = sizeof(OBJECT_HANDLE_COUNT_DATABASE) +
    00976                ((CountEntries - 1) * sizeof( OBJECT_HANDLE_COUNT_ENTRY ));
    00977
    00978     } else {
    00979
    00980         //
    00981         //  The object already has multiple handles so we reference the
    00982         //  current handle database, and compute a new size bumped by four
    00983         //
    00984
    00985         OldHandleCountDataBase = HandleInfo->HandleCountDataBase;
    00986
    00987         CountEntries = OldHandleCountDataBase->CountEntries;
    00988
    00989         OldSize = sizeof(OBJECT_HANDLE_COUNT_DATABASE) +
    00990                ((CountEntries - 1) * sizeof( OBJECT_HANDLE_COUNT_ENTRY));
    00991
    00992         CountEntries += 4;
    00993
    00994         NewSize = sizeof(OBJECT_HANDLE_COUNT_DATABASE) +
    00995                ((CountEntries - 1) * sizeof( OBJECT_HANDLE_COUNT_ENTRY));
    00996     }
    00997
    00998     //
    00999     //  Now allocate pool for the new handle database.
    01000     //
    01001
    01002     NewHandleCountDataBase = ExAllocatePoolWithTag(PagedPool, NewSize,'dHbO');
    01003
    01004     if (NewHandleCountDataBase == NULL) {
    01005
    01006         return NULL;
    01007     }
    01008
    01009     //
    01010     //  Copy over the old database.  Note that this might just copy our
    01011     //  local dummy entry for the single entry case
    01012     //
    01013
    01014     RtlMoveMemory(NewHandleCountDataBase, OldHandleCountDataBase, OldSize);
    01015
    01016     //
    01017     //  If the previous mode was a single entry then remove that
    01018     //  indication otherwise free up with previous handle database
    01019     //
    01020
    01021     if (ObjectHeader->Flags & OB_FLAG_SINGLE_HANDLE_ENTRY) {
    01022
    01023         ObjectHeader->Flags &= ~OB_FLAG_SINGLE_HANDLE_ENTRY;
    01024
    01025     } else {
    01026
    01027         ExFreePool( OldHandleCountDataBase );
    01028     }
    01029
    01030     //
    01031     //  Find the end of the new database that is used and zero out
    01032     //  the memory
    01033     //
    01034
    01035     FreeHandleCountEntry =
    01036         (POBJECT_HANDLE_COUNT_ENTRY)((PCHAR)NewHandleCountDataBase + OldSize);
    01037
    01038     RtlZeroMemory(FreeHandleCountEntry, NewSize - OldSize);
    01039
    01040     //
    01041     //  Set the new database to the proper entry count and put it
    01042     //  all in the object
    01043     //
    01044
    01045     NewHandleCountDataBase->CountEntries = CountEntries;
    01046
    01047     HandleInfo->HandleCountDataBase = NewHandleCountDataBase;
    01048
    01049     //
    01050     //  And return to our caller
    01051     //
    01052
    01053     return FreeHandleCountEntry;
    01054 }
    01055
    01056
    01057 NTSTATUS
    01058 ObpIncrementHandleDataBase (
    01059     IN POBJECT_HEADER ObjectHeader,
    01060     IN PEPROCESS Process,
    01061     OUT PULONG NewProcessHandleCount
    01062     )
    01063
    01064 /*++
    01065
    01066 Routine Description:
    01067
    01068     This function increments the handle count database associated with the
    01069     specified object for a specified process.
    01070
    01071 Arguments:
    01072
    01073     ObjectHeader - Supplies a pointer to the object.
    01074
    01075     Process - Supplies a pointer to the process whose handle count is to be
    01076         updated.
    01077
    01078     NewProcessHandleCount - Supplies a pointer to a variable that receives
    01079         the new handle count for the process.
    01080
    01081 Return Value:
    01082
    01083     An appropriate status value
    01084
    01085 --*/
    01086
    01087 {
    01088     POBJECT_HEADER_HANDLE_INFO HandleInfo;
    01089     POBJECT_HANDLE_COUNT_DATABASE HandleCountDataBase;
    01090     POBJECT_HANDLE_COUNT_ENTRY HandleCountEntry;
    01091     POBJECT_HANDLE_COUNT_ENTRY FreeHandleCountEntry;
    01092     ULONG CountEntries;
    01093     ULONG ProcessHandleCount;
    01094
    01095     PAGED_CODE();
    01096
    01097     //
    01098     //  Translate the object header to the handle information.
    01099     //
    01100
    01101     HandleInfo = OBJECT_HEADER_TO_HANDLE_INFO(ObjectHeader);
    01102
    01103     //
    01104     //  Check if the object has space for only a single handle
    01105     //
    01106
    01107     if (ObjectHeader->Flags & OB_FLAG_SINGLE_HANDLE_ENTRY) {
    01108
    01109         //
    01110         //  If the single handle isn't in use then set the entry
    01111         //  and tell the caller there is only one handle
    01112         //
    01113
    01114         if (HandleInfo->SingleEntry.HandleCount == 0) {
    01115
    01116             *NewProcessHandleCount = 1;
    01117             HandleInfo->SingleEntry.HandleCount = 1;
    01118             HandleInfo->SingleEntry.Process = Process;
    01119
    01120             return STATUS_SUCCESS;
    01121
    01122         //
    01123         //  If the single entry is for the same process as specified
    01124         //  then increment the count and we're done
    01125         //
    01126
    01127         } else if (HandleInfo->SingleEntry.Process == Process) {
    01128
    01129             *NewProcessHandleCount = ++HandleInfo->SingleEntry.HandleCount;
    01130
    01131             return STATUS_SUCCESS;
    01132
    01133         //
    01134         //  Finally we have a object with a single handle entry already
    01135         //  in use, so we need to grow the handle database before
    01136         //  we can set this new value
    01137         //
    01138
    01139         } else {
    01140
    01141             FreeHandleCountEntry = ObpInsertHandleCount( ObjectHeader );
    01142
    01143             if (FreeHandleCountEntry == NULL) {
    01144
    01145                 return STATUS_INSUFFICIENT_RESOURCES;
    01146             }
    01147
    01148             FreeHandleCountEntry->Process = Process;
    01149             FreeHandleCountEntry->HandleCount = 1;
    01150             *NewProcessHandleCount = 1;
    01151
    01152             return STATUS_SUCCESS;
    01153         }
    01154     }
    01155
    01156     //
    01157     //  The object does not contain a single entry, therefore we're
    01158     //  assuming it already has a handle count database
    01159     //
    01160
    01161     //
    01162     //  **** HandleInfo should first be checked for null
    01163     //
    01164
    01165     HandleCountDataBase = HandleInfo->HandleCountDataBase;
    01166
    01167     FreeHandleCountEntry = NULL;
    01168
    01169     //
    01170     //  **** can we with success if the database is null
    01171     //
    01172
    01173     if (HandleCountDataBase != NULL) {
    01174
    01175         //
    01176         //  Get the number of entries and a pointer to the first one
    01177         //  in the handle database
    01178         //
    01179
    01180         CountEntries = HandleCountDataBase->CountEntries;
    01181         HandleCountEntry = &HandleCountDataBase->HandleCountEntries[ 0 ];
    01182
    01183         //
    01184         //  For each entry in the handle database check for a process
    01185         //  match and if so then increment the handle count and return
    01186         //  to our caller.  Otherwise if the entry is free then remember
    01187         //  it so we can store to it later
    01188         //
    01189
    01190         while (CountEntries) {
    01191
    01192             if (HandleCountEntry->Process == Process) {
    01193
    01194                 *NewProcessHandleCount = ++HandleCountEntry->HandleCount;
    01195
    01196                 return STATUS_SUCCESS;
    01197
    01198             } else if (HandleCountEntry->HandleCount == 0) {
    01199
    01200                 FreeHandleCountEntry = HandleCountEntry;
    01201             }
    01202
    01203             ++HandleCountEntry;
    01204             --CountEntries;
    01205         }
    01206
    01207         //
    01208         //  If we did not find a free handle entry then we have to grow the
    01209         //  handle database before we can set this new value
    01210         //
    01211
    01212         if (FreeHandleCountEntry == NULL) {
    01213
    01214             FreeHandleCountEntry = ObpInsertHandleCount( ObjectHeader );
    01215
    01216             if (FreeHandleCountEntry == NULL) {
    01217
    01218                 return(STATUS_INSUFFICIENT_RESOURCES);
    01219             }
    01220         }
    01221
    01222         FreeHandleCountEntry->Process = Process;
    01223         FreeHandleCountEntry->HandleCount = 1;
    01224         *NewProcessHandleCount = 1;
    01225     }
    01226
    01227     return STATUS_SUCCESS;
    01228 }
    01229
    01230
    01231 NTSTATUS
    01232 ObpIncrementHandleCount (
    01233     OB_OPEN_REASON OpenReason,
    01234     PEPROCESS Process,
    01235     PVOID Object,
    01236     POBJECT_TYPE ObjectType,
    01237     PACCESS_STATE AccessState OPTIONAL,
    01238     KPROCESSOR_MODE AccessMode,
    01239     ULONG Attributes
    01240     )
    01241
    01242 /*++
    01243
    01244 Routine Description:
    01245
    01246     Increments the count of number of handles to the given object.
    01247
    01248     If the object is being opened or created, access validation and
    01249     auditing will be performed as appropriate.
    01250
    01251 Arguments:
    01252
    01253     OpenReason - Supplies the reason the handle count is being incremented.
    01254
    01255     Process - Pointer to the process in which the new handle will reside.
    01256
    01257     Object - Supplies a pointer to the body of the object.
    01258
    01259     ObjectType - Supplies the type of the object.
    01260
    01261     AccessState - Optional parameter supplying the current accumulated
    01262         security information describing the attempt to access the object.
    01263
    01264     AccessMode - Supplies the mode of the requestor.
    01265
    01266     Attributes - Desired attributes for the handle
    01267
    01268 Return Value:
    01269
    01270     An appropriate status value
    01271
    01272 --*/
    01273
    01274 {
    01275     NTSTATUS Status;
    01276     ULONG ProcessHandleCount;
    01277     BOOLEAN ExclusiveHandle;
    01278     POBJECT_HEADER_CREATOR_INFO CreatorInfo;
    01279     POBJECT_HEADER_QUOTA_INFO QuotaInfo;
    01280     POBJECT_HEADER ObjectHeader;
    01281     BOOLEAN HasPrivilege = FALSE;
    01282     PRIVILEGE_SET Privileges;
    01283     BOOLEAN NewObject;
    01284     BOOLEAN HoldObjectTypeMutex = FALSE;
    01285
    01286     PAGED_CODE();
    01287
    01288     ObpValidateIrql( "ObpIncrementHandleCount" );
    01289
    01290     //
    01291     //  Get a pointer to the object header
    01292     //
    01293
    01294     ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
    01295
    01296     //
    01297     //  Charge the user quota for the object
    01298     //
    01299
    01300     Status = ObpChargeQuotaForObject( ObjectHeader, ObjectType, &NewObject );
    01301
    01302     if (!NT_SUCCESS( Status )) {
    01303
    01304         return Status;
    01305     }
    01306
    01307     ObpEnterObjectTypeMutex( ObjectType );
    01308     HoldObjectTypeMutex = TRUE;
    01309
    01310     try {
    01311
    01312         ExclusiveHandle = FALSE;
    01313
    01314         //
    01315         //  Check if the caller wants exlusive access and if so then
    01316         //  make sure the attributes and header flags match up correctly
    01317         //
    01318
    01319         if (Attributes & OBJ_EXCLUSIVE) {
    01320
    01321             if ((Attributes & OBJ_INHERIT) ||
    01322                 ((ObjectHeader->Flags & OB_FLAG_EXCLUSIVE_OBJECT) == 0)) {
    01323
    01324                 Status = STATUS_INVALID_PARAMETER;
    01325                 leave;
    01326             }
    01327
    01328             if (((OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader) == NULL) &&
    01329                  (ObjectHeader->HandleCount != 0))
    01330
    01331                     ||
    01332
    01333                 ((OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader) != NULL) &&
    01334                  (OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader) != PsGetCurrentProcess()))) {
    01335
    01336                 Status = STATUS_ACCESS_DENIED;
    01337                 leave;
    01338             }
    01339
    01340             ExclusiveHandle = TRUE;
    01341
    01342         //
    01343         //  The user doesn't want exclusive access so now check to make sure
    01344         //  the attriutes and header flags match up correctly
    01345         //
    01346
    01347         } else if ((ObjectHeader->Flags & OB_FLAG_EXCLUSIVE_OBJECT) &&
    01348                    (OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader) != NULL)) {
    01349
    01350             Status = STATUS_ACCESS_DENIED;
    01351             leave;
    01352         }
    01353
    01354         //
    01355         //  If handle count going from zero to one for an existing object that
    01356         //  maintains a handle count database, but does not have an open procedure
    01357         //  just a close procedure, then fail the call as they are trying to
    01358         //  reopen an object by pointer and the close procedure will not know
    01359         //  that the object has been 'recreated'
    01360         //
    01361
    01362         if ((ObjectHeader->HandleCount == 0) &&
    01363             (!NewObject) &&
    01364             (ObjectType->TypeInfo.MaintainHandleCount) &&
    01365             (ObjectType->TypeInfo.OpenProcedure == NULL) &&
    01366             (ObjectType->TypeInfo.CloseProcedure != NULL)) {
    01367
    01368             Status = STATUS_UNSUCCESSFUL;
    01369             leave;
    01370         }
    01371
    01372         if ((OpenReason == ObOpenHandle) ||
    01373             ((OpenReason == ObDuplicateHandle) && ARGUMENT_PRESENT(AccessState))) {
    01374
    01375             //
    01376             //  Perform Access Validation to see if we can open this
    01377             //  (already existing) object.
    01378             //
    01379
    01380             if (!ObCheckObjectAccess( Object,
    01381                                       AccessState,
    01382                                       TRUE,
    01383                                       AccessMode,
    01384                                       &Status )) {
    01385
    01386                 leave;
    01387             }
    01388
    01389         } else if ((OpenReason == ObCreateHandle)) {
    01390
    01391             //
    01392             //  We are creating a new instance of this object type.
    01393             //  A total of three audit messages may be generated:
    01394             //
    01395             //  1 - Audit the attempt to create an instance of this
    01396             //      object type.
    01397             //
    01398             //  2 - Audit the successful creation.
    01399             //
    01400             //  3 - Audit the allocation of the handle.
    01401             //
    01402
    01403             //
    01404             //  At this point, the RemainingDesiredAccess field in
    01405             //  the AccessState may still contain either Generic access
    01406             //  types, or MAXIMUM_ALLOWED.  We will map the generics
    01407             //  and substitute GenericAll for MAXIMUM_ALLOWED.
    01408             //
    01409
    01410             if ( AccessState->RemainingDesiredAccess & MAXIMUM_ALLOWED ) {
    01411
    01412                 AccessState->RemainingDesiredAccess &= ~MAXIMUM_ALLOWED;
    01413                 AccessState->RemainingDesiredAccess |= GENERIC_ALL;
    01414             }
    01415
    01416             if ((GENERIC_ACCESS & AccessState->RemainingDesiredAccess) != 0) {
    01417
    01418                 RtlMapGenericMask( &AccessState->RemainingDesiredAccess,
    01419                                    &ObjectType->TypeInfo.GenericMapping );
    01420             }
    01421
    01422             //
    01423             //  Since we are creating the object, we can give any access the caller
    01424             //  wants.  The only exception is ACCESS_SYSTEM_SECURITY, which requires
    01425             //  a privilege.
    01426             //
    01427
    01428             if ( AccessState->RemainingDesiredAccess & ACCESS_SYSTEM_SECURITY ) {
    01429
    01430                 //
    01431                 //  We could use SeSinglePrivilegeCheck here, but it
    01432                 //  captures the subject context again, and we don't
    01433                 //  want to do that in this path for performance reasons.
    01434                 //
    01435
    01436                 Privileges.PrivilegeCount = 1;
    01437                 Privileges.Control = PRIVILEGE_SET_ALL_NECESSARY;
    01438                 Privileges.Privilege[0].Luid = SeSecurityPrivilege;
    01439                 Privileges.Privilege[0].Attributes = 0;
    01440
    01441                 HasPrivilege = SePrivilegeCheck( &Privileges,
    01442                                                  &AccessState->SubjectSecurityContext,
    01443                                                  KeGetPreviousMode() );
    01444
    01445                 if (!HasPrivilege) {
    01446
    01447                     SePrivilegedServiceAuditAlarm ( NULL,
    01448                                                     &AccessState->SubjectSecurityContext,
    01449                                                     &Privileges,
    01450                                                     FALSE );
    01451
    01452                     Status = STATUS_PRIVILEGE_NOT_HELD;
    01453                     leave;
    01454                 }
    01455
    01456                 AccessState->RemainingDesiredAccess &= ~ACCESS_SYSTEM_SECURITY;
    01457                 AccessState->PreviouslyGrantedAccess |= ACCESS_SYSTEM_SECURITY;
    01458
    01459                 (VOID) SeAppendPrivileges( AccessState,
    01460                                            &Privileges );
    01461             }
    01462
    01463             //
    01464             //  Get the objects creator info block and insert it on the
    01465             //  global list of objects for that type
    01466             //
    01467
    01468             CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO( ObjectHeader );
    01469
    01470             if (CreatorInfo != NULL) {
    01471
    01472                 InsertTailList( &ObjectType->TypeList, &CreatorInfo->TypeList );
    01473             }
    01474         }
    01475
    01476         if (ExclusiveHandle) {
    01477
    01478             OBJECT_HEADER_TO_QUOTA_INFO(ObjectHeader)->ExclusiveProcess = Process;
    01479         }
    01480
    01481         ObpIncrHandleCount( ObjectHeader );
    01482         ProcessHandleCount = 0;
    01483
    01484         //
    01485         //  If the object type wants us to keep try of the handle counts
    01486         //  then call our routine to do the work
    01487         //
    01488
    01489         if (ObjectType->TypeInfo.MaintainHandleCount) {
    01490
    01491             Status = ObpIncrementHandleDataBase( ObjectHeader,
    01492                                                  Process,
    01493                                                  &ProcessHandleCount );
    01494
    01495             if (!NT_SUCCESS(Status)) {
    01496                 // BUG BUG, We probably need more backout than this, NeillC
    01497                 ObpDecrHandleCount( ObjectHeader );
    01498
    01499                 leave;
    01500             }
    01501         }
    01502
    01503         //
    01504         //  Set our preliminary status now to success because
    01505         //  the call to the open procedure might change this
    01506         //
    01507
    01508         Status = STATUS_SUCCESS;
    01509
    01510         //
    01511         //  If the object type has an open procedure
    01512         //  then invoke that procedure
    01513         //
    01514
    01515         if (ObjectType->TypeInfo.OpenProcedure != NULL) {
    01516
    01517             KIRQL SaveIrql;
    01518
    01519             //
    01520             //  Leave the object type mutex when call the OpenProcedure. If an exception
    01521             //  while OpenProcedure the HoldObjectTypeMutex disable leaving the mutex
    01522             //  on finally block
    01523             //
    01524
    01525             ObpLeaveObjectTypeMutex( ObjectType );
    01526             HoldObjectTypeMutex = FALSE;
    01527
    01528             ObpBeginTypeSpecificCallOut( SaveIrql );
    01529
    01530             try {
    01531
    01532                 (*ObjectType->TypeInfo.OpenProcedure)( OpenReason,
    01533                                                        Process,
    01534                                                        Object,
    01535                                                        AccessState ?
    01536                                                            AccessState->PreviouslyGrantedAccess :
    01537                                                            0,
    01538                                                        ProcessHandleCount );
    01539
    01540             } except( EXCEPTION_EXECUTE_HANDLER ) {
    01541
    01542                 Status = GetExceptionCode();
    01543             }
    01544
    01545             ObpEndTypeSpecificCallOut( SaveIrql, "Open", ObjectType, Object );
    01546
    01547             //
    01548             //  Hold back the object type mutex and set the HoldObjectTypeMutex variable
    01549             //  to allow releasing the mutex while leaving this procedure
    01550             //
    01551
    01552             ObpEnterObjectTypeMutex( ObjectType );
    01553             HoldObjectTypeMutex = TRUE;
    01554
    01555             if (!NT_SUCCESS(Status)) {
    01556
    01557                 (VOID)ObpDecrHandleCount( ObjectHeader );
    01558                 leave;
    01559             }
    01560         }
    01561
    01562         //
    01563         //  Do some simple bookkeeping for the handle counts
    01564         //  and then return to our caller
    01565         //
    01566
    01567         ObjectType->TotalNumberOfHandles += 1;
    01568
    01569         if (ObjectType->TotalNumberOfHandles > ObjectType->HighWaterNumberOfHandles) {
    01570
    01571             ObjectType->HighWaterNumberOfHandles = ObjectType->TotalNumberOfHandles;
    01572         }
    01573
    01574     } finally {
    01575
    01576         if ( HoldObjectTypeMutex ) {
    01577
    01578             ObpLeaveObjectTypeMutex( ObjectType );
    01579         }
    01580     }
    01581
    01582     return( Status );
    01583 }
    01584
    01585
    01586 NTSTATUS
    01587 ObpIncrementUnnamedHandleCount (
    01588     PACCESS_MASK DesiredAccess,
    01589     PEPROCESS Process,
    01590     PVOID Object,
    01591     POBJECT_TYPE ObjectType,
    01592     KPROCESSOR_MODE AccessMode,
    01593     ULONG Attributes
    01594     )
    01595
    01596 /*++
    01597
    01598 Routine Description:
    01599
    01600     Increments the count of number of handles to the given object.
    01601
    01602 Arguments:
    01603
    01604     Desired Access - Supplies the desired access to the object and receives
    01605         the assign access mask
    01606
    01607     Process - Pointer to the process in which the new handle will reside.
    01608
    01609     Object - Supplies a pointer to the body of the object.
    01610
    01611     ObjectType - Supplies the type of the object.
    01612
    01613     AccessMode - Supplies the mode of the requestor.
    01614
    01615     Attributes - Desired attributes for the handle
    01616
    01617 Return Value:
    01618
    01619     An appropriate status value
    01620
    01621 --*/
    01622
    01623 {
    01624     NTSTATUS Status;
    01625     BOOLEAN ExclusiveHandle;
    01626     POBJECT_HEADER_CREATOR_INFO CreatorInfo;
    01627     POBJECT_HEADER_QUOTA_INFO QuotaInfo;
    01628     POBJECT_HEADER ObjectHeader;
    01629     BOOLEAN NewObject;
    01630     ULONG ProcessHandleCount;
    01631     BOOLEAN HoldObjectTypeMutex = FALSE;
    01632
    01633     PAGED_CODE();
    01634
    01635     ObpValidateIrql( "ObpIncrementUnnamedHandleCount" );
    01636
    01637     //
    01638     //  Get a pointer to the object header
    01639     //
    01640
    01641     ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
    01642
    01643     //
    01644     //  Charge the user quota for the object
    01645     //
    01646
    01647     Status = ObpChargeQuotaForObject( ObjectHeader, ObjectType, &NewObject );
    01648
    01649     if (!NT_SUCCESS( Status )) {
    01650
    01651         return Status;
    01652     }
    01653
    01654     ObpEnterObjectTypeMutex( ObjectType );
    01655     HoldObjectTypeMutex = TRUE;
    01656
    01657     try {
    01658
    01659         ExclusiveHandle = FALSE;
    01660
    01661         //
    01662         //  Check if the caller wants exlusive access and if so then
    01663         //  make sure the attributes and header flags match up correctly
    01664         //
    01665
    01666         if (Attributes & OBJ_EXCLUSIVE) {
    01667
    01668             if ((Attributes & OBJ_INHERIT) ||
    01669                 ((ObjectHeader->Flags & OB_FLAG_EXCLUSIVE_OBJECT) == 0)) {
    01670
    01671                 Status = STATUS_INVALID_PARAMETER;
    01672                 leave;
    01673             }
    01674
    01675             if (((OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader) == NULL) &&
    01676                  (ObjectHeader->HandleCount != 0))
    01677
    01678                         ||
    01679
    01680                 ((OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader) != NULL) &&
    01681                  (OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader) != PsGetCurrentProcess()))) {
    01682
    01683                 Status = STATUS_ACCESS_DENIED;
    01684                 leave;
    01685             }
    01686
    01687             ExclusiveHandle = TRUE;
    01688
    01689         //
    01690         //  The user doesn't want exclusive access so now check to make sure
    01691         //  the attriutes and header flags match up correctly
    01692         //
    01693
    01694         } else if ((ObjectHeader->Flags & OB_FLAG_EXCLUSIVE_OBJECT) &&
    01695                    (OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader) != NULL)) {
    01696
    01697             Status = STATUS_ACCESS_DENIED;
    01698             leave;
    01699         }
    01700
    01701         //
    01702         //  If handle count going from zero to one for an existing object that
    01703         //  maintains a handle count database, but does not have an open procedure
    01704         //  just a close procedure, then fail the call as they are trying to
    01705         //  reopen an object by pointer and the close procedure will not know
    01706         //  that the object has been 'recreated'
    01707         //
    01708
    01709         if ((ObjectHeader->HandleCount == 0) &&
    01710             (!NewObject) &&
    01711             (ObjectType->TypeInfo.MaintainHandleCount) &&
    01712             (ObjectType->TypeInfo.OpenProcedure == NULL) &&
    01713             (ObjectType->TypeInfo.CloseProcedure != NULL)) {
    01714
    01715             Status = STATUS_UNSUCCESSFUL;
    01716
    01717             leave;
    01718         }
    01719
    01720         //
    01721         //  If the user asked for the maximum allowed then remove the bit and
    01722         //  or in generic all access
    01723         //
    01724
    01725         if ( *DesiredAccess & MAXIMUM_ALLOWED ) {
    01726
    01727             *DesiredAccess &= ~MAXIMUM_ALLOWED;
    01728             *DesiredAccess |= GENERIC_ALL;
    01729         }
    01730
    01731         //  If the user asked for any generic bit then translate it to
    01732         //  someone more appropriate for the object type
    01733         //
    01734
    01735         if ((GENERIC_ACCESS & *DesiredAccess) != 0) {
    01736
    01737             RtlMapGenericMask( DesiredAccess,
    01738                                &ObjectType->TypeInfo.GenericMapping );
    01739         }
    01740
    01741         //
    01742         //  Get a pointer to the creator info block for the object and insert
    01743         //  it on the global list of object for that type
    01744         //
    01745
    01746         CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO( ObjectHeader );
    01747
    01748         if (CreatorInfo != NULL) {
    01749
    01750             InsertTailList( &ObjectType->TypeList, &CreatorInfo->TypeList );
    01751         }
    01752
    01753         if (ExclusiveHandle) {
    01754
    01755             OBJECT_HEADER_TO_QUOTA_INFO(ObjectHeader)->ExclusiveProcess = Process;
    01756         }
    01757
    01758         ObpIncrHandleCount( ObjectHeader );
    01759         ProcessHandleCount = 0;
    01760
    01761         //
    01762         //  If the object type wants us to keep try of the handle counts
    01763         //  then call our routine to do the work
    01764         //
    01765
    01766         if (ObjectType->TypeInfo.MaintainHandleCount) {
    01767
    01768             Status = ObpIncrementHandleDataBase( ObjectHeader,
    01769                                                  Process,
    01770                                                  &ProcessHandleCount );
    01771
    01772             if (!NT_SUCCESS(Status)) {
    01773                 // BUG BUG, We probably need more backout than this, NeillC
    01774                 ObpDecrHandleCount( ObjectHeader );
    01775                 leave;
    01776             }
    01777         }
    01778
    01779         //
    01780         //  Set our preliminary status now to success because
    01781         //  the call to the open procedure might change this
    01782         //
    01783
    01784         Status = STATUS_SUCCESS;
    01785
    01786         //
    01787         //  If the object type has an open procedure
    01788         //  then invoke that procedure
    01789         //
    01790
    01791         if (ObjectType->TypeInfo.OpenProcedure != NULL) {
    01792
    01793             KIRQL SaveIrql;
    01794
    01795             //
    01796             //  Leave the object type mutex when call the OpenProcedure. If an exception
    01797             //  while OpenProcedure the HoldObjectTypeMutex disable leaving the mutex
    01798             //  on finally block
    01799             //
    01800
    01801             ObpLeaveObjectTypeMutex( ObjectType );
    01802             HoldObjectTypeMutex = FALSE;
    01803
    01804             ObpBeginTypeSpecificCallOut( SaveIrql );
    01805
    01806             try {
    01807
    01808                 (*ObjectType->TypeInfo.OpenProcedure)( ObCreateHandle,
    01809                                                        Process,
    01810                                                        Object,
    01811                                                        *DesiredAccess,
    01812                                                        ProcessHandleCount );
    01813
    01814             } except( EXCEPTION_EXECUTE_HANDLER ) {
    01815
    01816                 Status = GetExceptionCode();
    01817             }
    01818
    01819             ObpEndTypeSpecificCallOut( SaveIrql, "Open", ObjectType, Object );
    01820
    01821             //
    01822             //  Hold back the object type mutex and set the HoldObjectTypeMutex variable
    01823             //  to allow releasing the mutex while leaving this procedure
    01824             //
    01825
    01826             ObpEnterObjectTypeMutex( ObjectType );
    01827             HoldObjectTypeMutex = TRUE;
    01828
    01829             if (!NT_SUCCESS(Status)) {
    01830
    01831                 (VOID)ObpDecrHandleCount( ObjectHeader );
    01832                 leave;
    01833             }
    01834         }
    01835
    01836         //
    01837         //  Do some simple bookkeeping for the handle counts
    01838         //  and then return to our caller
    01839         //
    01840
    01841         ObjectType->TotalNumberOfHandles += 1;
    01842
    01843         if (ObjectType->TotalNumberOfHandles > ObjectType->HighWaterNumberOfHandles) {
    01844
    01845             ObjectType->HighWaterNumberOfHandles = ObjectType->TotalNumberOfHandles;
    01846         }
    01847
    01848     } finally {
    01849
    01850         if ( HoldObjectTypeMutex ) {
    01851
    01852             ObpLeaveObjectTypeMutex( ObjectType );
    01853         }
    01854     }
    01855
    01856     return( Status );
    01857 }
    01858
    01859
    01860 NTSTATUS
    01861 ObpChargeQuotaForObject (
    01862     IN POBJECT_HEADER ObjectHeader,
    01863     IN POBJECT_TYPE ObjectType,
    01864     OUT PBOOLEAN NewObject
    01865     )
    01866
    01867 /*++
    01868
    01869 Routine Description:
    01870
    01871     This routine charges quota against the current process for the new
    01872     object
    01873
    01874 Arguments:
    01875
    01876     ObjectHeader - Supplies a pointer to the new object being charged for
    01877
    01878     ObjectType - Supplies the type of the new object
    01879
    01880     NewObject - Returns true if the object is really new and false otherwise
    01881
    01882 Return Value:
    01883
    01884     An appropriate status value
    01885
    01886 --*/
    01887
    01888 {
    01889     POBJECT_HEADER_QUOTA_INFO QuotaInfo;
    01890     ULONG NonPagedPoolCharge;
    01891     ULONG PagedPoolCharge;
    01892
    01893     //
    01894     //  Get a pointer to the quota block for this object
    01895     //
    01896
    01897     QuotaInfo = OBJECT_HEADER_TO_QUOTA_INFO( ObjectHeader );
    01898
    01899     *NewObject = FALSE;
    01900
    01901     //
    01902     //  If the object is new then we have work to do otherwise
    01903     //  we'll return with NewObject set to false
    01904     //
    01905
    01906     if (ObjectHeader->Flags & OB_FLAG_NEW_OBJECT) {
    01907
    01908         //
    01909         //  Say the object now isn't new
    01910         //
    01911
    01912         ObjectHeader->Flags &= ~OB_FLAG_NEW_OBJECT;
    01913
    01914         //
    01915         //  If there does exist a quota info structure for this
    01916         //  object then calculate what our charge should be from
    01917         //  the information stored in that structure
    01918         //
    01919
    01920         if (QuotaInfo != NULL) {
    01921
    01922             PagedPoolCharge = QuotaInfo->PagedPoolCharge +
    01923                               QuotaInfo->SecurityDescriptorCharge;
    01924             NonPagedPoolCharge = QuotaInfo->NonPagedPoolCharge;
    01925
    01926         } else {
    01927
    01928             //
    01929             //  There isn't any quota information so we're on our own
    01930             //  Paged pool charge is the default for the object plus
    01931             //  the security descriptor if present.  Nonpaged pool charge
    01932             //  is the default for the object.
    01933             //
    01934
    01935             PagedPoolCharge = ObjectType->TypeInfo.DefaultPagedPoolCharge;
    01936
    01937             if (ObjectHeader->SecurityDescriptor != NULL) {
    01938
    01939                 ObjectHeader->Flags |= OB_FLAG_DEFAULT_SECURITY_QUOTA;
    01940                 PagedPoolCharge += SE_DEFAULT_SECURITY_QUOTA;
    01941             }
    01942
    01943             NonPagedPoolCharge = ObjectType->TypeInfo.DefaultNonPagedPoolCharge;
    01944         }
    01945
    01946         //
    01947         //  Now charge for the quota and make sure it succeeds
    01948         //
    01949
    01950         ObjectHeader->QuotaBlockCharged = (PVOID)PsChargeSharedPoolQuota( PsGetCurrentProcess(),
    01951                                                                           PagedPoolCharge,
    01952                                                                           NonPagedPoolCharge );
    01953
    01954         if (ObjectHeader->QuotaBlockCharged == NULL) {
    01955
    01956             return STATUS_QUOTA_EXCEEDED;
    01957         }
    01958
    01959         *NewObject = TRUE;
    01960     }
    01961
    01962     return STATUS_SUCCESS;
    01963 }
    01964
    01965
    01966 VOID
    01967 ObpDecrementHandleCount (
    01968     PEPROCESS Process,
    01969     POBJECT_HEADER ObjectHeader,
    01970     POBJECT_TYPE ObjectType,
    01971     ACCESS_MASK GrantedAccess
    01972     )
    01973
    01974 /*++
    01975
    01976 Routine Description:
    01977
    01978     This procedure decrements the handle count for the specified object
    01979
    01980 Arguments:
    01981
    01982     Process - Supplies the process where the handle existed
    01983
    01984     ObjectHeader - Supplies a pointer to the object header for the object
    01985
    01986     ObjectType - Supplies a type of the object
    01987
    01988     GrantedAccess - Supplies the current access mask to the object
    01989
    01990 Return Value:
    01991
    01992     None.
    01993
    01994 --*/
    01995
    01996 {
    01997     POBJECT_HEADER_HANDLE_INFO HandleInfo;
    01998     POBJECT_HANDLE_COUNT_DATABASE HandleCountDataBase;
    01999     POBJECT_HANDLE_COUNT_ENTRY HandleCountEntry;
    02000     POBJECT_HEADER_CREATOR_INFO CreatorInfo;
    02001     PVOID Object;
    02002     ULONG CountEntries;
    02003     ULONG ProcessHandleCount;
    02004     ULONG SystemHandleCount;
    02005     BOOLEAN HandleCountIsZero;
    02006
    02007     PAGED_CODE();
    02008
    02009     ObpEnterObjectTypeMutex( ObjectType );
    02010
    02011     Object = (PVOID)&ObjectHeader->Body;
    02012
    02013     SystemHandleCount = ObjectHeader->HandleCount;
    02014     ProcessHandleCount = 0;
    02015
    02016     //
    02017     //  Decrement the handle count and it was one and it
    02018     //  was an exclusive object then zero out the exclusive
    02019     //  process
    02020     //
    02021
    02022     HandleCountIsZero = ObpDecrHandleCount( ObjectHeader );
    02023
    02024     if ( HandleCountIsZero &&
    02025         (ObjectHeader->Flags & OB_FLAG_EXCLUSIVE_OBJECT)) {
    02026
    02027         OBJECT_HEADER_TO_QUOTA_INFO( ObjectHeader )->ExclusiveProcess = NULL;
    02028     }
    02029
    02030     if ( HandleCountIsZero ) {
    02031
    02032         CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO( ObjectHeader );
    02033
    02034         //
    02035         //  If there is a creator info record and we are on the list
    02036         //  for the object type then remove this object from the list
    02037         //
    02038
    02039         if (CreatorInfo != NULL && !IsListEmpty( &CreatorInfo->TypeList )) {
    02040
    02041             RemoveEntryList( &CreatorInfo->TypeList );
    02042
    02043             InitializeListHead( &CreatorInfo->TypeList );
    02044         }
    02045     }
    02046
    02047     //
    02048     //  If the object maintains a handle count database then
    02049     //  search through the handle database and decrement
    02050     //  the necessary information
    02051     //
    02052
    02053     if (ObjectType->TypeInfo.MaintainHandleCount) {
    02054
    02055         HandleInfo = OBJECT_HEADER_TO_HANDLE_INFO( ObjectHeader );
    02056
    02057         //
    02058         //  Check if there is a single handle entry, then it better
    02059         //  be ours
    02060         //
    02061
    02062         if (ObjectHeader->Flags & OB_FLAG_SINGLE_HANDLE_ENTRY) {
    02063
    02064             ASSERT(HandleInfo->SingleEntry.Process == Process);
    02065             ASSERT(HandleInfo->SingleEntry.HandleCount > 0);
    02066
    02067             ProcessHandleCount = HandleInfo->SingleEntry.HandleCount--;
    02068             HandleCountEntry = &HandleInfo->SingleEntry;
    02069
    02070         } else {
    02071
    02072             //
    02073             //  Otherwise search the database for a process match
    02074             //
    02075
    02076             HandleCountDataBase = HandleInfo->HandleCountDataBase;
    02077
    02078             if (HandleCountDataBase != NULL) {
    02079
    02080                 CountEntries = HandleCountDataBase->CountEntries;
    02081                 HandleCountEntry = &HandleCountDataBase->HandleCountEntries[ 0 ];
    02082
    02083                 while (CountEntries) {
    02084
    02085                     if ((HandleCountEntry->HandleCount != 0) &&
    02086                         (HandleCountEntry->Process == Process)) {
    02087
    02088                         ProcessHandleCount = HandleCountEntry->HandleCount--;
    02089
    02090                         break;
    02091                     }
    02092
    02093                     HandleCountEntry++;
    02094                     CountEntries--;
    02095                 }
    02096             }
    02097         }
    02098
    02099         //
    02100         //  Now if the process is giving up all handles to the object
    02101         //  then zero out the handle count entry.  For a single handle
    02102         //  entry this is just the single entry in the header handle info
    02103         //  structure
    02104         //
    02105
    02106         if (ProcessHandleCount == 1) {
    02107
    02108             HandleCountEntry->Process = NULL;
    02109             HandleCountEntry->HandleCount = 0;
    02110         }
    02111     }
    02112
    02113     //
    02114     //  If the Object Type has a Close Procedure, then release the type
    02115     //  mutex before calling it, and then call ObpDeleteNameCheck without
    02116     //  the mutex held.
    02117     //
    02118
    02119     if (ObjectType->TypeInfo.CloseProcedure) {
    02120
    02121         KIRQL SaveIrql;
    02122
    02123         ObpLeaveObjectTypeMutex( ObjectType );
    02124
    02125         ObpBeginTypeSpecificCallOut( SaveIrql );
    02126
    02127         (*ObjectType->TypeInfo.CloseProcedure)( Process,
    02128                                                 Object,
    02129                                                 GrantedAccess,
    02130                                                 ProcessHandleCount,
    02131                                                 SystemHandleCount );
    02132
    02133         ObpEndTypeSpecificCallOut( SaveIrql, "Close", ObjectType, Object );
    02134
    02135         ObpDeleteNameCheck( Object, FALSE );
    02136
    02137     } else {
    02138
    02139         //
    02140         //  If there is no Close Procedure, then just call ObpDeleteNameCheck
    02141         //  with the mutex held.
    02142         //
    02143         //  The following call will release the type mutex
    02144         //
    02145
    02146         ObpDeleteNameCheck( Object, TRUE );
    02147     }
    02148
    02149     ObpEnterObjectTypeMutex( ObjectType );
    02150
    02151     ObjectType->TotalNumberOfHandles -= 1;
    02152
    02153     ObpLeaveObjectTypeMutex( ObjectType );
    02154
    02155     return;
    02156 }
    02157
    02158
    02159 NTSTATUS
    02160 ObpCreateHandle (
    02161     IN OB_OPEN_REASON OpenReason,
    02162     IN PVOID Object,
    02163     IN POBJECT_TYPE ExpectedObjectType OPTIONAL,
    02164     IN PACCESS_STATE AccessState,
    02165     IN ULONG ObjectPointerBias OPTIONAL,
    02166     IN ULONG Attributes,
    02167     IN BOOLEAN DirectoryLocked,
    02168     IN KPROCESSOR_MODE AccessMode,
    02169     OUT PVOID *ReferencedNewObject OPTIONAL,
    02170     OUT PHANDLE Handle
    02171     )
    02172
    02173 /*++
    02174
    02175 Routine Description:
    02176
    02177     This function creates a new handle to an existing object
    02178
    02179 Arguments:
    02180
    02181     OpenReason - The reason why we are doing this work
    02182
    02183     Object - A pointer to the body of the new object
    02184
    02185     ExpectedObjectType - Optionally Supplies the object type that
    02186         the caller is expecting
    02187
    02188     AccessState - Supplies the access state for the handle requested
    02189         by the caller
    02190
    02191     ObjectPointerBias - Optionally supplies a count of addition
    02192         increments we do to the pointer count for the object
    02193
    02194     Attributes -  Desired attributes for the handle
    02195
    02196     DirectoryLocked - Indicates if the root directory mutex is already held
    02197
    02198     AccessMode - Supplies the mode of the requestor.
    02199
    02200     ReferencedNewObject - Optionally receives a pointer to the body
    02201         of the new object
    02202
    02203     Handle - Receives the new handle value
    02204
    02205 Return Value:
    02206
    02207     An appropriate status value
    02208
    02209 --*/
    02210
    02211 {
    02212     NTSTATUS Status;
    02213     POBJECT_HEADER ObjectHeader;
    02214     POBJECT_TYPE ObjectType;
    02215     PVOID ObjectTable;
    02216     HANDLE_TABLE_ENTRY ObjectTableEntry;
    02217     HANDLE NewHandle;
    02218     ACCESS_MASK DesiredAccess;
    02219     ACCESS_MASK GrantedAccess;
    02220     ULONG BiasCount;
    02221     BOOLEAN AttachedToProcess = FALSE;
    02222     BOOLEAN KernelHandle = FALSE;
    02223     KAPC_STATE ApcState;
    02224
    02225     PAGED_CODE();
    02226
    02227     ObpValidateIrql( "ObpCreateHandle" );
    02228
    02229     //
    02230     //  Merge both the remaining desired access and the currently
    02231     //  granted access states into one mask
    02232     //
    02233     //  **** why is this being done here and then later in the this
    02234     //  same routine.
    02235     //
    02236
    02237     DesiredAccess = AccessState->RemainingDesiredAccess |
    02238                     AccessState->PreviouslyGrantedAccess;
    02239
    02240     //
    02241     //  Get a pointer to the object header and object type
    02242     //
    02243
    02244     ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
    02245     ObjectType = ObjectHeader->Type;
    02246
    02247     //
    02248     //  If the object type isn't what was expected then
    02249     //  return an error to our caller, but first see if
    02250     //  we should release the directory mutex
    02251     //
    02252
    02253     if ((ARGUMENT_PRESENT( ExpectedObjectType )) &&
    02254         (ObjectType != ExpectedObjectType )) {
    02255
    02256         if (DirectoryLocked) {
    02257
    02258             ObpLeaveRootDirectoryMutex();
    02259         }
    02260
    02261         return( STATUS_OBJECT_TYPE_MISMATCH );
    02262     }
    02263
    02264     //
    02265     //  Set the first ulong of the object table entry to point
    02266     //  back to the object header
    02267     //
    02268
    02269     ObjectTableEntry.Object = ObjectHeader;
    02270
    02271     //
    02272     //  Now get a pointer to the object table for either the current process
    02273     //  of the kernel handle table
    02274     //
    02275
    02276     if ((Attributes & OBJ_KERNEL_HANDLE) && (AccessMode == KernelMode)) {
    02277
    02278         ObjectTable = ObpKernelHandleTable;
    02279         KernelHandle = TRUE;
    02280
    02281         //
    02282         //  Go to the system process if we have to
    02283         //
    02284
    02285         if (PsGetCurrentProcess() != PsInitialSystemProcess) {
    02286             KeStackAttachProcess (&PsInitialSystemProcess->Pcb, &ApcState);
    02287             AttachedToProcess = TRUE;
    02288         }
    02289
    02290
    02291     } else {
    02292
    02293         ObjectTable = ObpGetObjectTable();
    02294     }
    02295
    02296     //
    02297     //  ObpIncrementHandleCount will perform access checking on the
    02298     //  object being opened as appropriate.
    02299     //
    02300
    02301     Status = ObpIncrementHandleCount( OpenReason,
    02302                                       PsGetCurrentProcess(),
    02303                                       Object,
    02304                                       ObjectType,
    02305                                       AccessState,
    02306                                       AccessMode,
    02307                                       Attributes );
    02308
    02309     if (AccessState->GenerateOnClose) {
    02310
    02311         Attributes |= OBJ_AUDIT_OBJECT_CLOSE;
    02312     }
    02313
    02314     //
    02315     //  Or in some low order bits into the first ulong of the object
    02316     //  table entry
    02317     //
    02318
    02319     ObjectTableEntry.ObAttributes |= (Attributes & OBJ_HANDLE_ATTRIBUTES);
    02320
    02321     //
    02322     //  Merge both the remaining desired access and the currently
    02323     //  granted access states into one mask and then compute
    02324     //  the granted access
    02325     //
    02326
    02327     DesiredAccess = AccessState->RemainingDesiredAccess |
    02328                     AccessState->PreviouslyGrantedAccess;
    02329
    02330     GrantedAccess = DesiredAccess &
    02331                     (ObjectType->TypeInfo.ValidAccessMask | ACCESS_SYSTEM_SECURITY );
    02332
    02333     //
    02334     //  Unlock the directory if it is locked and make sure
    02335     //  we've been successful so far
    02336     //
    02337
    02338     if (DirectoryLocked) {
    02339
    02340         ObpLeaveRootDirectoryMutex();
    02341     }
    02342
    02343     if (!NT_SUCCESS( Status )) {
    02344
    02345         //
    02346         //  If we are attached to the system process then return
    02347         //  back to our caller
    02348         //
    02349
    02350         if (AttachedToProcess) {
    02351             KeUnstackDetachProcess(&ApcState);
    02352             AttachedToProcess = FALSE;
    02353         }
    02354
    02355         return( Status );
    02356     }
    02357
    02358     //
    02359     //  Bias the pointer count if that is what the caller wanted
    02360     //
    02361
    02362     if (ARGUMENT_PRESENT( (PVOID)(ULONG_PTR)ObjectPointerBias )) {
    02363
    02364         BiasCount = ObjectPointerBias;
    02365
    02366         while (BiasCount--) {
    02367
    02368             ObpIncrPointerCount( ObjectHeader );
    02369         }
    02370     }
    02371
    02372     //
    02373     //  Set the granted access mask in the object table entry (second ulong)
    02374     //
    02375
    02376 #if i386 && !FPO
    02377
    02378     if (NtGlobalFlag & FLG_KERNEL_STACK_TRACE_DB) {
    02379
    02380         ObjectTableEntry.GrantedAccessIndex = ObpComputeGrantedAccessIndex( GrantedAccess );
    02381         ObjectTableEntry.CreatorBackTraceIndex = RtlLogStackBackTrace();
    02382
    02383     } else {
    02384
    02385         ObjectTableEntry.GrantedAccess = GrantedAccess;
    02386     }
    02387
    02388 #else
    02389
    02390     ObjectTableEntry.GrantedAccess = GrantedAccess;
    02391
    02392 #endif // i386 && !FPO
    02393
    02394     //
    02395     //  Add this new object table entry to the object table for the process
    02396     //
    02397
    02398     NewHandle = ExCreateHandle( ObjectTable, &ObjectTableEntry );
    02399
    02400     //
    02401     //  If we didn't get a handle then cleanup after ourselves and return
    02402     //  the error to our caller
    02403     //
    02404
    02405     if (NewHandle == NULL) {
    02406
    02407         if (ARGUMENT_PRESENT( (PVOID)(ULONG_PTR)ObjectPointerBias )) {
    02408
    02409             BiasCount = ObjectPointerBias;
    02410
    02411             while (BiasCount--) {
    02412
    02413                 ObpDecrPointerCount( ObjectHeader );
    02414             }
    02415         }
    02416
    02417         ObpDecrementHandleCount( PsGetCurrentProcess(),
    02418                                  ObjectHeader,
    02419                                  ObjectType,
    02420                                  GrantedAccess );
    02421
    02422         //
    02423         //  If we are attached to the system process then return
    02424         //  back to our caller
    02425         //
    02426
    02427         if (AttachedToProcess) {
    02428             KeUnstackDetachProcess(&ApcState);
    02429             AttachedToProcess = FALSE;
    02430         }
    02431
    02432         return( STATUS_INSUFFICIENT_RESOURCES );
    02433     }
    02434
    02435     //
    02436     //  We have a new Ex style handle now make it an ob style handle and also
    02437     //  adjust for the kernel handle by setting the sign bit in the handle
    02438     //  value
    02439     //
    02440
    02441     if (KernelHandle) {
    02442
    02443         NewHandle = EncodeKernelHandle( NewHandle );
    02444     }
    02445
    02446     *Handle = NewHandle;
    02447
    02448     //
    02449     //  If requested, generate audit messages to indicate that a new handle
    02450     //  has been allocated.
    02451     //
    02452     //  This is the final security operation in the creation/opening of the
    02453     //  object.
    02454     //
    02455
    02456     if ( AccessState->GenerateAudit ) {
    02457
    02458         SeAuditHandleCreation( AccessState,
    02459                                *Handle );
    02460     }
    02461
    02462     if (OpenReason == ObCreateHandle) {
    02463
    02464         PAUX_ACCESS_DATA AuxData = AccessState->AuxData;
    02465
    02466         if ( ( AuxData->PrivilegesUsed != NULL) && (AuxData->PrivilegesUsed->PrivilegeCount > 0) ) {
    02467
    02468             SePrivilegeObjectAuditAlarm( *Handle,
    02469                                          &AccessState->SubjectSecurityContext,
    02470                                          GrantedAccess,
    02471                                          AuxData->PrivilegesUsed,
    02472                                          TRUE,
    02473                                          KeGetPreviousMode() );
    02474         }
    02475     }
    02476
    02477     //
    02478     //  If the caller had a pointer bias and wanted the new reference object
    02479     //  then return that value
    02480     //
    02481
    02482     if ((ARGUMENT_PRESENT( (PVOID)(ULONG_PTR)ObjectPointerBias )) &&
    02483         (ARGUMENT_PRESENT( ReferencedNewObject ))) {
    02484
    02485         *ReferencedNewObject = Object;
    02486     }
    02487
    02488     //
    02489     //  If we are attached to the system process then return
    02490     //  back to our caller
    02491     //
    02492
    02493     if (AttachedToProcess) {
    02494         KeUnstackDetachProcess(&ApcState);
    02495         AttachedToProcess = FALSE;
    02496     }
    02497
    02498     //
    02499     //  And return to our caller
    02500     //
    02501
    02502     return( STATUS_SUCCESS );
    02503 }
    02504
    02505
    02506 NTSTATUS
    02507 ObpCreateUnnamedHandle (
    02508     IN PVOID Object,
    02509     IN ACCESS_MASK DesiredAccess,
    02510     IN ULONG ObjectPointerBias OPTIONAL,
    02511     IN ULONG Attributes,
    02512     IN KPROCESSOR_MODE AccessMode,
    02513     OUT PVOID *ReferencedNewObject OPTIONAL,
    02514     OUT PHANDLE Handle
    02515     )
    02516
    02517 /*++
    02518
    02519 Routine Description:
    02520
    02521     This function creates a new unnamed handle for an existing object
    02522
    02523 Arguments:
    02524
    02525     Object - A pointer to the body of the new object
    02526
    02527     DesiredAccess - Supplies the access mask being requsted
    02528
    02529     ObjectPointerBias - Optionally supplies a count of addition
    02530         increments we do to the pointer count for the object
    02531
    02532     Attributes -  Desired attributes for the handle
    02533
    02534     AccessMode - Supplies the mode of the requestor.
    02535
    02536     ReferencedNewObject - Optionally receives a pointer to the body
    02537         of the new object
    02538
    02539     Handle - Receives the new handle value
    02540
    02541 Return Value:
    02542
    02543     An appropriate status value
    02544
    02545 --*/
    02546
    02547 {
    02548     NTSTATUS Status;
    02549     POBJECT_HEADER ObjectHeader;
    02550     POBJECT_TYPE ObjectType;
    02551     PVOID ObjectTable;
    02552     HANDLE_TABLE_ENTRY ObjectTableEntry;
    02553     HANDLE NewHandle;
    02554     ULONG BiasCount;
    02555     ACCESS_MASK GrantedAccess;
    02556     BOOLEAN AttachedToProcess = FALSE;
    02557     BOOLEAN KernelHandle = FALSE;
    02558     KAPC_STATE ApcState;
    02559
    02560     PAGED_CODE();
    02561
    02562     ObpValidateIrql( "ObpCreateUnnamedHandle" );
    02563
    02564     //
    02565     //  Get the object header and type for the new object
    02566     //
    02567
    02568     ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
    02569     ObjectType = ObjectHeader->Type;
    02570
    02571     //
    02572     //  Set the first ulong of the object table entry to point
    02573     //  to the object header and then or in the low order attribute
    02574     //  bits
    02575     //
    02576
    02577     ObjectTableEntry.Object = ObjectHeader;
    02578
    02579     ObjectTableEntry.ObAttributes |= (Attributes & OBJ_HANDLE_ATTRIBUTES);
    02580
    02581     //
    02582     //  Now get a pointer to the object table for either the current process
    02583     //  of the kernel handle table
    02584     //
    02585
    02586     if ((Attributes & OBJ_KERNEL_HANDLE) && (AccessMode == KernelMode)) {
    02587
    02588         ObjectTable = ObpKernelHandleTable;
    02589         KernelHandle = TRUE;
    02590
    02591         //
    02592         //  Go to the system process if we have to
    02593         //
    02594
    02595         if (PsGetCurrentProcess() != PsInitialSystemProcess) {
    02596             KeStackAttachProcess (&PsInitialSystemProcess->Pcb, &ApcState);
    02597             AttachedToProcess = TRUE;
    02598         }
    02599
    02600     } else {
    02601
    02602         ObjectTable = ObpGetObjectTable();
    02603     }
    02604
    02605     //
    02606     //  Increment the handle count, this routine also does the access
    02607     //  check if necessary
    02608     //
    02609
    02610     Status = ObpIncrementUnnamedHandleCount( &DesiredAccess,
    02611                                              PsGetCurrentProcess(),
    02612                                              Object,
    02613                                              ObjectType,
    02614                                              AccessMode,
    02615                                              Attributes );
    02616
    02617
    02618     GrantedAccess = DesiredAccess &
    02619                     (ObjectType->TypeInfo.ValidAccessMask | ACCESS_SYSTEM_SECURITY );
    02620
    02621     if (!NT_SUCCESS( Status )) {
    02622
    02623         //
    02624         //  If we are attached to the system process then return
    02625         //  back to our caller
    02626         //
    02627
    02628         if (AttachedToProcess) {
    02629             KeUnstackDetachProcess(&ApcState);
    02630             AttachedToProcess = FALSE;
    02631         }
    02632
    02633         return( Status );
    02634     }
    02635
    02636     //
    02637     //  Bias the pointer count if that is what the caller wanted
    02638     //
    02639
    02640     if (ARGUMENT_PRESENT( (PVOID)(ULONG_PTR)ObjectPointerBias )) {
    02641
    02642         BiasCount = ObjectPointerBias;
    02643
    02644         while (BiasCount--) {
    02645
    02646             ObpIncrPointerCount( ObjectHeader );
    02647         }
    02648     }
    02649
    02650     //
    02651     //  Set the granted access mask in the object table entry (second ulong)
    02652     //
    02653
    02654 #if i386 && !FPO
    02655
    02656     if (NtGlobalFlag & FLG_KERNEL_STACK_TRACE_DB) {
    02657
    02658         ObjectTableEntry.GrantedAccessIndex = ObpComputeGrantedAccessIndex( GrantedAccess );
    02659         ObjectTableEntry.CreatorBackTraceIndex = RtlLogStackBackTrace();
    02660
    02661     } else {
    02662
    02663         ObjectTableEntry.GrantedAccess = GrantedAccess;
    02664     }
    02665
    02666 #else
    02667
    02668     ObjectTableEntry.GrantedAccess = GrantedAccess;
    02669
    02670 #endif // i386 && !FPO
    02671
    02672     //
    02673     //  Add this new object table entry to the object table for the process
    02674     //
    02675
    02676     NewHandle = ExCreateHandle( ObjectTable, &ObjectTableEntry );
    02677
    02678     //
    02679     //  If we didn't get a handle then cleanup after ourselves and return
    02680     //  the error to our caller
    02681     //
    02682
    02683     if (NewHandle == NULL) {
    02684
    02685         if (ARGUMENT_PRESENT( (PVOID)(ULONG_PTR)ObjectPointerBias )) {
    02686
    02687             BiasCount = ObjectPointerBias;
    02688
    02689             while (BiasCount--) {
    02690
    02691                 ObpDecrPointerCount( ObjectHeader );
    02692             }
    02693         }
    02694
    02695         ObpDecrementHandleCount( PsGetCurrentProcess(),
    02696                                  ObjectHeader,
    02697                                  ObjectType,
    02698                                  GrantedAccess );
    02699
    02700         //
    02701         //  If we are attached to the system process then return
    02702         //  back to our caller
    02703         //
    02704
    02705         if (AttachedToProcess) {
    02706             KeUnstackDetachProcess(&ApcState);
    02707             AttachedToProcess = FALSE;
    02708         }
    02709
    02710         return( STATUS_INSUFFICIENT_RESOURCES );
    02711     }
    02712
    02713     //
    02714     //  We have a new Ex style handle now make it an ob style handle and also
    02715     //  adjust for the kernel handle by setting the sign bit in the handle
    02716     //  value
    02717     //
    02718
    02719     if (KernelHandle) {
    02720
    02721         NewHandle = EncodeKernelHandle( NewHandle );
    02722     }
    02723
    02724     *Handle = NewHandle;
    02725
    02726     //
    02727     //  If the caller had a pointer bias and wanted the new reference object
    02728     //  then return that value
    02729     //
    02730
    02731     if ((ARGUMENT_PRESENT( (PVOID)(ULONG_PTR)ObjectPointerBias )) &&
    02732         (ARGUMENT_PRESENT( ReferencedNewObject ))) {
    02733
    02734         *ReferencedNewObject = Object;
    02735     }
    02736
    02737     //
    02738     //  If we are attached to the system process then return
    02739     //  back to our caller
    02740     //
    02741
    02742     if (AttachedToProcess) {
    02743         KeUnstackDetachProcess(&ApcState);
    02744         AttachedToProcess = FALSE;
    02745     }
    02746
    02747     return( STATUS_SUCCESS );
    02748 }
    02749
    02750
    02751 NTSTATUS
    02752 ObpValidateDesiredAccess (
    02753     IN ACCESS_MASK DesiredAccess
    02754     )
    02755
    02756 /*++
    02757
    02758 Routine Description:
    02759
    02760     This routine checks the input desired access mask to see that
    02761     some invalid bits are not set.  The invalid bits are the top
    02762     two reserved bits and the top three standard rights bits.
    02763     See \nt\public\sdk\inc\ntseapi.h for more details.
    02764
    02765 Arguments:
    02766
    02767     DesiredAccess - Supplies the mask being checked
    02768
    02769 Return Value:
    02770
    02771     STATUS_ACCESS_DENIED if one or more of the wrongs bits are set and
    02772     STATUS_SUCCESS otherwise
    02773
    02774 --*/
    02775
    02776 {
    02777     if (DesiredAccess & 0x0CE00000) {
    02778
    02779         return( STATUS_ACCESS_DENIED );
    02780
    02781     } else {
    02782
    02783         return( STATUS_SUCCESS );
    02784     }
    02785 }
    02786
    02787
    02788 #if i386 && !FPO
    02789
    02790 //
    02791 //  The following three variables are just performance counters
    02792 //  for the following two routines
    02793 //
    02794
    02795 ULONG ObpXXX1;
    02796 ULONG ObpXXX2;
    02797 ULONG ObpXXX3;
    02798
    02799 USHORT
    02800 ObpComputeGrantedAccessIndex (
    02801     ACCESS_MASK GrantedAccess
    02802     )
    02803
    02804 /*++
    02805
    02806 Routine Description:
    02807
    02808     This routine takes a granted access and returns and index
    02809     back to our cache of granted access masks.
    02810
    02811 Arguments:
    02812
    02813     GrantedAccess - Supplies the access mask being added to the cache
    02814
    02815 Return Value:
    02816
    02817     USHORT - returns an index in the cache for the input granted access
    02818
    02819 --*/
    02820
    02821 {
    02822     KIRQL OldIrql;
    02823     ULONG GrantedAccessIndex, n;
    02824     PACCESS_MASK p;
    02825
    02826     ObpXXX1 += 1;
    02827
    02828     //
    02829     //  Lock the global data structure
    02830     //
    02831
    02832     ExAcquireFastLock( &ObpLock, &OldIrql );
    02833
    02834     n = ObpCurCachedGrantedAccessIndex;
    02835     p = ObpCachedGrantedAccesses;
    02836
    02837     //
    02838     //  For each index in our cache look for a match and if found
    02839     //  then unlock the data structure and return that index
    02840     //
    02841
    02842     for (GrantedAccessIndex = 0; GrantedAccessIndex < n; GrantedAccessIndex++, p++ ) {
    02843
    02844         ObpXXX2 += 1;
    02845
    02846         if (*p == GrantedAccess) {
    02847
    02848             ExReleaseFastLock( &ObpLock, OldIrql );
    02849             return (USHORT)GrantedAccessIndex;
    02850         }
    02851     }
    02852
    02853     //
    02854     //  We didn't find a match now see if we've maxed out the cache
    02855     //
    02856
    02857     if (ObpCurCachedGrantedAccessIndex == ObpMaxCachedGrantedAccessIndex) {
    02858
    02859         DbgPrint( "OB: GrantedAccess cache limit hit.\n" );
    02860         DbgBreakPoint();
    02861     }
    02862
    02863     //
    02864     //  Set the granted access to the next free slot and increment the
    02865     //  number used in the cache, release the lock, and return the
    02866     //  new index to our caller
    02867     //
    02868
    02869     *p = GrantedAccess;
    02870     ObpCurCachedGrantedAccessIndex += 1;
    02871
    02872     ExReleaseFastLock( &ObpLock, OldIrql );
    02873
    02874     return (USHORT)GrantedAccessIndex;
    02875 }
    02876
    02877 ACCESS_MASK
    02878 ObpTranslateGrantedAccessIndex (
    02879     USHORT GrantedAccessIndex
    02880     )
    02881
    02882 /*++
    02883
    02884 Routine Description:
    02885
    02886     This routine takes as input a cache index and returns
    02887     the corresponding granted access mask
    02888
    02889 Arguments:
    02890
    02891     GrantedAccessIndex - Supplies the cache index to look up
    02892
    02893 Return Value:
    02894
    02895     ACCESS_MASK - Returns the corresponding desired access mask
    02896
    02897 --*/
    02898
    02899 {
    02900     KIRQL OldIrql;
    02901     ACCESS_MASK GrantedAccess = (ACCESS_MASK)0;
    02902
    02903     ObpXXX3 += 1;
    02904
    02905     //
    02906     //  Lock the global data structure
    02907     //
    02908
    02909     ExAcquireFastLock( &ObpLock, &OldIrql );
    02910
    02911     //
    02912     //  If the input index is within bounds then get the granted
    02913     //  access
    02914     //
    02915
    02916     if (GrantedAccessIndex < ObpCurCachedGrantedAccessIndex) {
    02917
    02918         GrantedAccess = ObpCachedGrantedAccesses[ GrantedAccessIndex ];
    02919     }
    02920
    02921     //
    02922     //  Release the lock and return the granted access to our caller
    02923     //
    02924
    02925     ExReleaseFastLock( &ObpLock, OldIrql );
    02926
    02927     return GrantedAccess;
    02928 }
    02929
    02930 #endif // i386 && !FPO
    02931