test: obse.c Source File

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

# obse.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1989  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     obse.c
    00008
    00009 Abstract:
    00010
    00011     Object Security API calls
    00012
    00013 Author:
    00014
    00015     Steve Wood (stevewo) 31-Mar-1989
    00016
    00017 Revision History:
    00018
    00019 --*/
    00020
    00021 #include "obp.h"
    00022
    00023 #if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
    00024
    00025 #pragma alloc_text(PAGE,NtSetSecurityObject)
    00026 #pragma alloc_text(PAGE,NtQuerySecurityObject)
    00027 #pragma alloc_text(PAGE,ObAssignObjectSecurityDescriptor)
    00028 #pragma alloc_text(PAGE,ObAssignSecurity)
    00029 #pragma alloc_text(PAGE,ObCheckCreateObjectAccess)
    00030 #pragma alloc_text(PAGE,ObCheckObjectAccess)
    00031 #pragma alloc_text(PAGE,ObCheckObjectReference)
    00032 #pragma alloc_text(PAGE,ObpCheckTraverseAccess)
    00033 #pragma alloc_text(PAGE,ObGetObjectSecurity)
    00034 #pragma alloc_text(PAGE,ObSetSecurityDescriptorInfo)
    00035 #pragma alloc_text(PAGE,ObQuerySecurityDescriptorInfo)
    00036 #pragma alloc_text(PAGE,ObReleaseObjectSecurity)
    00037 #pragma alloc_text(PAGE,ObSetSecurityQuotaCharged)
    00038 #pragma alloc_text(PAGE,ObValidateSecurityQuota)
    00039 #pragma alloc_text(PAGE,ObpValidateAccessMask)
    00040 #pragma alloc_text(PAGE,ObSetSecurityObjectByPointer)
    00041
    00042 #endif
    00043
    00044
    00045 NTSTATUS
    00046 NtSetSecurityObject (
    00047     IN HANDLE Handle,
    00048     IN SECURITY_INFORMATION SecurityInformation,
    00049     IN PSECURITY_DESCRIPTOR SecurityDescriptor
    00050     )
    00051
    00052 /*++
    00053
    00054 Routine Description:
    00055
    00056     This routine is used to invoke an object's security routine.  It
    00057     is used to set the object's security state.
    00058
    00059 Arguments:
    00060
    00061     Handle - Supplies the handle for the object being modified
    00062
    00063     SecurityInformation - Indicates the type of information we are
    00064         interested in setting. e.g., owner, group, dacl, or sacl.
    00065
    00066     SecurityDescriptor - Supplies the security descriptor for the
    00067         object being modified.
    00068
    00069 Return Value:
    00070
    00071     An appropriate NTSTATUS value
    00072
    00073 --*/
    00074
    00075 {
    00076     NTSTATUS Status;
    00077     PVOID Object;
    00078     ACCESS_MASK DesiredAccess;
    00079     OBJECT_HANDLE_INFORMATION HandleInformation;
    00080     KPROCESSOR_MODE RequestorMode;
    00081     SECURITY_DESCRIPTOR_RELATIVE *CapturedDescriptor;
    00082
    00083     PAGED_CODE();
    00084
    00085     //
    00086     //  Make sure the passed security descriptor is really there.
    00087     //  SeCaptureSecurityDescriptor doesn't mind being passed a NULL
    00088     //  SecurityDescriptor, and will just return NULL back.
    00089     //
    00090
    00091     if (!ARGUMENT_PRESENT( SecurityDescriptor )) {
    00092
    00093         return( STATUS_ACCESS_VIOLATION );
    00094     }
    00095
    00096     //
    00097     //  Establish the accesses needed to the object based upon the
    00098     //  security information being modified.
    00099     //
    00100
    00101     SeSetSecurityAccessMask( SecurityInformation, &DesiredAccess );
    00102
    00103     Status = ObReferenceObjectByHandle( Handle,
    00104                                         DesiredAccess,
    00105                                         NULL,
    00106                                         RequestorMode = KeGetPreviousMode(),
    00107                                         &Object,
    00108                                         &HandleInformation );
    00109
    00110     if (NT_SUCCESS( Status )) {
    00111
    00112         //
    00113         //  Probe and capture the input security descriptor, and return
    00114         //  right away if it is ill-formed.
    00115         //
    00116         //  Because the security descriptor is always captured the returned
    00117         //  security descriptor is in self-relative format.
    00118         //
    00119
    00120         Status = SeCaptureSecurityDescriptor( SecurityDescriptor,
    00121                                               RequestorMode,
    00122                                               PagedPool,
    00123                                               TRUE,
    00124                                               (PSECURITY_DESCRIPTOR *)&CapturedDescriptor );
    00125
    00126         if (NT_SUCCESS( Status )) {
    00127
    00128             //
    00129             //  Now check for a valid combination of what the user wants to set
    00130             //  and what was supplied in the input security descriptor.  If the
    00131             //  caller wants to set the owner then the owner field of the
    00132             //  security descriptor better not be null, likewise for the group
    00133             //  setting.  If anything is missing we'll return and error.
    00134             //
    00135
    00136             ASSERT(CapturedDescriptor->Control & SE_SELF_RELATIVE);
    00137
    00138             if (((SecurityInformation & OWNER_SECURITY_INFORMATION) &&
    00139                 (CapturedDescriptor->Owner == 0))
    00140
    00141                 ||
    00142
    00143                 ((SecurityInformation & GROUP_SECURITY_INFORMATION) &&
    00144                 (CapturedDescriptor->Group == 0))) {
    00145
    00146                 SeReleaseSecurityDescriptor( (PSECURITY_DESCRIPTOR)CapturedDescriptor,
    00147                                              RequestorMode,
    00148                                              TRUE );
    00149
    00150                 ObDereferenceObject( Object );
    00151
    00152                 ASSERT(FALSE);
    00153                 return( STATUS_INVALID_SECURITY_DESCR );
    00154             }
    00155
    00156             Status = ObSetSecurityObjectByPointer( Object,
    00157                                                    SecurityInformation,
    00158                                                    CapturedDescriptor );
    00159
    00160             SeReleaseSecurityDescriptor( (PSECURITY_DESCRIPTOR)CapturedDescriptor,
    00161                                          RequestorMode,
    00162                                          TRUE );
    00163         }
    00164
    00165         ObDereferenceObject( Object );
    00166
    00167     }
    00168
    00169     return( Status );
    00170 }
    00171
    00172
    00173 NTSTATUS
    00174 ObSetSecurityObjectByPointer (
    00175     IN PVOID Object,
    00176     IN SECURITY_INFORMATION SecurityInformation,
    00177     IN PSECURITY_DESCRIPTOR SecurityDescriptor
    00178     )
    00179
    00180 /*++
    00181
    00182 Routine Description:
    00183
    00184     This routine is used to invoke an object's security routine.  It
    00185     is used to set the object's security state.
    00186
    00187     This routine is accessible only to the kernel and assumes that all
    00188     necessary validation of parameters has been done by the caller.
    00189
    00190 Arguments:
    00191
    00192     Object - Supplies the pointer for the object being modified
    00193
    00194     SecurityInformation - Indicates the type of information we are
    00195         interested in setting. e.g., owner, group, dacl, or sacl.
    00196
    00197     SecurityDescriptor - Supplies the security descriptor for the
    00198         object being modified.
    00199
    00200 Return Value:
    00201
    00202     An appropriate NTSTATUS value
    00203
    00204 --*/
    00205
    00206 {
    00207     NTSTATUS Status;
    00208     POBJECT_HEADER ObjectHeader;
    00209     POBJECT_TYPE ObjectType;
    00210
    00211     PAGED_CODE();
    00212
    00213 //    DbgPrint("ObSetSecurityObjectByPointer called for object %#08lx with info "
    00214 //             "%x and descriptor %#08lx\n",
    00215 //             Object, SecurityInformation, SecurityDescriptor);
    00216
    00217     //
    00218     //  Map the object body to an object header and the corresponding
    00219     //  object type
    00220     //
    00221
    00222     ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
    00223     ObjectType = ObjectHeader->Type;
    00224
    00225     //
    00226     //  Make sure the passed security descriptor is really there.
    00227     //
    00228
    00229     ASSERT(ARGUMENT_PRESENT( SecurityDescriptor ));
    00230
    00231     //
    00232     //  Now invoke the security procedure call back to set the security
    00233     //  descriptor for the object
    00234     //
    00235
    00236     Status = (ObjectType->TypeInfo.SecurityProcedure)
    00237                 ( Object,
    00238                   SetSecurityDescriptor,
    00239                   &SecurityInformation,
    00240                   SecurityDescriptor,
    00241                   NULL,
    00242                   &ObjectHeader->SecurityDescriptor,
    00243                   ObjectType->TypeInfo.PoolType,
    00244                   &ObjectType->TypeInfo.GenericMapping );
    00245
    00246
    00247 //    DbgPrint("ObSetSecurityObjectByPointer: object security routine returned "
    00248 //             "%#08lx\n", Status);
    00249
    00250     return( Status );
    00251 }
    00252
    00253
    00254 NTSTATUS
    00255 NtQuerySecurityObject (
    00256     IN HANDLE Handle,
    00257     IN SECURITY_INFORMATION SecurityInformation,
    00258     OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
    00259     IN ULONG Length,
    00260     OUT PULONG LengthNeeded
    00261     )
    00262
    00263 /*++
    00264
    00265 Routine Description:
    00266
    00267     This routine is used to query the security descriptor for an
    00268     object.
    00269
    00270 Arguments:
    00271
    00272     Handle - Supplies the handle for the object being investigated
    00273
    00274     SecurityInformation - Indicates the type of information we are
    00275         interested in getting. e.g., owner, group, dacl, or sacl.
    00276
    00277     SecurityDescriptor - Supplies a pointer to where the information
    00278         should be returned
    00279
    00280     Length - Supplies the size, in bytes, of the output buffer
    00281
    00282     LengthNeeded - Receives the length, in bytes, needed to store
    00283         the output security descriptor
    00284
    00285 Return Value:
    00286
    00287     An appropriate NTSTATUS value
    00288
    00289 --*/
    00290
    00291 {
    00292     NTSTATUS Status;
    00293     PVOID Object;
    00294     ACCESS_MASK DesiredAccess;
    00295     OBJECT_HANDLE_INFORMATION HandleInformation;
    00296     KPROCESSOR_MODE RequestorMode;
    00297     POBJECT_HEADER ObjectHeader;
    00298     POBJECT_TYPE ObjectType;
    00299
    00300     PAGED_CODE();
    00301
    00302     //
    00303     //  Probe output parameters
    00304     //
    00305
    00306     RequestorMode = KeGetPreviousMode();
    00307
    00308     if (RequestorMode != KernelMode) {
    00309
    00310         try {
    00311
    00312             ProbeForWriteUlong( LengthNeeded );
    00313
    00314             ProbeForWrite( SecurityDescriptor, Length, sizeof(ULONG) );
    00315
    00316         } except(EXCEPTION_EXECUTE_HANDLER) {
    00317
    00318             return GetExceptionCode();
    00319         }
    00320     }
    00321
    00322     //
    00323     //  Establish the accesses needed to the object based upon the
    00324     //  security information being queried
    00325     //
    00326
    00327     SeQuerySecurityAccessMask( SecurityInformation, &DesiredAccess );
    00328
    00329     Status = ObReferenceObjectByHandle( Handle,
    00330                                         DesiredAccess,
    00331                                         NULL,
    00332                                         RequestorMode,
    00333                                         &Object,
    00334                                         &HandleInformation );
    00335
    00336     if (!NT_SUCCESS( Status )) {
    00337
    00338         return( Status );
    00339     }
    00340
    00341     //
    00342     //  Map the object body to an object header and the corresponding
    00343     //  object type
    00344     //
    00345
    00346     ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
    00347     ObjectType = ObjectHeader->Type;
    00348
    00349     //
    00350     //  Invoke the object type's security callback routine to query
    00351     //  the object.  This routine is assumed to have a try-except around
    00352     //  the setting of the output security descriptor
    00353     //
    00354
    00355     Status = (ObjectType->TypeInfo.SecurityProcedure)( Object,
    00356                                                        QuerySecurityDescriptor,
    00357                                                        &SecurityInformation,
    00358                                                        SecurityDescriptor,
    00359                                                        &Length,
    00360                                                        &ObjectHeader->SecurityDescriptor,
    00361                                                        ObjectType->TypeInfo.PoolType,
    00362                                                        &ObjectType->TypeInfo.GenericMapping );
    00363
    00364     //
    00365     //  Indicate the length needed for the security descriptor.  This
    00366     //  will be set even if the callback failed so the caller will know
    00367     //  the number of bytes necessary
    00368     //
    00369
    00370     try {
    00371
    00372         *LengthNeeded = Length;
    00373
    00374     } except(EXCEPTION_EXECUTE_HANDLER) {
    00375
    00376         ObDereferenceObject( Object );
    00377
    00378         return(GetExceptionCode());
    00379     }
    00380
    00381     //
    00382     //  And return to our caller
    00383     //
    00384
    00385     ObDereferenceObject( Object );
    00386
    00387     return( Status );
    00388 }
    00389
    00390
    00391 BOOLEAN
    00392 ObCheckObjectAccess (
    00393     IN PVOID Object,
    00394     IN OUT PACCESS_STATE AccessState,
    00395     IN BOOLEAN TypeMutexLocked,
    00396     IN KPROCESSOR_MODE AccessMode,
    00397     OUT PNTSTATUS AccessStatus
    00398     )
    00399
    00400 /*++
    00401
    00402 Routine Description:
    00403
    00404     This routine performs access validation on the passed object.  The
    00405     remaining desired access mask is extracted from the AccessState
    00406     parameter and passes to the appropriate security routine to perform the
    00407     access check.
    00408
    00409     If the access attempt is successful, SeAccessCheck returns a mask
    00410     containing the granted accesses.  The bits in this mask are turned
    00411     on in the PreviouslyGrantedAccess field of the AccessState, and
    00412     are turned off in the RemainingDesiredAccess field.
    00413
    00414 Arguments:
    00415
    00416     Object - The object being examined.
    00417
    00418     AccessState - The ACCESS_STATE structure containing accumulated
    00419         information about the current attempt to gain access to the object.
    00420
    00421     TypeMutexLocked - Indicates whether the type mutex for this object's
    00422         type is locked.  The type mutex is used to protect the object's
    00423         security descriptor from being modified while it is being accessed.
    00424
    00425     AccessMode - The previous processor mode.
    00426
    00427     AccessStatus - Pointer to a variable to return the status code of the
    00428         access attempt.  In the case of failure this status code must be
    00429         propagated back to the user.
    00430
    00431
    00432 Return Value:
    00433
    00434     BOOLEAN - TRUE if access is allowed and FALSE otherwise
    00435
    00436 --*/
    00437
    00438 {
    00439     ACCESS_MASK GrantedAccess = 0;
    00440     BOOLEAN AccessAllowed;
    00441     BOOLEAN MemoryAllocated;
    00442     NTSTATUS Status;
    00443     PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
    00444     POBJECT_HEADER ObjectHeader;
    00445     POBJECT_TYPE ObjectType;
    00446     PPRIVILEGE_SET Privileges = NULL;
    00447
    00448     PAGED_CODE();
    00449
    00450     //
    00451     //  Map the object body to an object header and the
    00452     //  corresponding object type
    00453     //
    00454
    00455     ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
    00456     ObjectType = ObjectHeader->Type;
    00457
    00458     //
    00459     //  If the caller does not have the object type locked
    00460     //  then lock it down
    00461     //
    00462
    00463     if (!TypeMutexLocked) {
    00464
    00465         ObpEnterObjectTypeMutex( ObjectType );
    00466     }
    00467
    00468     //
    00469     //  Obtain the object's security descriptor
    00470     //
    00471
    00472     Status = ObGetObjectSecurity( Object,
    00473                                   &SecurityDescriptor,
    00474                                   &MemoryAllocated );
    00475
    00476     //
    00477     //  If we failed in getting the security descriptor then
    00478     //  put the object type lock back where it was and return
    00479     //  the error back to our caller
    00480     //
    00481
    00482     if (!NT_SUCCESS( Status )) {
    00483
    00484         if (!TypeMutexLocked) {
    00485
    00486             ObpLeaveObjectTypeMutex( ObjectType );
    00487         }
    00488
    00489         *AccessStatus = Status;
    00490
    00491         return( FALSE );
    00492
    00493     } else {
    00494
    00495         //
    00496         //  Otherwise we've been successful at getting the
    00497         //  object's security descriptor, but now make sure
    00498         //  it is not null.
    00499
    00500         if (SecurityDescriptor == NULL) {
    00501
    00502             if (!TypeMutexLocked) {
    00503
    00504                 ObpLeaveObjectTypeMutex( ObjectType );
    00505             }
    00506
    00507             *AccessStatus = Status;
    00508
    00509             return(TRUE);
    00510         }
    00511     }
    00512
    00513     //
    00514     //  We have a non-null security descriptor so now
    00515     //  lock the caller's tokens until after auditing has been
    00516     //  performed.
    00517     //
    00518
    00519     SeLockSubjectContext( &AccessState->SubjectSecurityContext );
    00520
    00521     //
    00522     //  Do the access check, and if we have some privileges then
    00523     //  put those in the access state too.
    00524     //
    00525
    00526     AccessAllowed = SeAccessCheck( SecurityDescriptor,
    00527                                    &AccessState->SubjectSecurityContext,
    00528                                    TRUE,                        // Tokens are locked
    00529                                    AccessState->RemainingDesiredAccess,
    00530                                    AccessState->PreviouslyGrantedAccess,
    00531                                    &Privileges,
    00532                                    &ObjectType->TypeInfo.GenericMapping,
    00533                                    AccessMode,
    00534                                    &GrantedAccess,
    00535                                    AccessStatus );
    00536
    00537     if (Privileges != NULL) {
    00538
    00539         Status = SeAppendPrivileges( AccessState,
    00540                                      Privileges );
    00541
    00542         SeFreePrivileges( Privileges );
    00543     }
    00544
    00545     //
    00546     //  If we were granted access then set that fact into
    00547     //  what we've been granted and remove it from what remains
    00548     //  to be granted.
    00549     //
    00550
    00551     if (AccessAllowed) {
    00552
    00553         AccessState->PreviouslyGrantedAccess |= GrantedAccess;
    00554         AccessState->RemainingDesiredAccess &= ~(GrantedAccess | MAXIMUM_ALLOWED);
    00555     }
    00556
    00557     //
    00558     //  Audit the attempt to open the object, audit
    00559     //  the creation of its handle later.
    00560     //
    00561     //  **** SecurityDescriptor cannot be null
    00562     //
    00563
    00564     if ( SecurityDescriptor != NULL ) {
    00565
    00566         SeOpenObjectAuditAlarm( &ObjectType->Name,
    00567                                 Object,
    00568                                 NULL,                    // AbsoluteObjectName
    00569                                 SecurityDescriptor,
    00570                                 AccessState,
    00571                                 FALSE,                   // ObjectCreated (FALSE, only open here)
    00572                                 AccessAllowed,
    00573                                 AccessMode,
    00574                                 &AccessState->GenerateOnClose );
    00575     }
    00576
    00577     SeUnlockSubjectContext( &AccessState->SubjectSecurityContext );
    00578
    00579     //
    00580     //  If the caller didn't lock the object type then we have to
    00581     //  remove our lock on it.
    00582     //
    00583
    00584     if (!TypeMutexLocked) {
    00585
    00586         ObpLeaveObjectTypeMutex( ObjectType );
    00587     }
    00588
    00589     //
    00590     //  Free the security descriptor before returning to
    00591     //  our caller
    00592     //
    00593
    00594     ObReleaseObjectSecurity( SecurityDescriptor,
    00595                              MemoryAllocated );
    00596
    00597     return( AccessAllowed );
    00598 }
    00599
    00600
    00601 BOOLEAN
    00602 ObpCheckObjectReference (
    00603     IN PVOID Object,
    00604     IN OUT PACCESS_STATE AccessState,
    00605     IN BOOLEAN TypeMutexLocked,
    00606     IN KPROCESSOR_MODE AccessMode,
    00607     OUT PNTSTATUS AccessStatus
    00608     )
    00609
    00610 /*++
    00611
    00612 Routine Description:
    00613
    00614     The routine performs access validation on the passed object.  The
    00615     remaining desired access mask is extracted from the AccessState
    00616     parameter and passes to the appropriate security routine to
    00617     perform the access check.
    00618
    00619     If the access attempt is successful, SeAccessCheck returns a mask
    00620     containing the granted accesses.  The bits in this mask are turned
    00621     on in the PreviouslyGrantedAccess field of the AccessState, and
    00622     are turned off in the RemainingDesiredAccess field.
    00623
    00624     This routine differs from ObpCheckObjectAccess in that it calls
    00625     a different audit routine.
    00626
    00627 Arguments:
    00628
    00629     Object - The object being examined.
    00630
    00631     AccessState - The ACCESS_STATE structure containing accumulated
    00632         information about the current attempt to gain access to the object.
    00633
    00634     TypeMutexLocked - Indicates whether the type mutex for this object's
    00635         type is locked.  The type mutex is used to protect the object's
    00636         security descriptor from being modified while it is being accessed.
    00637
    00638     AccessMode - The previous processor mode.
    00639
    00640     AccessStatus - Pointer to a variable to return the status code of the
    00641         access attempt.  In the case of failure this status code must be
    00642         propagated back to the user.
    00643
    00644
    00645 Return Value:
    00646
    00647     BOOLEAN - TRUE if access is allowed and FALSE otherwise
    00648
    00649 --*/
    00650
    00651 {
    00652     BOOLEAN AccessAllowed;
    00653     ACCESS_MASK GrantedAccess = 0;
    00654     BOOLEAN MemoryAllocated;
    00655     PSECURITY_DESCRIPTOR SecurityDescriptor;
    00656     NTSTATUS Status;
    00657     POBJECT_HEADER ObjectHeader;
    00658     POBJECT_TYPE ObjectType;
    00659     PPRIVILEGE_SET Privileges = NULL;
    00660
    00661     PAGED_CODE();
    00662
    00663     //
    00664     //  Map the object body to an object header and the
    00665     //  corresponding object type
    00666     //
    00667
    00668     ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
    00669     ObjectType = ObjectHeader->Type;
    00670
    00671     //
    00672     //  If the caller does not have the object type locked
    00673     //  then lock it down
    00674     //
    00675
    00676     if (!TypeMutexLocked) {
    00677
    00678         ObpEnterObjectTypeMutex( ObjectType );
    00679     }
    00680
    00681     //
    00682     //  Obtain the object's security descriptor
    00683     //
    00684
    00685     Status = ObGetObjectSecurity( Object,
    00686                                   &SecurityDescriptor,
    00687                                   &MemoryAllocated );
    00688
    00689     //
    00690     //  If we failed in getting the security descriptor then
    00691     //  put the object type lock back where it was and return
    00692     //  the error back to our caller
    00693     //
    00694
    00695     if (!NT_SUCCESS( Status )) {
    00696
    00697         if (!TypeMutexLocked) {
    00698
    00699             ObpLeaveObjectTypeMutex( ObjectType );
    00700         }
    00701
    00702         *AccessStatus = Status;
    00703
    00704         return( FALSE );
    00705     }
    00706
    00707     //
    00708     //  Lock the caller's tokens until after auditing has been
    00709     //  performed.
    00710     //
    00711
    00712     SeLockSubjectContext( &AccessState->SubjectSecurityContext );
    00713
    00714     //
    00715     //  Do the access check, and if we have some privileges then
    00716     //  put those in the access state too.
    00717     //
    00718
    00719     AccessAllowed = SeAccessCheck( SecurityDescriptor,
    00720                                    &AccessState->SubjectSecurityContext,
    00721                                    TRUE,               // Tokens are locked
    00722                                    AccessState->RemainingDesiredAccess,
    00723                                    AccessState->PreviouslyGrantedAccess,
    00724                                    &Privileges,
    00725                                    &ObjectType->TypeInfo.GenericMapping,
    00726                                    AccessMode,
    00727                                    &GrantedAccess,
    00728                                    AccessStatus );
    00729
    00730     if (AccessAllowed) {
    00731
    00732         AccessState->PreviouslyGrantedAccess |= GrantedAccess;
    00733         AccessState->RemainingDesiredAccess &= ~GrantedAccess;
    00734     }
    00735
    00736     //
    00737     //  If we have a security descriptor then call the security routine
    00738     //  to audit this reference and then unlock the caller's token
    00739     //
    00740
    00741     if ( SecurityDescriptor != NULL ) {
    00742
    00743         SeObjectReferenceAuditAlarm( &AccessState->OperationID,
    00744                                      Object,
    00745                                      SecurityDescriptor,
    00746                                      &AccessState->SubjectSecurityContext,
    00747                                      AccessState->RemainingDesiredAccess | AccessState->PreviouslyGrantedAccess,
    00748                                      ((PAUX_ACCESS_DATA)(AccessState->AuxData))->PrivilegesUsed,
    00749                                      AccessAllowed,
    00750                                      AccessMode );
    00751     }
    00752
    00753     SeUnlockSubjectContext( &AccessState->SubjectSecurityContext );
    00754
    00755     //
    00756     //  If the caller didn't have the object type locked then remove
    00757     //  our lock
    00758     //
    00759
    00760     if (!TypeMutexLocked) {
    00761
    00762         ObpLeaveObjectTypeMutex( ObjectType );
    00763     }
    00764
    00765     //
    00766     //  Finally free the security descriptor
    00767     //  and return to our caller
    00768     //
    00769
    00770     ObReleaseObjectSecurity( SecurityDescriptor,
    00771                              MemoryAllocated );
    00772
    00773     return( AccessAllowed );
    00774 }
    00775
    00776
    00777 BOOLEAN
    00778 ObpCheckTraverseAccess (
    00779     IN PVOID DirectoryObject,
    00780     IN ACCESS_MASK TraverseAccess,
    00781     IN PACCESS_STATE AccessState OPTIONAL,
    00782     IN BOOLEAN TypeMutexLocked,
    00783     IN KPROCESSOR_MODE PreviousMode,
    00784     OUT PNTSTATUS AccessStatus
    00785     )
    00786
    00787 /*++
    00788
    00789 Routine Description:
    00790
    00791     This routine checks for traverse access to the given directory object.
    00792
    00793     Note that the contents of the AccessState structure are not
    00794     modified, since it is assumed that this access check is incidental
    00795     to another access operation.
    00796
    00797 Arguments:
    00798
    00799     DirectoryObject - The object body of the object being examined.
    00800
    00801     TraverseAccess - The desired access to the object, most likely DIRECTORY
    00802         TRAVERSE access.
    00803
    00804     AccessState - Checks for traverse access will typically be incidental
    00805         to some other access attempt.  Information on the current state of
    00806         that access attempt is required so that the constituent access
    00807         attempts may be associated with each other in the audit log.
    00808         This is an OPTIONAL parameter, in which case the call will
    00809         success ONLY if the Directory Object grants World traverse
    00810         access rights.
    00811
    00812     TypeMutexLocked - Indicates whether the type mutex for this object's
    00813         type is locked.  The type mutex is used to protect the object's
    00814         security descriptor from being modified while it is being accessed.
    00815
    00816     PreviousMode - The previous processor mode.
    00817
    00818     AccessStatus - Pointer to a variable to return the status code of the
    00819         access attempt.  In the case of failure this status code must be
    00820         propagated back to the user.
    00821
    00822 Return Value:
    00823
    00824     BOOLEAN - TRUE if access is allowed and FALSE otherwise.  AccessStatus
    00825     contains the status code to be passed back to the caller.  It is not
    00826     correct to simply pass back STATUS_ACCESS_DENIED, since this will have
    00827     to change with the advent of mandatory access control.
    00828
    00829 --*/
    00830
    00831 {
    00832     BOOLEAN AccessAllowed;
    00833     ACCESS_MASK GrantedAccess = 0;
    00834     PSECURITY_DESCRIPTOR SecurityDescriptor;
    00835     BOOLEAN MemoryAllocated;
    00836     NTSTATUS Status;
    00837     POBJECT_HEADER ObjectHeader;
    00838     POBJECT_TYPE ObjectType;
    00839     BOOLEAN SubjectContextLocked = FALSE;
    00840     PPRIVILEGE_SET Privileges = NULL;
    00841
    00842     PAGED_CODE();
    00843
    00844     //
    00845     //  Map the object body to an object header and corresponding
    00846     //  object type
    00847     //
    00848
    00849     ObjectHeader = OBJECT_TO_OBJECT_HEADER( DirectoryObject );
    00850     ObjectType = ObjectHeader->Type;
    00851
    00852     //
    00853     //  If the caller hasn't locked down the object type then
    00854     //  lock it down now
    00855     //
    00856
    00857     if (!TypeMutexLocked) {
    00858
    00859         ObpEnterObjectTypeMutex( ObjectType );
    00860     }
    00861
    00862     //
    00863     //  Obtain the object's security descriptor and make it was
    00864     //  successful
    00865     //
    00866
    00867     Status = ObGetObjectSecurity( DirectoryObject,
    00868                                   &SecurityDescriptor,
    00869                                   &MemoryAllocated );
    00870
    00871     if (!NT_SUCCESS( Status )) {
    00872
    00873         if (!TypeMutexLocked) {
    00874
    00875             ObpLeaveObjectTypeMutex( ObjectType );
    00876         }
    00877
    00878         *AccessStatus = Status;
    00879
    00880         return( FALSE );
    00881     }
    00882
    00883     //
    00884     //  Check to see if WORLD has TRAVERSE access, by seeing if the
    00885     //  token is restricted or the fast traverse check fails meaning
    00886     //  that the world does not have traverse access
    00887     //
    00888
    00889     if (((AccessState->Flags & TOKEN_IS_RESTRICTED) != 0)
    00890
    00891         ||
    00892
    00893         (!SeFastTraverseCheck( SecurityDescriptor,
    00894                                DIRECTORY_TRAVERSE,
    00895                                PreviousMode ))) {
    00896
    00897         //
    00898         //  SeFastTraverseCheck could be modified to tell us that
    00899         //  no one has any access to this directory.  However,
    00900         //  we're going to have to fail this entire call if
    00901         //  that is the case, so we really don't need to worry
    00902         //  all that much about making it blindingly fast.
    00903         //
    00904
    00905         if (ARGUMENT_PRESENT( AccessState )) {
    00906
    00907             //
    00908             //  The world does not have traverse access and we have
    00909             //  the client's access state so lock down the client's
    00910             //  token and then do the access check, appending privileges
    00911             //  if present.  The access check will give the answer
    00912             //  we return back to our caller
    00913             //
    00914
    00915             SeLockSubjectContext( &AccessState->SubjectSecurityContext );
    00916
    00917             SubjectContextLocked = TRUE;
    00918
    00919             AccessAllowed = SeAccessCheck( SecurityDescriptor,
    00920                                            &AccessState->SubjectSecurityContext,
    00921                                            TRUE,             // Tokens are locked
    00922                                            TraverseAccess,
    00923                                            0,
    00924                                            &Privileges,
    00925                                            &ObjectType->TypeInfo.GenericMapping,
    00926                                            PreviousMode,
    00927                                            &GrantedAccess,
    00928                                            AccessStatus );
    00929
    00930             if (Privileges != NULL) {
    00931
    00932                 Status = SeAppendPrivileges( AccessState,
    00933                                              Privileges );
    00934
    00935                 SeFreePrivileges( Privileges );
    00936             }
    00937         }
    00938
    00939     } else {
    00940
    00941         //
    00942         //  At this point the world has traverse access
    00943         //
    00944
    00945         AccessAllowed = TRUE;
    00946     }
    00947
    00948     //
    00949     //  If the client's token is locked then now we can unlock it
    00950     //
    00951     //  **** this should be able to move up into the preceding clause
    00952     //  where it is locked
    00953     //
    00954
    00955     if ( SubjectContextLocked ) {
    00956
    00957         SeUnlockSubjectContext( &AccessState->SubjectSecurityContext );
    00958     }
    00959
    00960     //
    00961     //  If the caller did not lock the object type then we
    00962     //  now need to unlock it
    00963     //
    00964
    00965     if (!TypeMutexLocked) {
    00966
    00967         ObpLeaveObjectTypeMutex( ObjectType );
    00968     }
    00969
    00970     //
    00971     //  Finally free the security descriptor
    00972     //  and then return to our caller
    00973     //
    00974
    00975     ObReleaseObjectSecurity( SecurityDescriptor,
    00976                              MemoryAllocated );
    00977
    00978     return( AccessAllowed );
    00979 }
    00980
    00981
    00982 BOOLEAN
    00983 ObCheckCreateObjectAccess (
    00984     IN PVOID DirectoryObject,
    00985     IN ACCESS_MASK CreateAccess,
    00986     IN PACCESS_STATE AccessState,
    00987     IN PUNICODE_STRING ComponentName,
    00988     IN BOOLEAN TypeMutexLocked,
    00989     IN KPROCESSOR_MODE PreviousMode,
    00990     OUT PNTSTATUS AccessStatus
    00991     )
    00992
    00993 /*++
    00994
    00995 Routine Description:
    00996
    00997     This routine checks to see if we are allowed to create an object in the
    00998     given directory, and performs auditing as appropriate.
    00999
    01000 Arguments:
    01001
    01002     DirectoryObject - The directory object being examined.
    01003
    01004     CreateAccess - The access mask corresponding to create access for
    01005         this directory type.
    01006
    01007     AccessState - Checks for traverse access will typically be incidental
    01008         to some other access attempt.  Information on the current state of
    01009         that access attempt is required so that the constituent access
    01010         attempts may be associated with each other in the audit log.
    01011
    01012     ComponentName - Pointer to a Unicode string containing the name of
    01013         the object being created.
    01014
    01015     TypeMutexLocked - Indicates whether the type mutex for this object's
    01016         type is locked.  The type mutex is used to protect the object's
    01017         security descriptor from being modified while it is being accessed.
    01018
    01019     PreviousMode - The previous processor mode.
    01020
    01021     AccessStatus - Pointer to a variable to return the status code of the
    01022         access attempt.  In the case of failure this status code must be
    01023         propagated back to the user.
    01024
    01025 Return Value:
    01026
    01027     BOOLEAN - TRUE if access is allowed and FALSE otherwise.  AccessStatus
    01028     contains the status code to be passed back to the caller.  It is not
    01029     correct to simply pass back STATUS_ACCESS_DENIED, since this will have
    01030     to change with the advent of mandatory access control.
    01031
    01032 --*/
    01033
    01034 {
    01035     BOOLEAN AccessAllowed;
    01036     ACCESS_MASK GrantedAccess = 0;
    01037     PSECURITY_DESCRIPTOR SecurityDescriptor;
    01038     BOOLEAN MemoryAllocated;
    01039     NTSTATUS Status;
    01040     POBJECT_HEADER ObjectHeader;
    01041     POBJECT_TYPE ObjectType;
    01042     PPRIVILEGE_SET Privileges = NULL;
    01043     BOOLEAN AuditPerformed = FALSE;
    01044
    01045     PAGED_CODE();
    01046
    01047     //
    01048     //  Map the object body to its object header and corresponding
    01049     //  object type
    01050     //
    01051
    01052     ObjectHeader = OBJECT_TO_OBJECT_HEADER( DirectoryObject );
    01053     ObjectType = ObjectHeader->Type;
    01054
    01055     //
    01056     //  If the caller didn't lock the object type down then
    01057     //  we'll do it now
    01058     //
    01059
    01060     if (!TypeMutexLocked) {
    01061
    01062         ObpEnterObjectTypeMutex( ObjectType );
    01063     }
    01064
    01065     //
    01066     //  Obtain the object's security descriptor and make it was
    01067     //  successful
    01068     //
    01069
    01070     Status = ObGetObjectSecurity( DirectoryObject,
    01071                                   &SecurityDescriptor,
    01072                                   &MemoryAllocated );
    01073
    01074     if (!NT_SUCCESS( Status )) {
    01075
    01076         if (!TypeMutexLocked) {
    01077
    01078             ObpLeaveObjectTypeMutex( ObjectType );
    01079         }
    01080
    01081         *AccessStatus = Status;
    01082
    01083         return( FALSE );
    01084     }
    01085
    01086     //
    01087     //  lock the caller's tokens until after auditing has been
    01088     //  performed.
    01089     //
    01090
    01091     SeLockSubjectContext( &AccessState->SubjectSecurityContext );
    01092
    01093     //
    01094     //  if we have a security descriptor then do an access
    01095     //  check to see if access is allowed and set in the
    01096     //  privileges if necessary
    01097     //
    01098
    01099     if (SecurityDescriptor != NULL) {
    01100
    01101         AccessAllowed = SeAccessCheck( SecurityDescriptor,
    01102                                        &AccessState->SubjectSecurityContext,
    01103                                        TRUE,            // Tokens are locked
    01104                                        CreateAccess,
    01105                                        0,
    01106                                        &Privileges,
    01107                                        &ObjectType->TypeInfo.GenericMapping,
    01108                                        PreviousMode,
    01109                                        &GrantedAccess,
    01110                                        AccessStatus );
    01111
    01112         if (Privileges != NULL) {
    01113
    01114             Status = SeAppendPrivileges( AccessState,
    01115                                          Privileges );
    01116
    01117             SeFreePrivileges( Privileges );
    01118         }
    01119
    01120         //
    01121         //  This is wrong, but leave for reference.
    01122         //
    01123         //  if (AccessAllowed) {
    01124         //
    01125         //      AccessState->PreviouslyGrantedAccess |= GrantedAccess;
    01126         //      AccessState->RemainingDesiredAccess &= ~GrantedAccess;
    01127         //  }
    01128         //
    01129
    01130 #if 0
    01131         SeCreateObjectAuditAlarm( &AccessState->OperationID,
    01132                                   DirectoryObject,
    01133                                   ComponentName,
    01134                                   SecurityDescriptor,
    01135                                   &AccessState->SubjectSecurityContext,
    01136                                   CreateAccess,
    01137                                   AccessState->PrivilegesUsed,
    01138                                   AccessAllowed,
    01139                                   &AuditPerformed,
    01140                                   PreviousMode );
    01141
    01142         if ( AuditPerformed ) {
    01143
    01144             AccessState->AuditHandleCreation = TRUE;
    01145         }
    01146 #endif
    01147
    01148     } else {
    01149
    01150         //
    01151         //  At this point there is not a security descriptor
    01152         //  so we'll assume access is allowed
    01153         //
    01154
    01155         AccessAllowed = TRUE;
    01156     }
    01157
    01158     //
    01159     //  Free the caller's token and if the caller didn't have the
    01160     //  object type locked we need to free it.
    01161     //
    01162
    01163     SeUnlockSubjectContext( &AccessState->SubjectSecurityContext );
    01164
    01165     if (!TypeMutexLocked) {
    01166
    01167         ObpLeaveObjectTypeMutex( ObjectType );
    01168     }
    01169
    01170     //
    01171     //  Finally free the security descriptor
    01172     //  and return to our caller
    01173     //
    01174
    01175     ObReleaseObjectSecurity( SecurityDescriptor,
    01176                              MemoryAllocated );
    01177
    01178     return( AccessAllowed );
    01179 }
    01180
    01181
    01182 NTSTATUS
    01183 ObAssignObjectSecurityDescriptor (
    01184     IN PVOID Object,
    01185     IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL,
    01186     IN POOL_TYPE PoolType // This field is currently ignored.
    01187     )
    01188
    01189 /*++
    01190
    01191 Routine Description:
    01192
    01193     Takes a pointer to an object and sets the SecurityDescriptor field
    01194     in the object's header.
    01195
    01196 Arguments:
    01197
    01198     Object - Supplies a pointer to the object
    01199
    01200     SecurityDescriptor - Supplies a pointer to the security descriptor
    01201         to be assigned to the object.  This pointer may be null if there
    01202         is no security on the object.
    01203
    01204     PoolType - Supplies the type of pool memory used to allocate the
    01205         security descriptor.  This field is currently ignored.
    01206
    01207 Return Value:
    01208
    01209     An appropriate NTSTATUS value.
    01210
    01211 --*/
    01212
    01213 {
    01214     NTSTATUS Status;
    01215     PSECURITY_DESCRIPTOR OutputSecurityDescriptor;
    01216
    01217     PAGED_CODE();
    01218
    01219     //
    01220     //  If the security descriptor isn't supplied then we set the
    01221     //  object header's security descriptor to null and return
    01222     //  to our caller
    01223     //
    01224
    01225     if (!ARGUMENT_PRESENT(SecurityDescriptor)) {
    01226
    01227         OBJECT_TO_OBJECT_HEADER( Object )->SecurityDescriptor = NULL;
    01228
    01229         return( STATUS_SUCCESS );
    01230     }
    01231
    01232     //
    01233     //  Log the new security descriptor into our security database and
    01234     //  get back the real security descriptor to use
    01235     //
    01236
    01237     Status = ObpLogSecurityDescriptor( SecurityDescriptor, &OutputSecurityDescriptor );
    01238
    01239     //
    01240     //  If we've been successful so far then set the object's
    01241     //  security descriptor to the newly allocated one.
    01242     //
    01243
    01244     if (NT_SUCCESS(Status)) {
    01245
    01246         OBJECT_TO_OBJECT_HEADER( Object )->SecurityDescriptor = OutputSecurityDescriptor;
    01247     }
    01248
    01249     //
    01250     //  And return to our caller
    01251     //
    01252
    01253     return( Status );
    01254 }
    01255
    01256
    01257 NTSTATUS
    01258 ObGetObjectSecurity (
    01259     IN PVOID Object,
    01260     OUT PSECURITY_DESCRIPTOR *SecurityDescriptor,
    01261     OUT PBOOLEAN MemoryAllocated
    01262     )
    01263
    01264 /*++
    01265
    01266 Routine Description:
    01267
    01268     Given an object, this routine will find its security descriptor.
    01269     It will do this by calling the object's security method.
    01270
    01271     It is possible for an object not to have a security descriptor
    01272     at all.  Unnamed objects such as events that can only be referenced
    01273     by a handle are an example of an object that does not have a
    01274     security descriptor.
    01275
    01276 Arguments:
    01277
    01278     Object - Supplies the object body being queried.
    01279
    01280     SecurityDescriptor - Returns a pointer to the object's security
    01281         descriptor.
    01282
    01283     MemoryAllocated - indicates whether we had to allocate pool
    01284         memory to hold the security descriptor or not.  This should
    01285         be passed back into ObReleaseObjectSecurity.
    01286
    01287 Return Value:
    01288
    01289     STATUS_SUCCESS - The operation was successful.  Note that the
    01290         operation may be successful and still return a NULL security
    01291         descriptor.
    01292
    01293     STATUS_INSUFFICIENT_RESOURCES - Insufficient memory was available
    01294         to satisfy the request.
    01295
    01296 --*/
    01297
    01298 {
    01299     SECURITY_INFORMATION SecurityInformation;
    01300     ULONG Length = 0;
    01301     NTSTATUS Status;
    01302     POBJECT_TYPE ObjectType;
    01303     POBJECT_HEADER ObjectHeader;
    01304     KIRQL SaveIrql;
    01305
    01306     PAGED_CODE();
    01307
    01308     //
    01309     //  Map the object body to its object header and corresponding
    01310     //  object type
    01311     //
    01312
    01313     ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
    01314     ObjectType = ObjectHeader->Type;
    01315
    01316     //
    01317     //  If the object is one that uses the default object method,
    01318     //  its security descriptor is contained in ob's security
    01319     //  descriptor cache.
    01320     //
    01321     //  Reference it so that it doesn't go away out from under us.
    01322     //
    01323
    01324     if (ObpCentralizedSecurity(ObjectType))  {
    01325
    01326         *SecurityDescriptor = ObpReferenceSecurityDescriptor( Object );
    01327
    01328         *MemoryAllocated = FALSE;
    01329
    01330         return( STATUS_SUCCESS );
    01331     }
    01332
    01333     //
    01334     //  Request a complete security descriptor
    01335     //
    01336
    01337     SecurityInformation = OWNER_SECURITY_INFORMATION |
    01338                           GROUP_SECURITY_INFORMATION |
    01339                           DACL_SECURITY_INFORMATION  |
    01340                           SACL_SECURITY_INFORMATION;
    01341
    01342     //
    01343     //  Call the security method with Length = 0 to find out
    01344     //  how much memory we need to store the final result.
    01345     //
    01346     //  Note that the ObjectsSecurityDescriptor parameter is NULL,
    01347     //  because we expect whoever is on the other end of this call
    01348     //  to find the security descriptor for us.  We pass in a pool
    01349     //  type to keep the compiler happy, it will not be used for a
    01350     //  query operation.
    01351     //
    01352
    01353
    01354     ObpBeginTypeSpecificCallOut( SaveIrql );
    01355
    01356     Status = (*ObjectType->TypeInfo.SecurityProcedure)( Object,
    01357                                                         QuerySecurityDescriptor,
    01358                                                         &SecurityInformation,
    01359                                                         *SecurityDescriptor,
    01360                                                         &Length,
    01361                                                         &ObjectHeader->SecurityDescriptor,         // not used
    01362                                                         ObjectType->TypeInfo.PoolType,
    01363                                                         &ObjectType->TypeInfo.GenericMapping );
    01364
    01365     ObpEndTypeSpecificCallOut( SaveIrql, "Security", ObjectType, Object );
    01366
    01367     if (Status != STATUS_BUFFER_TOO_SMALL) {
    01368
    01369         return( Status );
    01370     }
    01371
    01372     //
    01373     //  Now that we know how large the security descriptor is we
    01374     //  can allocate space for it
    01375     //
    01376
    01377     *SecurityDescriptor = ExAllocatePoolWithTag( PagedPool, Length, 'qSbO' );
    01378
    01379     if (*SecurityDescriptor == NULL) {
    01380
    01381         return( STATUS_INSUFFICIENT_RESOURCES );
    01382     }
    01383
    01384     *MemoryAllocated = TRUE;
    01385
    01386     //
    01387     //  The security method will return an absolute format
    01388     //  security descriptor that just happens to be in a self
    01389     //  contained buffer (not to be confused with a self-relative
    01390     //  security descriptor).
    01391     //
    01392
    01393     ObpBeginTypeSpecificCallOut( SaveIrql );
    01394
    01395     Status = (*ObjectType->TypeInfo.SecurityProcedure)( Object,
    01396                                                         QuerySecurityDescriptor,
    01397                                                         &SecurityInformation,
    01398                                                         *SecurityDescriptor,
    01399                                                         &Length,
    01400                                                         &ObjectHeader->SecurityDescriptor,
    01401                                                         ObjectType->TypeInfo.PoolType,
    01402                                                         &ObjectType->TypeInfo.GenericMapping );
    01403
    01404     ObpEndTypeSpecificCallOut( SaveIrql, "Security", ObjectType, Object );
    01405
    01406     if (!NT_SUCCESS( Status )) {
    01407
    01408         ExFreePool( *SecurityDescriptor );
    01409
    01410         *MemoryAllocated = FALSE;
    01411     }
    01412
    01413     return( Status );
    01414 }
    01415
    01416
    01417 VOID
    01418 ObReleaseObjectSecurity (
    01419     IN PSECURITY_DESCRIPTOR SecurityDescriptor,
    01420     IN BOOLEAN MemoryAllocated
    01421     )
    01422
    01423 /*++
    01424
    01425 Routine Description:
    01426
    01427     This function will free up any memory associated with a queried
    01428     security descriptor.  This undoes the function ObGetObjectSecurity
    01429
    01430 Arguments:
    01431
    01432     SecurityDescriptor - Supplies a pointer to the security descriptor
    01433         to be freed.
    01434
    01435     MemoryAllocated - Supplies whether or not we should free the
    01436         memory pointed to by SecurityDescriptor.
    01437
    01438 Return Value:
    01439
    01440     None.
    01441
    01442 --*/
    01443
    01444 {
    01445     PAGED_CODE();
    01446
    01447     //
    01448     //  Check if there is a security descriptor to actually free
    01449     //
    01450
    01451     if ( SecurityDescriptor != NULL ) {
    01452
    01453         //
    01454         //  If ObGetObjectSecurity allocated memory then we
    01455         //  need to free it. Otherwise what the earlier routine did
    01456         //  was reference the object to keep the security descriptor
    01457         //  to keep it from going away
    01458         //
    01459
    01460         if (MemoryAllocated) {
    01461
    01462             ExFreePool( SecurityDescriptor );
    01463
    01464         } else {
    01465
    01466             ObpDereferenceSecurityDescriptor( SecurityDescriptor );
    01467         }
    01468     }
    01469 }
    01470
    01471
    01472 NTSTATUS
    01473 ObValidateSecurityQuota (
    01474     IN PVOID Object,
    01475     IN ULONG NewSize
    01476     )
    01477
    01478 /*++
    01479
    01480 Routine Description:
    01481
    01482     This routine will check to see if the new security information
    01483     is larger than is allowed by the object's pre-allocated quota.
    01484
    01485 Arguments:
    01486
    01487     Object - Supplies a pointer to the object whose information is to be
    01488         modified.
    01489
    01490     NewSize - Supplies the size of the proposed new security
    01491         information.
    01492
    01493 Return Value:
    01494
    01495     STATUS_SUCCESS - New size is within alloted quota.
    01496
    01497     STATUS_QUOTA_EXCEEDED - The desired adjustment would have exceeded
    01498         the permitted security quota for this object.
    01499
    01500 --*/
    01501
    01502 {
    01503     POBJECT_HEADER ObjectHeader;
    01504     POBJECT_HEADER_QUOTA_INFO QuotaInfo;
    01505
    01506     PAGED_CODE();
    01507
    01508     //
    01509     //  Map the object body to its object header and corresponding
    01510     //  quota information block
    01511     //
    01512
    01513     ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
    01514     QuotaInfo = OBJECT_HEADER_TO_QUOTA_INFO( ObjectHeader );
    01515
    01516     //
    01517     //  If there isn't any quota info and the new size is greater
    01518     //  then the default security quota then if the object uses
    01519     //  the default value then we've exceeded quota otherwise
    01520     //  let the caller get the quota
    01521     //
    01522
    01523     if ((QuotaInfo == NULL) && (NewSize > SE_DEFAULT_SECURITY_QUOTA)) {
    01524
    01525         if (!(ObjectHeader->Flags & OB_FLAG_DEFAULT_SECURITY_QUOTA)) {
    01526
    01527             //
    01528             //  Should really charge quota here.
    01529             //
    01530
    01531             return( STATUS_SUCCESS );
    01532         }
    01533
    01534         return( STATUS_QUOTA_EXCEEDED );
    01535
    01536     //
    01537     //  If the quota is not null and the new size is greater than the
    01538     //  allowed quota charge then if the charge is zero we grant the
    01539     //  request otherwise we've exceeded quota.
    01540     //
    01541     //  **** this logic seems wierd
    01542     //
    01543
    01544     } else if ((QuotaInfo != NULL) && (NewSize > QuotaInfo->SecurityDescriptorCharge)) {
    01545
    01546         if (QuotaInfo->SecurityDescriptorCharge == 0) {
    01547
    01548             //
    01549             //  Should really charge quota here.
    01550             //
    01551
    01552             //  QuotaInfo->SecurityDescriptorCharge = SeComputeSecurityQuota( NewSize );
    01553
    01554             return( STATUS_SUCCESS );
    01555         }
    01556
    01557         return( STATUS_QUOTA_EXCEEDED );
    01558
    01559     //
    01560     //  Otherwise we have two cases.  (1) there isn't any quota info but
    01561     //  the size is within limits or (2) there is a quota info block and
    01562     //  the size is within the specified security descriptor charge so
    01563     //  return success to our caller
    01564     //
    01565
    01566     } else {
    01567
    01568         return( STATUS_SUCCESS );
    01569     }
    01570 }
    01571
    01572
    01573 NTSTATUS
    01574 ObAssignSecurity (
    01575     IN PACCESS_STATE AccessState,
    01576     IN PSECURITY_DESCRIPTOR ParentDescriptor OPTIONAL,
    01577     IN PVOID Object,
    01578     IN POBJECT_TYPE ObjectType
    01579     )
    01580
    01581 /*++
    01582
    01583 Routine Description:
    01584
    01585     This routine will assign a security descriptor to a newly created object.
    01586     It assumes that the AccessState parameter contains a captured security
    01587     descriptor.
    01588
    01589 Arguments:
    01590
    01591      AccessState - The AccessState containing the security information
    01592         for this object creation.
    01593
    01594      ParentDescriptor - The security descriptor from the parent object, if
    01595         available.
    01596
    01597      Object - A pointer to the object being created.
    01598
    01599      ObjectType - Supplies the type of object being created.
    01600
    01601 Return Value:
    01602
    01603     STATUS_SUCCESS - indicates the operation was successful.
    01604
    01605     STATUS_INVALID_OWNER - The owner SID provided as the owner of the
    01606         target security descriptor is not one the caller is authorized
    01607         to assign as the owner of an object.
    01608
    01609     STATUS_PRIVILEGE_NOT_HELD - The caller does not have the privilege
    01610         necessary to explicitly assign the specified system ACL.
    01611         SeSecurityPrivilege privilege is needed to explicitly assign
    01612         system ACLs to objects.
    01613
    01614 --*/
    01615
    01616 {
    01617     PSECURITY_DESCRIPTOR NewDescriptor = NULL;
    01618     NTSTATUS Status;
    01619     KIRQL SaveIrql;
    01620
    01621     PAGED_CODE();
    01622
    01623     //
    01624     //  SeAssignSecurity will construct the final version
    01625     //  of the security  descriptor
    01626     //
    01627
    01628     Status = SeAssignSecurity( ParentDescriptor,
    01629                                AccessState->SecurityDescriptor,
    01630                                &NewDescriptor,
    01631                                (BOOLEAN)(ObjectType == ObpDirectoryObjectType),
    01632                                &AccessState->SubjectSecurityContext,
    01633                                &ObjectType->TypeInfo.GenericMapping,
    01634                                PagedPool );
    01635
    01636     if (!NT_SUCCESS( Status )) {
    01637
    01638         return( Status );
    01639     }
    01640
    01641     ObpBeginTypeSpecificCallOut( SaveIrql );
    01642
    01643     //
    01644     //  Now invoke the security method callback to finish
    01645     //  the assignment.
    01646     //
    01647
    01648     Status = (*ObjectType->TypeInfo.SecurityProcedure)( Object,
    01649                                                         AssignSecurityDescriptor,
    01650                                                         NULL,
    01651                                                         NewDescriptor,
    01652                                                         NULL,
    01653                                                         NULL,
    01654                                                         PagedPool,
    01655                                                         &ObjectType->TypeInfo.GenericMapping );
    01656
    01657     ObpEndTypeSpecificCallOut( SaveIrql, "Security", ObjectType, Object );
    01658
    01659     if (!NT_SUCCESS( Status )) {
    01660
    01661         //
    01662         // The attempt to assign the security descriptor to the object
    01663         // failed.  Free the space used by the new security descriptor.
    01664         //
    01665
    01666         SeDeassignSecurity( &NewDescriptor );
    01667     }
    01668
    01669     //
    01670     //  And return to our caller
    01671     //
    01672
    01673     return( Status );
    01674 }
    01675
    01676
    01677
    01678 NTSTATUS
    01679 ObQuerySecurityDescriptorInfo(
    01680     IN PSECURITY_INFORMATION SecurityInformation,
    01681     OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
    01682     IN OUT PULONG Length,
    01683     IN PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor
    01684     )
    01685 /*++
    01686
    01687 Routine Description:
    01688
    01689     This routine will extract the desired information from the
    01690     passed security descriptor and return the information in
    01691     the passed buffer as a security descriptor in self-relative
    01692     format.
    01693
    01694     This routine assumes that all parameters are captured and
    01695     safe to reference.
    01696
    01697 Arguments:
    01698
    01699     SecurityInformation - Specifies what information is being queried.
    01700
    01701     SecurityDescriptor - Supplies the buffer to output the requested
    01702         information into.
    01703
    01704         This buffer has been probed only to the size indicated by
    01705         the Length parameter.  Since it still points into user space,
    01706         it must always be accessed in a try clause.
    01707
    01708     Length - Supplies the address of a variable containing the length of
    01709         the security descriptor buffer.  Upon return this variable will
    01710         contain the length needed to store the requested information.
    01711
    01712     ObjectsSecurityDescriptor - Supplies the address of a pointer to
    01713         the objects security descriptor.  The passed security descriptor
    01714         must be in self-relative format.
    01715
    01716 Return Value:
    01717
    01718     NTSTATUS - STATUS_SUCCESS if successful and an appropriate error value
    01719         otherwise
    01720
    01721 --*/
    01722 {
    01723     NTSTATUS Status;
    01724
    01725     PAGED_CODE();
    01726
    01727     //
    01728     // Take the read lock on the security descriptor cache so we
    01729     // don't collide with anyone who is modifying this security
    01730     // descriptor (bug 347986).
    01731     //
    01732
    01733     ObpAcquireDescriptorCacheReadLock();
    01734
    01735     Status = SeQuerySecurityDescriptorInfo( SecurityInformation,
    01736                                             SecurityDescriptor,
    01737                                             Length,
    01738                                             ObjectsSecurityDescriptor
    01739                                             );
    01740     ObpReleaseDescriptorCacheLock();
    01741
    01742     return( Status );
    01743 }
    01744
    01745
    01746
    01747 NTSTATUS
    01748 ObSetSecurityDescriptorInfo (
    01749     IN PVOID Object,
    01750     IN PSECURITY_INFORMATION SecurityInformation,
    01751     IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
    01752     IN OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
    01753     IN POOL_TYPE PoolType,
    01754     IN PGENERIC_MAPPING GenericMapping
    01755     )
    01756
    01757 /*++
    01758
    01759 Routine Description:
    01760
    01761     Sets the security descriptor on an already secure object.
    01762
    01763 Arguments:
    01764
    01765     Object - Pointer to the object being modified.
    01766
    01767     SecurityInformation - Describes which information in the SecurityDescriptor parameter
    01768         is relevent.
    01769
    01770     SecurityDescriptor - Provides the new security information.
    01771
    01772     ObjectsSecurityDescriptor - Provides/returns the object's security descriptor.
    01773
    01774     PoolType - The pool the ObjectSecurityDescriptor is allocated from.
    01775
    01776     GenericMapping - Supplies the generic mapping for the object.
    01777
    01778 Return Value:
    01779
    01780     An appropriate status value
    01781
    01782 --*/
    01783
    01784 {
    01785     PSECURITY_DESCRIPTOR OldDescriptor;
    01786     PSECURITY_DESCRIPTOR NewDescriptor;
    01787     NTSTATUS Status;
    01788
    01789     PAGED_CODE();
    01790
    01791     //
    01792     //  Check the rest of our input and call the default set security
    01793     //  method.  Also make sure no one is modifying the security descriptor
    01794     //  while we're looking at it.
    01795     //
    01796
    01797     ObpAcquireDescriptorCacheWriteLock();
    01798
    01799     OldDescriptor = *ObjectsSecurityDescriptor;
    01800     NewDescriptor = OldDescriptor;
    01801
    01802     Status = SeSetSecurityDescriptorInfo( Object,
    01803                                           SecurityInformation,
    01804                                           SecurityDescriptor,
    01805                                           &NewDescriptor,
    01806                                           PoolType,
    01807                                           GenericMapping );
    01808
    01809     //
    01810     //  Now if the object is an object directory object that
    01811     //  participated in snapped symbolic links.  If so and the
    01812     //  new security on the object does NOT allow world traverse
    01813     //  access, then return an error, as it is too late to change
    01814     //  the security on the object directory at this point.
    01815     //
    01816
    01817     if (NT_SUCCESS( Status )
    01818
    01819             &&
    01820
    01821         (OBJECT_TO_OBJECT_HEADER( Object )->Type == ObpDirectoryObjectType)
    01822
    01823             &&
    01824
    01825         (((POBJECT_DIRECTORY)Object)->SymbolicLinkUsageCount != 0)
    01826
    01827             &&
    01828
    01829         !SeFastTraverseCheck( NewDescriptor, DIRECTORY_TRAVERSE, UserMode )) {
    01830
    01831         KdPrint(( "OB: Failing attempt the remove world traverse access from object directory\n" ));
    01832
    01833         ExFreePool( NewDescriptor );
    01834
    01835         Status = STATUS_INVALID_PARAMETER;
    01836     }
    01837
    01838     //
    01839     //  If we successfully set the new security descriptor then we
    01840     //  need to log it in our database and get yet another pointer
    01841     //  to the finaly security descriptor
    01842     //
    01843
    01844     if ( NT_SUCCESS( Status )) {
    01845
    01846         Status = ObpLogSecurityDescriptor( NewDescriptor,
    01847                                            ObjectsSecurityDescriptor );
    01848
    01849         ObpReleaseDescriptorCacheLock();
    01850
    01851         if ( NT_SUCCESS( Status )) {
    01852
    01853             //
    01854             //  Dereference old SecurityDescriptor and insert new one
    01855             //
    01856
    01857             ObpDereferenceSecurityDescriptor( OldDescriptor );
    01858
    01859         } else {
    01860
    01861             //
    01862             //  We failed logging the new security descriptor.
    01863             //  Clean up and fail the entire operation.
    01864             //
    01865
    01866             ExFreePool( NewDescriptor );
    01867         }
    01868     } else {
    01869
    01870         //
    01871         //  Release the security descriptor lock
    01872         //
    01873
    01874         ObpReleaseDescriptorCacheLock();
    01875     }
    01876
    01877     //
    01878     //  And return to our caller
    01879     //
    01880
    01881     return( Status );
    01882 }
    01883
    01884
    01885 NTSTATUS
    01886 ObpValidateAccessMask (
    01887     PACCESS_STATE AccessState
    01888     )
    01889
    01890 /*++
    01891
    01892 Routine Description:
    01893
    01894     Checks the desired access mask of a passed object against the
    01895     passed security descriptor.
    01896
    01897 Arguments:
    01898
    01899     AccessState - A pointer to the AccessState for the pending operation.
    01900
    01901 Return Value:
    01902
    01903     Only returns STATUS_SUCCESS
    01904
    01905 --*/
    01906
    01907 {
    01908     SECURITY_DESCRIPTOR *SecurityDescriptor = AccessState->SecurityDescriptor;
    01909
    01910     PAGED_CODE();
    01911
    01912     //
    01913     //  First make sure the access state has a security descriptor.  If there
    01914     //  is one and it has a system acl and the previously granted access did
    01915     //  not include system security then add the fact that we want system
    01916     //  security to the remaining desired access state.
    01917     //
    01918
    01919     if (SecurityDescriptor != NULL) {
    01920
    01921         if ( SecurityDescriptor->Control & SE_SACL_PRESENT ) {
    01922
    01923             if ( !(AccessState->PreviouslyGrantedAccess & ACCESS_SYSTEM_SECURITY)) {
    01924
    01925                 AccessState->RemainingDesiredAccess |= ACCESS_SYSTEM_SECURITY;
    01926             }
    01927         }
    01928     }
    01929
    01930     return( STATUS_SUCCESS );
    01931 }
    01932